Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMR-9848: When submitting multiple associations, if one fails CMR returns a 400 but still makes the other associations #2198

Merged
merged 37 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
200a41e
CMR-9429: Validate ProcessingLevel Id
Jun 5, 2024
3a044b4
CMR-9429: Revert the commit into master by accident
Jun 5, 2024
8ad1e4d
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jun 10, 2024
bf1b84c
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jun 11, 2024
5190c5a
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jun 19, 2024
eae148e
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jun 21, 2024
3e669b0
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jul 17, 2024
8ee5022
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jul 22, 2024
0c88ff3
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jul 25, 2024
9fe05ac
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Jul 31, 2024
2dba0d6
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Aug 8, 2024
393cdcd
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Aug 12, 2024
d274599
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Aug 29, 2024
af1dc64
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
Sep 13, 2024
64ee76f
CMR-9848 Return 400 failure status only when all the associations/dis…
Sep 16, 2024
61eb516
CMR-9848: Fixed some tests
Sep 16, 2024
f46c405
CMR-9848:
Sep 18, 2024
cfffaa6
CMR-9848:
Sep 18, 2024
55ba3e1
CMR-9848: Modified the api doc
Sep 18, 2024
5a4f989
CMR-9848: Modified API doc
Sep 18, 2024
a4dab32
CMR-9848: Removed print.
Sep 18, 2024
3c38e61
CMR-9848: Fixed api doc.
Sep 18, 2024
47d0ec2
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
jmaeng72 Dec 3, 2024
e7c9bb9
update doc
jmaeng72 Dec 3, 2024
d22b907
fix tag assoc and disassoc
jmaeng72 Dec 3, 2024
a76845e
remove comments
jmaeng72 Dec 3, 2024
4d479d4
add statuses to 207 assoc responses and update unit and int tests
jmaeng72 Dec 10, 2024
9605ba1
update docs and fix last int test
jmaeng72 Dec 11, 2024
00d7941
remove print statements
jmaeng72 Dec 11, 2024
af94d29
prettify
jmaeng72 Dec 11, 2024
01fa43b
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
jmaeng72 Dec 11, 2024
127cce5
prettify doc
jmaeng72 Dec 11, 2024
669f0e7
pr comments
jmaeng72 Dec 19, 2024
4f1b60f
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
jmaeng72 Dec 19, 2024
21e23aa
clean up int tests and make api-response funcs private
jmaeng72 Dec 19, 2024
66cba06
remove atoms in funcs
jmaeng72 Dec 20, 2024
02f3f66
Merge branch 'master' of https://github.com/nasa/Common-Metadata-Repo…
jmaeng72 Dec 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 209 additions & 37 deletions search-app/docs/api.md

Large diffs are not rendered by default.

49 changes: 34 additions & 15 deletions search-app/src/cmr/search/api/association.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,48 @@
[headers]
(mt/extract-header-mime-type #{mt/json} headers "content-type" true))

(defn add-individual-statuses
jceaser marked this conversation as resolved.
Show resolved Hide resolved
"When given a list of response entities, will set the http response status of each response entity based on its content.
Ex) If the response entity contains an error message, will set the status as 400."
[list]
(map #(assoc % :status (if (or (:errors %) (:warning %)) 400 200))
list))

(defn- api-response
"Creates a successful association response with the given data response"
([data]
(api-response 200 data))
"Creates an association response with the given data response"
([status-code data]
{:status status-code
:body (json/generate-string (util/snake-case-data data))
:headers {"Content-Type" mt/json}}))
;; For association responses that partially fail we want to return a 207 and
;; detail which associations failed and/or succeeded in the given body
(let [data-value (if (= 207 status-code)
(add-individual-statuses data)
data)]
{:status status-code
:body (json/generate-string (util/snake-case-data data-value))
:headers {"Content-Type" mt/json}})))

(defn- results-contain-errors?
"Returns true if the results contain :errors"
(defn num-errors-in-assoc-results
"Counts the number of errors in association-results"
[results]
(seq (filter #(some? (:errors %)) results)))
(count (filter :errors results)))

(defn association-results->status-code
"Check for concept-types requiring error status to be returned. This is currently :service and :variable
If the concept-type is error-sensitive the function will check for any errors in the results, and will return 400 if
any are errors are present. Otherwise it will return 200"
"Check for concept-types requiring error status to be returned.
If the concept-type is error-sensitive the function will check for any errors in the results.
Will return:
- 200 OK -- if response has no errors
- 207 MULTI-STATUS -- if response has some errors and some successes
- 400 BAD REQUEST -- if response has all errors"
[concept-type results]
(if (some #{concept-type} '(:variable :service :tool))
(if (results-contain-errors? results)
400
200)
(let [result-count (count results)
num-errors (num-errors-in-assoc-results results)]
(if (= 0 result-count)
200
(if (= num-errors result-count)
400
(if (> num-errors 0)
207
200))))
200))

(defn associate-concept-to-collections
Expand Down
60 changes: 34 additions & 26 deletions search-app/src/cmr/search/api/generic_association.clj
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
(ns cmr.search.api.generic-association
"Defines common functions used by associations among generic concepts in the CMR."
(:require
[cheshire.core :as json]
[cmr.common-app.api.enabled :as common-enabled]
[cmr.common.concepts :as common-concepts]
[cmr.common.log :refer (info)]
[cmr.common.mime-types :as mt]
[cmr.common.util :as util]
[cmr.search.services.generic-association-service :as generic-assoc-service]
[compojure.core :refer :all]))
[cheshire.core :as json]
[cmr.common-app.api.enabled :as common-enabled]
[cmr.common.concepts :as common-concepts]
[cmr.common.log :refer (info)]
[cmr.common.mime-types :as mt]
[cmr.common.util :as util]
[cmr.search.api.association :as assoc]
[cmr.search.services.generic-association-service :as generic-assoc-service]
[compojure.core :refer :all]))

(defn- validate-association-content-type
"Validates that content type sent with a association is JSON."
Expand All @@ -17,24 +18,31 @@

(defn- api-response
"Creates a successful association response with the given data response"
([data]
(api-response 200 data))
([status-code data]
{:status status-code
:body (json/generate-string (util/snake-case-data data))
:headers {"Content-Type" mt/json}}))
[status-code data]
(if (= 207 status-code)
{:status status-code
:body (json/generate-string (util/snake-case-data (assoc/add-individual-statuses data)))
:headers {"Content-Type" mt/json}}
{:status status-code
:body (json/generate-string (util/snake-case-data data))
:headers {"Content-Type" mt/json}}))

(defn- results-contain-errors?
"Returns true if the results contain :errors"
(defn generic-assoc-results->status-code
"Return status code depending on if results contains error.
Check for concept-types requiring error status to be returned.
If the concept-type is error-sensitive the function will check for any errors in the results.
Will return:
- 200 OK -- if response has no errors
- 207 MULTI-STATUS -- if response has some errors and some successes
- 400 BAD REQUEST -- if response has all errors"
[results]
(seq (filter #(some? (:errors %)) results)))

(defn- results->status-code
"Return status code depending on if results contains error."
[results]
(if (results-contain-errors? results)
400
200))
(let [result-count (count results)
num-errors (assoc/num-errors-in-assoc-results results)]
(cond
(zero? result-count) 200
(= num-errors result-count) 400
(pos? num-errors) 207
:else 200)))

(defn associate-concept-to-concepts
"Associate the given concept by concept type and concept id to a list of
Expand All @@ -47,7 +55,7 @@
concept-id revision-id body (:client-id context)))
(let [concept-type (common-concepts/concept-id->type concept-id)
results (generic-assoc-service/associate-to-concepts context concept-type concept-id revision-id body)
status-code (results->status-code results)]
status-code (generic-assoc-results->status-code results)]
(api-response status-code results)))

(defn dissociate-concept-from-concepts
Expand All @@ -60,5 +68,5 @@
concept-id revision-id body (:client-id context)))
(let [concept-type (common-concepts/concept-id->type concept-id)
results (generic-assoc-service/dissociate-from-concepts context concept-type concept-id revision-id body)
status-code (results->status-code results)]
status-code (generic-assoc-results->status-code results)]
(api-response status-code results)))
34 changes: 29 additions & 5 deletions search-app/src/cmr/search/api/tags.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[clojure.string :as string]
[cmr.acl.core :as acl]
[cmr.common-app.api.enabled :as common-enabled]
[cmr.common.log :refer (debug info warn error)]
[cmr.common.log :refer (debug)]
jceaser marked this conversation as resolved.
Show resolved Hide resolved
[cmr.search.api.association :as assoc]
[cmr.common.mime-types :as mt]
[cmr.common.services.errors :as errors]
[cmr.common.util :as util]
Expand All @@ -23,16 +24,35 @@
[data]
(some #(contains? % :errors) data))

(defn tag-association-results->status-code
"Check for concept-types requiring error status to be returned.
If the concept-type is error-sensitive the function will check for any errors in the results.
Will return:
- 200 OK -- if response has no errors
- 207 MULTI-STATUS -- if response has some errors and some successes
- 400 BAD REQUEST -- if response has all errors"
[results]
(let [result-count (count results)
num-errors (assoc/num-errors-in-assoc-results results)]
(cond
(zero? result-count) 200
(= num-errors result-count) 400
(pos? num-errors) 207
:else 200)))

jceaser marked this conversation as resolved.
Show resolved Hide resolved
(defn tag-api-response
"Creates a successful tag response with the given data response"
([data]
(if (has-error? data)
(tag-api-response 400 data)
(tag-api-response 200 data)))
([status-code data]
(let [data-val (if (= 207 status-code)
(assoc/add-individual-statuses data)
data)]
{:status status-code
:body (json/generate-string (util/snake-case-data data))
:headers {"Content-Type" mt/json}}))
:body (json/generate-string (util/snake-case-data data-val))
:headers {"Content-Type" mt/json}})))

(defn- verify-tag-modification-permission
"Verifies the current user has been granted permission to modify tags in ECHO ACLs"
Expand Down Expand Up @@ -81,7 +101,9 @@
(validate-tag-content-type headers)
(debug (format "Tagging [%s] on collections: %s by client: %s."
tag-key body (:client-id context)))
(tag-api-response (tagging-service/associate-tag-to-collections context tag-key body)))
(let [result (tagging-service/associate-tag-to-collections context tag-key body)
status-code (tag-association-results->status-code result)]
(tag-api-response status-code result)))

(defn dissociate-tag-to-collections
"Dissociate the tag to a list of collections."
Expand All @@ -91,7 +113,9 @@
(validate-tag-content-type headers)
(debug (format "Dissociating tag [%s] from collections: %s by client: %s."
tag-key body (:client-id context)))
(tag-api-response (tagging-service/dissociate-tag-to-collections context tag-key body)))
(let [result (tagging-service/dissociate-tag-to-collections context tag-key body)
status-code (tag-association-results->status-code result)]
(tag-api-response status-code result)))

(defn associate-tag-by-query
"Processes a request to associate a tag."
Expand Down
Loading
Loading