rucio 37.5.0__py3-none-any.whl → 37.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rucio might be problematic. Click here for more details.

Files changed (202) hide show
  1. rucio/cli/bin_legacy/rucio.py +41 -22
  2. rucio/cli/bin_legacy/rucio_admin.py +1 -1
  3. rucio/cli/did.py +2 -2
  4. rucio/cli/rse.py +2 -3
  5. rucio/cli/rule.py +9 -5
  6. rucio/cli/subscription.py +1 -1
  7. rucio/client/baseclient.py +9 -4
  8. rucio/client/didclient.py +16 -16
  9. rucio/client/downloadclient.py +16 -15
  10. rucio/client/exportclient.py +45 -4
  11. rucio/client/lockclient.py +3 -3
  12. rucio/client/pingclient.py +35 -4
  13. rucio/client/replicaclient.py +2 -2
  14. rucio/client/touchclient.py +3 -2
  15. rucio/client/uploadclient.py +728 -183
  16. rucio/common/cache.py +1 -2
  17. rucio/common/client.py +4 -30
  18. rucio/common/config.py +27 -3
  19. rucio/common/constants.py +5 -1
  20. rucio/common/didtype.py +2 -2
  21. rucio/common/dumper/__init__.py +1 -1
  22. rucio/common/pcache.py +20 -25
  23. rucio/common/plugins.py +12 -19
  24. rucio/common/policy.py +3 -2
  25. rucio/common/schema/__init__.py +11 -8
  26. rucio/common/types.py +7 -5
  27. rucio/common/utils.py +1 -1
  28. rucio/core/account.py +2 -1
  29. rucio/core/account_limit.py +3 -2
  30. rucio/core/authentication.py +1 -1
  31. rucio/core/credential.py +1 -1
  32. rucio/core/did.py +62 -61
  33. rucio/core/did_meta_plugins/__init__.py +10 -10
  34. rucio/core/did_meta_plugins/did_column_meta.py +9 -9
  35. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +3 -3
  36. rucio/core/did_meta_plugins/elasticsearch_meta.py +7 -7
  37. rucio/core/did_meta_plugins/json_meta.py +2 -2
  38. rucio/core/did_meta_plugins/mongo_meta.py +9 -9
  39. rucio/core/did_meta_plugins/postgres_meta.py +7 -7
  40. rucio/core/dirac.py +3 -2
  41. rucio/core/distance.py +2 -1
  42. rucio/core/exporter.py +3 -2
  43. rucio/core/importer.py +5 -5
  44. rucio/core/lifetime_exception.py +2 -2
  45. rucio/core/lock.py +7 -7
  46. rucio/core/meta_conventions.py +2 -2
  47. rucio/core/monitor.py +1 -1
  48. rucio/core/naming_convention.py +1 -1
  49. rucio/core/nongrid_trace.py +2 -2
  50. rucio/core/oidc.py +2 -2
  51. rucio/core/permission/__init__.py +9 -6
  52. rucio/core/permission/generic.py +2 -2
  53. rucio/core/permission/generic_multi_vo.py +2 -2
  54. rucio/core/replica.py +22 -22
  55. rucio/core/request.py +2 -2
  56. rucio/core/rse.py +7 -7
  57. rucio/core/rule.py +38 -38
  58. rucio/core/rule_grouping.py +2 -3
  59. rucio/core/scope.py +1 -1
  60. rucio/core/trace.py +2 -2
  61. rucio/core/transfer.py +2 -2
  62. rucio/core/vo.py +2 -1
  63. rucio/daemons/atropos/atropos.py +2 -1
  64. rucio/daemons/auditor/__init__.py +1 -1
  65. rucio/daemons/automatix/automatix.py +5 -5
  66. rucio/daemons/badreplicas/minos.py +12 -5
  67. rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -2
  68. rucio/daemons/badreplicas/necromancer.py +9 -3
  69. rucio/daemons/bb8/bb8.py +2 -1
  70. rucio/daemons/bb8/common.py +1 -1
  71. rucio/daemons/bb8/nuclei_background_rebalance.py +3 -3
  72. rucio/daemons/bb8/t2_background_rebalance.py +1 -1
  73. rucio/daemons/cache/consumer.py +1 -1
  74. rucio/daemons/conveyor/common.py +3 -3
  75. rucio/daemons/conveyor/finisher.py +13 -4
  76. rucio/daemons/conveyor/poller.py +5 -2
  77. rucio/daemons/conveyor/receiver.py +1 -1
  78. rucio/daemons/conveyor/submitter.py +2 -1
  79. rucio/daemons/follower/follower.py +1 -1
  80. rucio/daemons/hermes/hermes.py +29 -8
  81. rucio/daemons/judge/cleaner.py +2 -2
  82. rucio/daemons/judge/evaluator.py +7 -7
  83. rucio/daemons/judge/injector.py +2 -2
  84. rucio/daemons/judge/repairer.py +2 -2
  85. rucio/daemons/reaper/dark_reaper.py +5 -4
  86. rucio/daemons/reaper/reaper.py +7 -7
  87. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +4 -4
  88. rucio/daemons/storage/consistency/actions.py +3 -3
  89. rucio/daemons/tracer/kronos.py +3 -2
  90. rucio/daemons/transmogrifier/transmogrifier.py +71 -69
  91. rucio/daemons/undertaker/undertaker.py +8 -7
  92. rucio/db/sqla/constants.py +4 -3
  93. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -1
  94. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +1 -1
  95. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +1 -1
  96. rucio/db/sqla/models.py +3 -3
  97. rucio/db/sqla/session.py +7 -7
  98. rucio/db/sqla/util.py +3 -2
  99. rucio/gateway/account.py +77 -101
  100. rucio/gateway/account_limit.py +90 -116
  101. rucio/gateway/authentication.py +9 -8
  102. rucio/gateway/config.py +11 -10
  103. rucio/gateway/credential.py +2 -1
  104. rucio/gateway/did.py +58 -58
  105. rucio/gateway/dirac.py +3 -2
  106. rucio/gateway/exporter.py +2 -1
  107. rucio/gateway/heartbeat.py +3 -2
  108. rucio/gateway/identity.py +4 -3
  109. rucio/gateway/importer.py +2 -1
  110. rucio/gateway/lifetime_exception.py +5 -4
  111. rucio/gateway/lock.py +6 -5
  112. rucio/gateway/meta_conventions.py +3 -2
  113. rucio/gateway/permission.py +2 -1
  114. rucio/gateway/quarantined_replica.py +2 -1
  115. rucio/gateway/replica.py +20 -20
  116. rucio/gateway/request.py +10 -10
  117. rucio/gateway/rse.py +27 -26
  118. rucio/gateway/rule.py +12 -11
  119. rucio/gateway/scope.py +4 -3
  120. rucio/gateway/subscription.py +7 -6
  121. rucio/gateway/vo.py +5 -4
  122. rucio/rse/__init__.py +7 -6
  123. rucio/rse/protocols/ngarc.py +2 -2
  124. rucio/rse/protocols/srm.py +1 -1
  125. rucio/rse/protocols/webdav.py +8 -1
  126. rucio/rse/rsemanager.py +5 -4
  127. rucio/rse/translation.py +2 -2
  128. rucio/tests/common.py +6 -5
  129. rucio/vcsversion.py +3 -3
  130. rucio/web/rest/flaskapi/v1/accountlimits.py +5 -5
  131. rucio/web/rest/flaskapi/v1/accounts.py +20 -20
  132. rucio/web/rest/flaskapi/v1/archives.py +4 -3
  133. rucio/web/rest/flaskapi/v1/common.py +5 -4
  134. rucio/web/rest/flaskapi/v1/dids.py +382 -331
  135. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +5 -5
  136. rucio/web/rest/flaskapi/v1/locks.py +13 -13
  137. rucio/web/rest/flaskapi/v1/main.py +1 -0
  138. rucio/web/rest/flaskapi/v1/redirect.py +2 -2
  139. rucio/web/rest/flaskapi/v1/replicas.py +16 -16
  140. rucio/web/rest/flaskapi/v1/requests.py +16 -16
  141. rucio/web/rest/flaskapi/v1/subscriptions.py +7 -7
  142. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-account +8 -1
  143. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-rse +8 -1
  144. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-auditor +1 -1
  145. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-throttler +7 -1
  146. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-follower +1 -1
  147. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-cleaner +9 -1
  148. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-necromancer +7 -1
  149. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-replica-recoverer +31 -9
  150. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-undertaker +8 -2
  151. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/METADATA +1 -1
  152. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/RECORD +202 -202
  153. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/alembic.ini.template +0 -0
  154. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  155. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  156. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
  157. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  158. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  159. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  160. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  161. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  162. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  163. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  164. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  165. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
  166. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  167. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/requirements.server.txt +0 -0
  168. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/bootstrap.py +0 -0
  169. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  170. {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/reset_database.py +0 -0
  171. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio +0 -0
  172. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-collection-replica +0 -0
  173. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-admin +0 -0
  174. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-atropos +0 -0
  175. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-automatix +0 -0
  176. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-bb8 +0 -0
  177. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-cache-client +0 -0
  178. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-cache-consumer +0 -0
  179. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-finisher +0 -0
  180. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-poller +0 -0
  181. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-preparer +0 -0
  182. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-receiver +0 -0
  183. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-stager +0 -0
  184. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-submitter +0 -0
  185. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-dark-reaper +0 -0
  186. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-dumper +0 -0
  187. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-hermes +0 -0
  188. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-evaluator +0 -0
  189. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-injector +0 -0
  190. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-repairer +0 -0
  191. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-kronos +0 -0
  192. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-minos +0 -0
  193. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
  194. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-oauth-manager +0 -0
  195. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-reaper +0 -0
  196. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-rse-decommissioner +0 -0
  197. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-storage-consistency-actions +0 -0
  198. {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-transmogrifier +0 -0
  199. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/WHEEL +0 -0
  200. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/licenses/AUTHORS.rst +0 -0
  201. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/licenses/LICENSE +0 -0
  202. {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,6 @@ from rucio.common.exception import (
22
22
  DatabaseException,
23
23
  DataIdentifierAlreadyExists,
24
24
  DataIdentifierNotFound,
25
- Duplicate,
26
25
  DuplicateContent,
27
26
  FileAlreadyExists,
28
27
  FileConsistencyMismatch,
@@ -94,7 +93,7 @@ class Scope(ErrorHandlingMethodView):
94
93
  style: simple
95
94
  - name: name
96
95
  in: query
97
- description: "The name of the data identifier (did)."
96
+ description: "The name of the data identifier (DID)."
98
97
  required: false
99
98
  schema:
100
99
  type: string
@@ -110,7 +109,7 @@ class Scope(ErrorHandlingMethodView):
110
109
  content:
111
110
  application/x-json-stream:
112
111
  schema:
113
- description: "Line-separated dictionary of dids."
112
+ description: "Line-separated dictionary of DIDs."
114
113
  type: array
115
114
  items:
116
115
  type: object
@@ -118,24 +117,24 @@ class Scope(ErrorHandlingMethodView):
118
117
  properties:
119
118
  scope:
120
119
  type: string
121
- description: "The scope of the did."
120
+ description: "The scope of the DID."
122
121
  name:
123
122
  type: string
124
- description: "The name of the did."
123
+ description: "The name of the DID."
125
124
  type:
126
125
  type: string
127
- description: "The type of the did."
126
+ description: "The type of the DID."
128
127
  enum: ['F', 'D', 'C', 'A', 'X', 'Y', 'Z']
129
128
  parent:
130
129
  type: string
131
- description: "The parent of the did."
130
+ description: "The parent of the DID."
132
131
  level:
133
132
  type: integer
134
- description: "The level of the did."
133
+ description: "The level of the DID."
135
134
  401:
136
135
  description: "Invalid Auth Token"
137
136
  404:
138
- description: "No Dids found"
137
+ description: "No DIDs found"
139
138
  406:
140
139
  description: "Not acceptable"
141
140
  """
@@ -176,14 +175,14 @@ class Search(ErrorHandlingMethodView):
176
175
  style: simple
177
176
  - name: type
178
177
  in: query
179
- description: "The did type to search for."
178
+ description: "The DID type to search for."
180
179
  schema:
181
180
  type: string
182
181
  enum: ['all', 'collection', 'container', 'dataset', 'file']
183
182
  default: 'collection'
184
183
  - name: limit
185
184
  in: query
186
- description: "The maximum number od dids returned."
185
+ description: "The maximum number of DIDs returned."
187
186
  schema:
188
187
  type: integer
189
188
  - name: long
@@ -234,7 +233,7 @@ class Search(ErrorHandlingMethodView):
234
233
  type: integer
235
234
  - name: name
236
235
  in: query
237
- description: "Name or pattern of a did."
236
+ description: "Name or pattern of a DID."
238
237
  schema:
239
238
  type: string
240
239
  responses:
@@ -255,7 +254,7 @@ class Search(ErrorHandlingMethodView):
255
254
  406:
256
255
  description: "Not acceptable"
257
256
  409:
258
- description: "Wrong did type"
257
+ description: "Wrong DID type"
259
258
  """
260
259
  filters = request.args.get('filters', default=None)
261
260
  if filters is not None:
@@ -289,8 +288,8 @@ class BulkDIDS(ErrorHandlingMethodView):
289
288
  def post(self):
290
289
  """
291
290
  ---
292
- summary: Add Dids bulk
293
- description: "Add new Dids in bulk."
291
+ summary: Add DIDs bulk
292
+ description: "Add new DIDs in bulk."
294
293
  tags:
295
294
  - Data Identifiers
296
295
  requestBody:
@@ -299,7 +298,7 @@ class BulkDIDS(ErrorHandlingMethodView):
299
298
  schema:
300
299
  type: array
301
300
  items:
302
- description: "One did to add."
301
+ description: "One DID to add."
303
302
  type: object
304
303
  required:
305
304
  - scope
@@ -307,17 +306,17 @@ class BulkDIDS(ErrorHandlingMethodView):
307
306
  - type
308
307
  properties:
309
308
  scope:
310
- description: "The did scope."
309
+ description: "The DID scope."
311
310
  type: string
312
311
  name:
313
- description: "The did name."
312
+ description: "The DID name."
314
313
  type: string
315
314
  type:
316
- description: "The type of the did."
315
+ description: "The type of the DID."
317
316
  type: string
318
317
  enum: ["F", "D", "C", "A", "X", "Y", "Z"]
319
318
  account:
320
- description: "The account associated with the did."
319
+ description: "The account associated with the DID."
321
320
  type: string
322
321
  statuses:
323
322
  description: "The monotonic status"
@@ -335,7 +334,7 @@ class BulkDIDS(ErrorHandlingMethodView):
335
334
  406:
336
335
  description: "Not acceptable"
337
336
  409:
338
- description: "Did already exists"
337
+ description: "DID already exists"
339
338
  """
340
339
  dids = json_list()
341
340
  try:
@@ -354,8 +353,8 @@ class Attachments(ErrorHandlingMethodView):
354
353
  def post(self):
355
354
  """
356
355
  ---
357
- summary: Attach did to did
358
- description: "Attaches a did to another did"
356
+ summary: Attach DID to DID
357
+ description: "Attaches a DID to another DID"
359
358
  tags:
360
359
  - Data Identifiers
361
360
  requestBody:
@@ -363,7 +362,7 @@ class Attachments(ErrorHandlingMethodView):
363
362
  'application/json':
364
363
  schema:
365
364
  oneOf:
366
- - description: An array containing all dids. Duplicates are not ignored.
365
+ - description: An array containing all DIDs. Duplicates are not ignored.
367
366
  type: array
368
367
  required:
369
368
  - scope
@@ -371,29 +370,29 @@ class Attachments(ErrorHandlingMethodView):
371
370
  - dids
372
371
  properties:
373
372
  scope:
374
- description: "The scope of the did."
373
+ description: "The scope of the DID."
375
374
  type: string
376
375
  name:
377
- description: "The name of the did."
376
+ description: "The name of the DID."
378
377
  type: string
379
378
  dids:
380
- description: "The dids associated to the did."
379
+ description: "The DIDs associated with the DID."
381
380
  type: array
382
381
  items:
383
382
  type: object
384
- description: "A did."
383
+ description: "A DID."
385
384
  required:
386
385
  - scope
387
386
  - name
388
387
  properties:
389
388
  scope:
390
- description: "The scope of the did."
389
+ description: "The scope of the DID."
391
390
  type: string
392
391
  name:
393
- description: "The name of the did."
392
+ description: "The name of the DID."
394
393
  type: string
395
394
  rse_id:
396
- description: "The rse id of the did."
395
+ description: "The rse id of the DID."
397
396
  type: string
398
397
  - type: object
399
398
  required:
@@ -404,7 +403,7 @@ class Attachments(ErrorHandlingMethodView):
404
403
  type: boolean
405
404
  default: false
406
405
  attachments:
407
- description: "An array containing all dids. Duplicates are not ignored."
406
+ description: "An array containing all DIDs. Duplicates are not ignored."
408
407
  type: array
409
408
  required:
410
409
  - scope
@@ -412,29 +411,29 @@ class Attachments(ErrorHandlingMethodView):
412
411
  - dids
413
412
  properties:
414
413
  scope:
415
- description: "The scope of the did."
414
+ description: "The scope of the DID."
416
415
  type: string
417
416
  name:
418
- description: "The name of the did."
417
+ description: "The name of the DID."
419
418
  type: string
420
419
  dids:
421
- description: "The dids associated to the did."
420
+ description: "The DIDs associated to the DID."
422
421
  type: array
423
422
  items:
424
423
  type: object
425
- description: "A did."
424
+ description: "A DID."
426
425
  required:
427
426
  - scope
428
427
  - name
429
428
  properties:
430
429
  scope:
431
- description: "The scope of the did."
430
+ description: "The scope of the DID."
432
431
  type: string
433
432
  name:
434
- description: "The name of the did."
433
+ description: "The name of the DID."
435
434
  type: string
436
435
  rse_id:
437
- description: "The rse id of the did."
436
+ description: "The rse id of the DID."
438
437
  type: string
439
438
  responses:
440
439
  200:
@@ -481,14 +480,14 @@ class DIDs(ErrorHandlingMethodView):
481
480
  def get(self, scope_name):
482
481
  """
483
482
  ---
484
- summary: Get did
483
+ summary: Get DID
485
484
  description: "Get a single data identifier."
486
485
  tags:
487
486
  - Data identifiers
488
487
  parameters:
489
488
  - name: scope_name
490
489
  in: path
491
- description: "The scope and the name of the did."
490
+ description: "The scope and the name of the DID."
492
491
  schema:
493
492
  type: string
494
493
  style: simple
@@ -511,14 +510,14 @@ class DIDs(ErrorHandlingMethodView):
511
510
  application/json:
512
511
  schema:
513
512
  oneOf:
514
- - description: "A single file did."
513
+ - description: "A single file DID."
515
514
  type: object
516
515
  properties:
517
516
  scope:
518
- description: "The scope of the did."
517
+ description: "The scope of the DID."
519
518
  type: string
520
519
  name:
521
- description: "The name of the did."
520
+ description: "The name of the DID."
522
521
  type: string
523
522
  type:
524
523
  description: "The type of the string."
@@ -539,14 +538,14 @@ class DIDs(ErrorHandlingMethodView):
539
538
  adler32:
540
539
  description: "adler32 checksum."
541
540
  type: string
542
- - description: "A single file did."
541
+ - description: "A single file DID."
543
542
  type: object
544
543
  properties:
545
544
  scope:
546
- description: "The scope of the did."
545
+ description: "The scope of the DID."
547
546
  type: string
548
547
  name:
549
- description: "The name of the did."
548
+ description: "The name of the DID."
550
549
  type: string
551
550
  type:
552
551
  description: "The type of the string."
@@ -555,16 +554,16 @@ class DIDs(ErrorHandlingMethodView):
555
554
  description: "The associated account."
556
555
  type: string
557
556
  open:
558
- description: "If the did is write open."
557
+ description: "If the DID is write open."
559
558
  type: boolean
560
559
  monotonic:
561
- description: "If the did is monotonic."
560
+ description: "If the DID is monotonic."
562
561
  type: boolean
563
562
  expired_at:
564
- description: "When the did expired."
563
+ description: "When the DID expired."
565
564
  type: string
566
565
  length:
567
- description: "The number of associated dids."
566
+ description: "The number of associated DIDs."
568
567
  type: number
569
568
  bytes:
570
569
  description: "The size in bytes."
@@ -599,14 +598,14 @@ class DIDs(ErrorHandlingMethodView):
599
598
  def post(self, scope_name):
600
599
  """
601
600
  ---
602
- summary: Create did
601
+ summary: Create DID
603
602
  description: "Create a new data identifier."
604
603
  tags:
605
604
  - Data Identifiers
606
605
  parameters:
607
606
  - name: scope_name
608
607
  in: path
609
- description: "The scope and the name of the did."
608
+ description: "The scope and the name of the DID."
610
609
  schema:
611
610
  type: string
612
611
  style: simple
@@ -619,38 +618,38 @@ class DIDs(ErrorHandlingMethodView):
619
618
  - type
620
619
  properties:
621
620
  type:
622
- description: "The type of the did."
621
+ description: "The type of the DID."
623
622
  type: string
624
623
  statuses:
625
- description: "The statuses of the did."
624
+ description: "The statuses of the DID."
626
625
  type: string
627
626
  meta:
628
- description: "The meta of the did."
627
+ description: "The meta of the DID."
629
628
  type: string
630
629
  rules:
631
- description: "The rules associated with the did."
630
+ description: "The rules associated with the DID."
632
631
  type: array
633
632
  items:
634
633
  type: object
635
634
  description: "A rule."
636
635
  lifetime:
637
- description: "The lifetime of the did."
636
+ description: "The lifetime of the DID."
638
637
  type: string
639
638
  dids:
640
- description: "The dids associated with the did."
639
+ description: "The DIDs associated with the DID."
641
640
  type: array
642
641
  items:
643
642
  type: object
644
- description: "The did associated with a did."
643
+ description: "The DID associated with a DID."
645
644
  properties:
646
645
  scope:
647
- description: "The scope of the did."
646
+ description: "The scope of the DID."
648
647
  type: string
649
648
  name:
650
- description: "The name of the did."
649
+ description: "The name of the DID."
651
650
  type: string
652
651
  rse:
653
- description: "The rse associated with the did."
652
+ description: "The rse associated with the DID."
654
653
  type: string
655
654
  responses:
656
655
  201:
@@ -663,9 +662,9 @@ class DIDs(ErrorHandlingMethodView):
663
662
  401:
664
663
  description: "Invalid Auth Token"
665
664
  404:
666
- description: "Did or scope not found"
665
+ description: "DID or scope not found"
667
666
  409:
668
- description: "Did already exists"
667
+ description: "DID already exists"
669
668
  """
670
669
  try:
671
670
  scope, name = parse_scope_name(scope_name, request.environ['vo'])
@@ -712,14 +711,14 @@ class DIDs(ErrorHandlingMethodView):
712
711
  def put(self, scope_name):
713
712
  """
714
713
  ---
715
- summary: Update did
716
- description: "Update a did."
714
+ summary: Update DID
715
+ description: "Update a DID."
717
716
  tags:
718
717
  - Data Identifiers
719
718
  parameters:
720
719
  - name: scope_name
721
720
  in: path
722
- description: "The scope and the name of the did."
721
+ description: "The scope and the name of the DID."
723
722
  schema:
724
723
  type: string
725
724
  style: simple
@@ -738,7 +737,7 @@ class DIDs(ErrorHandlingMethodView):
738
737
  401:
739
738
  description: "Invalid Auth Token"
740
739
  404:
741
- description: "Did not found"
740
+ description: "DID not found"
742
741
  409:
743
742
  description: "Wrong status"
744
743
  """
@@ -767,24 +766,24 @@ class Attachment(ErrorHandlingMethodView):
767
766
  def get(self, scope_name):
768
767
  """
769
768
  ---
770
- summary: Get did
769
+ summary: Get DID
771
770
  description: "Returns the contents of a data identifier."
772
771
  tags:
773
772
  - Data Identifiers
774
773
  parameters:
775
774
  - name: scope_name
776
775
  in: path
777
- description: "The scope and the name of the did."
776
+ description: "The scope and the name of the DID."
778
777
  schema:
779
778
  type: string
780
779
  style: simple
781
780
  responses:
782
781
  200:
783
- description: "Did found"
782
+ description: "DID found"
784
783
  content:
785
784
  application/x-json-stream:
786
785
  schema:
787
- description: "The contents of a did. Items are line separated."
786
+ description: "The contents of a DID. Items are line separated."
788
787
  type: array
789
788
  items:
790
789
  type: object
@@ -797,22 +796,22 @@ class Attachment(ErrorHandlingMethodView):
797
796
  - md5
798
797
  properties:
799
798
  scope:
800
- description: "The scope of the did."
799
+ description: "The scope of the DID."
801
800
  type: string
802
801
  name:
803
- description: "The name of the did."
802
+ description: "The name of the DID."
804
803
  type: string
805
804
  type:
806
- description: "The type of the did."
805
+ description: "The type of the DID."
807
806
  type: string
808
807
  bytes:
809
- description: "The size of the did."
808
+ description: "The size of the DID."
810
809
  type: number
811
810
  adler32:
812
- description: "The adler32 checksum of the did."
811
+ description: "The adler32 checksum of the DID."
813
812
  type: string
814
813
  md5:
815
- description: "The md5 checksum of the did."
814
+ description: "The md5 checksum of the DID."
816
815
  type: string
817
816
  401:
818
817
  description: "Invalid Auth Token"
@@ -837,14 +836,14 @@ class Attachment(ErrorHandlingMethodView):
837
836
  def post(self, scope_name):
838
837
  """
839
838
  ---
840
- summary: Add dids to did
839
+ summary: Add DIDs to DID
841
840
  description: "Append data identifiers to data identifiers."
842
841
  tags:
843
842
  - Data Identifiers
844
843
  parameters:
845
844
  - name: scope_name
846
845
  in: path
847
- description: "The scope and the name of the did."
846
+ description: "The scope and the name of the DID."
848
847
  schema:
849
848
  type: string
850
849
  style: simple
@@ -860,20 +859,20 @@ class Attachment(ErrorHandlingMethodView):
860
859
  description: "The name of the rse."
861
860
  type: string
862
861
  account:
863
- description: "The account which attaches the dids."
862
+ description: "The account which attaches the DIDs."
864
863
  type: string
865
864
  dids:
866
- description: "The dids to attach."
865
+ description: "The DIDs to attach."
867
866
  type: object
868
867
  properties:
869
868
  account:
870
- description: "The account attaching the did."
869
+ description: "The account attaching the DID."
871
870
  type: string
872
871
  scope:
873
- description: "The scope of the did."
872
+ description: "The scope of the DID."
874
873
  type: string
875
874
  name:
876
- description: "The name of the did."
875
+ description: "The name of the DID."
877
876
  type: string
878
877
  responses:
879
878
  201:
@@ -886,7 +885,7 @@ class Attachment(ErrorHandlingMethodView):
886
885
  401:
887
886
  description: "Invalid Auth Token"
888
887
  404:
889
- description: "Did not found"
888
+ description: "DID not found"
890
889
  406:
891
890
  description: "Not acceptable"
892
891
  409:
@@ -915,14 +914,14 @@ class Attachment(ErrorHandlingMethodView):
915
914
  def delete(self, scope_name):
916
915
  """
917
916
  ---
918
- summary: Detach dids from did
917
+ summary: Detach DIDs from DID
919
918
  description: "Detach data identifiers from data identifiers."
920
919
  tags:
921
920
  - Data Identifiers
922
921
  parameters:
923
922
  - name: scope_name
924
923
  in: path
925
- description: "The scope and the name of the did."
924
+ description: "The scope and the name of the DID."
926
925
  schema:
927
926
  type: string
928
927
  style: simple
@@ -935,16 +934,16 @@ class Attachment(ErrorHandlingMethodView):
935
934
  - dids
936
935
  properties:
937
936
  dids:
938
- description: "The dids to detach."
937
+ description: "The DIDs to detach."
939
938
  type: array
940
939
  items:
941
940
  type: object
942
941
  properties:
943
942
  scope:
944
- description: "The scope of the did."
943
+ description: "The scope of the DID."
945
944
  type: string
946
945
  name:
947
- description: "The name of the did."
946
+ description: "The name of the DID."
948
947
  type: string
949
948
  responses:
950
949
  200:
@@ -952,7 +951,7 @@ class Attachment(ErrorHandlingMethodView):
952
951
  401:
953
952
  description: "Invalid Auth Token"
954
953
  404:
955
- description: "Did not found"
954
+ description: "DID not found"
956
955
  """
957
956
  try:
958
957
  scope, name = parse_scope_name(scope_name, request.environ['vo'])
@@ -987,33 +986,33 @@ class AttachmentHistory(ErrorHandlingMethodView):
987
986
  parameters:
988
987
  - name: scope_name
989
988
  in: path
990
- description: "The scope and the name of the did."
989
+ description: "The scope and the name of the DID."
991
990
  schema:
992
991
  type: string
993
992
  style: simple
994
993
  responses:
995
994
  200:
996
- description: "Did found"
995
+ description: "DID found"
997
996
  content:
998
997
  application/x-json-stream:
999
998
  schema:
1000
- description: "The dids with their information and history. Elements are separated by new line characters."
999
+ description: "The DIDs with their information and history. Elements are separated by new line characters."
1001
1000
  type: array
1002
1001
  items:
1003
1002
  type: object
1004
- description: "A single did with history data."
1003
+ description: "A single DID with history data."
1005
1004
  properties:
1006
1005
  scope:
1007
- description: "The scope of the did."
1006
+ description: "The scope of the DID."
1008
1007
  type: string
1009
1008
  name:
1010
- description: "The name of the did."
1009
+ description: "The name of the DID."
1011
1010
  type: string
1012
1011
  type:
1013
- description: "The type of the did."
1012
+ description: "The type of the DID."
1014
1013
  type: string
1015
1014
  bytes:
1016
- description: "The size of the did in bytes."
1015
+ description: "The size of the DID in bytes."
1017
1016
  type: integer
1018
1017
  adler32:
1019
1018
  description: "The abler32 sha checksum."
@@ -1028,12 +1027,12 @@ class AttachmentHistory(ErrorHandlingMethodView):
1028
1027
  description: "The created_at date time."
1029
1028
  type: string
1030
1029
  updated_at:
1031
- description: "The last time the did was updated."
1030
+ description: "The last time the DID was updated."
1032
1031
  type: string
1033
1032
  401:
1034
1033
  description: "Invalid Auth Token"
1035
1034
  404:
1036
- description: "Did not found"
1035
+ description: "DID not found"
1037
1036
  406:
1038
1037
  description: "Not acceptable"
1039
1038
  """
@@ -1058,13 +1057,13 @@ class Files(ErrorHandlingMethodView):
1058
1057
  """
1059
1058
  ---
1060
1059
  summary: Get replicas
1061
- description: "List all replicas for a did."
1060
+ description: "List all replicas for a DID."
1062
1061
  tags:
1063
1062
  - Data Identifiers
1064
1063
  parameters:
1065
1064
  - name: scope_name
1066
1065
  in: path
1067
- description: "The scope and the name of the did."
1066
+ description: "The scope and the name of the DID."
1068
1067
  schema:
1069
1068
  type: string
1070
1069
  style: simple
@@ -1087,19 +1086,19 @@ class Files(ErrorHandlingMethodView):
1087
1086
  type: object
1088
1087
  properties:
1089
1088
  scope:
1090
- description: "The scope of the did."
1089
+ description: "The scope of the DID."
1091
1090
  type: string
1092
1091
  name:
1093
- description: "The name of the did."
1092
+ description: "The name of the DID."
1094
1093
  type: string
1095
1094
  bytes:
1096
- description: "The size of the did in bytes."
1095
+ description: "The size of the DID in bytes."
1097
1096
  type: integer
1098
1097
  guid:
1099
- description: "The guid of the did."
1098
+ description: "The guid of the DID."
1100
1099
  type: string
1101
1100
  events:
1102
- description: "The number of events of the did."
1101
+ description: "The number of events of the DID."
1103
1102
  type: integer
1104
1103
  adler32:
1105
1104
  description: "The adler32 checksum."
@@ -1113,19 +1112,19 @@ class Files(ErrorHandlingMethodView):
1113
1112
  type: object
1114
1113
  properties:
1115
1114
  scope:
1116
- description: "The scope of the did."
1115
+ description: "The scope of the DID."
1117
1116
  type: string
1118
1117
  name:
1119
- description: "The name of the did."
1118
+ description: "The name of the DID."
1120
1119
  type: string
1121
1120
  bytes:
1122
- description: "The size of the did in bytes."
1121
+ description: "The size of the DID in bytes."
1123
1122
  type: integer
1124
1123
  guid:
1125
- description: "The guid of the did."
1124
+ description: "The guid of the DID."
1126
1125
  type: string
1127
1126
  events:
1128
- description: "The number of events of the did."
1127
+ description: "The number of events of the DID."
1129
1128
  type: integer
1130
1129
  adler32:
1131
1130
  description: "The adler32 checksum."
@@ -1133,7 +1132,7 @@ class Files(ErrorHandlingMethodView):
1133
1132
  401:
1134
1133
  description: "Invalid Auth Token"
1135
1134
  404:
1136
- description: "Did not found"
1135
+ description: "DID not found"
1137
1136
  406:
1138
1137
  description: "Not acceptable"
1139
1138
  """
@@ -1160,7 +1159,7 @@ class BulkFiles(ErrorHandlingMethodView):
1160
1159
  """
1161
1160
  ---
1162
1161
  summary: List files bulk
1163
- description: "List files in multiple dids"
1162
+ description: "List files in multiple DIDs"
1164
1163
  tags:
1165
1164
  - Data Identifiers
1166
1165
  requestBody:
@@ -1169,17 +1168,17 @@ class BulkFiles(ErrorHandlingMethodView):
1169
1168
  schema:
1170
1169
  type: array
1171
1170
  items:
1172
- description: "One did to list files."
1171
+ description: "One DID to list files."
1173
1172
  type: object
1174
1173
  required:
1175
1174
  - scope
1176
1175
  - name
1177
1176
  properties:
1178
1177
  scope:
1179
- description: "The did scope."
1178
+ description: "The DID scope."
1180
1179
  type: string
1181
1180
  name:
1182
- description: "The did name."
1181
+ description: "The DID name."
1183
1182
  type: string
1184
1183
  responses:
1185
1184
  201:
@@ -1194,25 +1193,25 @@ class BulkFiles(ErrorHandlingMethodView):
1194
1193
  type: object
1195
1194
  properties:
1196
1195
  parent_scope:
1197
- description: "The scope of the parent did."
1196
+ description: "The scope of the parent DID."
1198
1197
  type: string
1199
1198
  parent_name:
1200
- description: "The name of the parent did."
1199
+ description: "The name of the parent DID."
1201
1200
  type: string
1202
1201
  scope:
1203
- description: "The scope of the did."
1202
+ description: "The scope of the DID."
1204
1203
  type: string
1205
1204
  name:
1206
- description: "The name of the did."
1205
+ description: "The name of the DID."
1207
1206
  type: string
1208
1207
  bytes:
1209
- description: "The size of the did in bytes."
1208
+ description: "The size of the DID in bytes."
1210
1209
  type: integer
1211
1210
  guid:
1212
- description: "The guid of the did."
1211
+ description: "The guid of the DID."
1213
1212
  type: string
1214
1213
  events:
1215
- description: "The number of events of the did."
1214
+ description: "The number of events of the DID."
1216
1215
  type: integer
1217
1216
  adler32:
1218
1217
  description: "The adler32 checksum."
@@ -1240,13 +1239,13 @@ class Parents(ErrorHandlingMethodView):
1240
1239
  """
1241
1240
  ---
1242
1241
  summary: Get Parents
1243
- description: "Lists all parents of the did."
1242
+ description: "Lists all parents of the DID."
1244
1243
  tags:
1245
1244
  - Data Identifiers
1246
1245
  parameters:
1247
1246
  - name: scope_name
1248
1247
  in: path
1249
- description: "The scope and the name of the did."
1248
+ description: "The scope and the name of the DID."
1250
1249
  schema:
1251
1250
  type: string
1252
1251
  style: simple
@@ -1256,25 +1255,25 @@ class Parents(ErrorHandlingMethodView):
1256
1255
  content:
1257
1256
  application/x-json-stream:
1258
1257
  schema:
1259
- description: "The parents of the did."
1258
+ description: "The parents of the DID."
1260
1259
  type: array
1261
1260
  items:
1262
1261
  type: object
1263
- description: "A parent of the did."
1262
+ description: "A parent of the DID."
1264
1263
  properties:
1265
1264
  scope:
1266
- description: "The scope of the did."
1265
+ description: "The scope of the DID."
1267
1266
  type: string
1268
1267
  name:
1269
- description: "The name of the did."
1268
+ description: "The name of the DID."
1270
1269
  type: string
1271
1270
  type:
1272
- description: "The type of the did."
1271
+ description: "The type of the DID."
1273
1272
  type: string
1274
1273
  401:
1275
1274
  description: "Invalid Auth Token"
1276
1275
  404:
1277
- description: "Did not found"
1276
+ description: "DID not found"
1278
1277
  406:
1279
1278
  description: "Not acceptable"
1280
1279
  """
@@ -1295,172 +1294,304 @@ class Parents(ErrorHandlingMethodView):
1295
1294
  class Meta(ErrorHandlingMethodView):
1296
1295
 
1297
1296
  @check_accept_header_wrapper_flask(['application/json'])
1298
- def get(self, scope_name):
1297
+ def get(self, scope_name, key=None):
1299
1298
  """
1300
1299
  ---
1301
1300
  summary: Get metadata
1302
- description: "Get the metadata of a did."
1301
+ description: "Retrieve the metadata of a data identifier (DID)."
1303
1302
  tags:
1304
1303
  - Data Identifiers
1305
1304
  parameters:
1306
1305
  - name: scope_name
1307
1306
  in: path
1308
- description: "The scope and the name of the did."
1307
+ description: "The scope and the name of the DID (e.g., `scope:name`)."
1308
+ required: true
1309
+ style: simple
1309
1310
  schema:
1310
1311
  type: string
1311
- style: simple
1312
1312
  - name: plugin
1313
1313
  in: query
1314
- description: "The plugin to use."
1314
+ description: "The metadata plugin to use."
1315
+ required: false
1316
+ style: form
1315
1317
  schema:
1316
1318
  type: string
1317
1319
  default: DID_COLUMN
1318
1320
  responses:
1319
1321
  200:
1320
- description: "OK"
1322
+ description: "OK – returns the metadata of the DID."
1321
1323
  content:
1322
1324
  application/json:
1323
1325
  schema:
1324
- description: "A data identifier with all attributes."
1325
1326
  type: object
1327
+ description: "A JSON object containing all attributes of the DID."
1328
+ examples:
1329
+ defaultPlugin:
1330
+ summary: "Response produced by the default 'DID_COLUMN' plug-in"
1331
+ value:
1332
+ scope: "user"
1333
+ name: "dataset_123"
1334
+ did_type: "DATASET"
1335
+ bytes: 123456789
1336
+ length: 42
1337
+ account: "root"
1338
+ is_open: true
1339
+ suppressed: false
1340
+ created_at: "2025-05-20T12:16:58"
1341
+ updated_at: "2025-05-20T12:17:27"
1342
+ # ... rest DID fields
1343
+ jsonPlugin:
1344
+ summary: "Response produced by the 'JSON' plugin"
1345
+ value:
1346
+ custom_key1: "value1"
1347
+ custom_key2: "value2"
1348
+ # ... etc
1326
1349
  400:
1327
- description: "Bad Request - Invalid metadata plugin specified"
1350
+ description: "Bad Request invalid scope_name, or invalid metadata plugin specified."
1328
1351
  401:
1329
- description: "Invalid Auth Token"
1352
+ description: "Unauthorized – invalid Auth Token."
1330
1353
  404:
1331
- description: "Did not found"
1354
+ description: "Not found – the specified DID does not exist."
1355
+ 405:
1356
+ description: "Method Not Allowed – the 'key' parameter is not supported with GET."
1332
1357
  406:
1333
- description: "Not acceptable"
1358
+ description: "Not Acceptable – the requested format is not supported."
1334
1359
  """
1360
+ # Flask injects the `key` keyword argument here because the blueprint registers
1361
+ # the generic `/meta` endpoint with `defaults={'key': None}`. The GET endpoint is
1362
+ # intentionally *not* exposed as `/meta/<key>`—it always returns the complete
1363
+ # metadata record (optionally filtered by the `plugin` query parameter). Hence,
1364
+ # a non‑None `key` should never reach this method today. The following guard
1365
+ # defends against any future routing changes that might introduce
1366
+ # `/meta/<key>` for GET requests by explicitly rejecting such usage.
1367
+ if key is not None:
1368
+ return generate_http_error_flask(405,
1369
+ 'MethodNotAllowed',
1370
+ 'GET not allowing keys')
1371
+
1372
+ vo = request.environ['vo']
1335
1373
  try:
1336
- scope, name = parse_scope_name(scope_name, request.environ['vo'])
1374
+ scope, name = parse_scope_name(scope_name, vo)
1337
1375
  except ValueError as error:
1338
1376
  return generate_http_error_flask(400, error)
1339
1377
 
1378
+ plugin = request.args.get('plugin', default='DID_COLUMN')
1340
1379
  try:
1341
- plugin = request.args.get('plugin', default='DID_COLUMN')
1342
- meta = get_metadata(scope=scope, name=name, plugin=plugin, vo=request.environ['vo'])
1380
+ meta = get_metadata(scope=scope, name=name, plugin=plugin, vo=vo)
1343
1381
  return Response(render_json(**meta), content_type='application/json')
1344
1382
  except DataIdentifierNotFound as error:
1345
1383
  return generate_http_error_flask(404, error)
1346
1384
  except UnsupportedMetadataPlugin as error:
1347
1385
  return generate_http_error_flask(400, error)
1348
1386
 
1349
- def post(self, scope_name):
1387
+ def post(self, scope_name, key=None):
1350
1388
  """
1351
1389
  ---
1352
- summary: Add metadata
1353
- description: "Add metadata to a did."
1390
+ summary: Set or update metadata
1391
+ description: |
1392
+ Set metadata for a data identifier (DID). If a piece of metadata for a given key
1393
+ already exists, it will be handled according to the underlying metadata plugin
1394
+ in use. Certain plugins may disallow updating specific metadata keys.
1395
+
1396
+ - **Single-key mode** (key provided in the path):
1397
+ The request body must contain a `value` field (e.g., `{"value": "some_value"}`).
1398
+ - **Multi-key mode** (no key in the path):
1399
+ The request body must contain a `meta` field with the dictionary containing
1400
+ multiple key-value pairs (e.g. `{"meta": {"k1": "v1", "k2": "v2"}}`).
1401
+
1402
+ The optional `recursive` flag indicates whether the metadata should be applied
1403
+ recursively to child DIDs. Note that whether recursion is supported depends on
1404
+ the plugin configured for your system.
1354
1405
  tags:
1355
1406
  - Data Identifiers
1356
1407
  parameters:
1357
1408
  - name: scope_name
1358
1409
  in: path
1359
- description: "The scope and the name of the did."
1410
+ description: "The scope and the name of the DID (e.g., `scope:name`)."
1411
+ required: true
1412
+ style: simple
1360
1413
  schema:
1361
1414
  type: string
1415
+ - name: key
1416
+ in: path
1417
+ description: |
1418
+ The key parameter applies only to the `/meta/<key>` endpoint (**Single-key mode**)
1419
+ and defines which metadata key to set/update. If omitted (by calling just `/meta`
1420
+ without the extra path segment), it defaults to `None` and **Multi-key mode** is used.
1421
+ required: true
1362
1422
  style: simple
1423
+ schema:
1424
+ type: string
1363
1425
  requestBody:
1426
+ required: true
1364
1427
  content:
1365
- 'application/json':
1428
+ application/json:
1366
1429
  schema:
1367
- type: object
1368
- required:
1369
- - meta
1370
- properties:
1371
- meta:
1372
- description: "The metadata to add. A dictionary containing the metadata name as key and the value as value."
1373
- type: object
1374
- recursive:
1375
- description: "Flag if the metadata should be applied recirsively to children."
1376
- type: boolean
1377
- default: false
1430
+ oneOf:
1431
+ - type: object
1432
+ description: "Schema for **Single-key mode** (`key` included in path)."
1433
+ required:
1434
+ - value
1435
+ properties:
1436
+ value:
1437
+ description: "The metadata value to set for this key."
1438
+ type: string
1439
+ recursive:
1440
+ description: "Whether to apply the update recursively to child DIDs."
1441
+ type: boolean
1442
+ default: false
1443
+ - type: object
1444
+ description: "Schema for **Multi-key mode** (`key` not included in path)."
1445
+ required:
1446
+ - meta
1447
+ properties:
1448
+ meta:
1449
+ description: "A dictionary of multiple metadata keys and their values."
1450
+ type: object
1451
+ recursive:
1452
+ description: "Whether to apply the update recursively to child DIDs."
1453
+ type: boolean
1454
+ default: false
1455
+ examples:
1456
+ singleKeyMode:
1457
+ summary: "Setting a single metadata key"
1458
+ value:
1459
+ value: "my_metadata_value"
1460
+ recursive: false
1461
+ multiKeyMode:
1462
+ summary: "Setting multiple metadata keys at once"
1463
+ value:
1464
+ meta:
1465
+ experiment: "ATLAS"
1466
+ physics_group: "Higgs"
1467
+ data_type: "RAW"
1468
+ recursive: true
1378
1469
  responses:
1379
1470
  201:
1380
- description: "Created"
1471
+ description: "Created – metadata was successfully set (or updated)."
1381
1472
  content:
1382
- application/json:
1473
+ text/plain:
1383
1474
  schema:
1384
1475
  type: string
1385
1476
  enum: ["Created"]
1477
+ 400:
1478
+ description: "Bad Request – invalid scope_name, or invalid key/value parameters."
1386
1479
  401:
1387
- description: "Invalid Auth Token"
1480
+ description: "Unauthorized – invalid Auth Token."
1388
1481
  404:
1389
- description: "Not found"
1390
- 406:
1391
- description: "Not acceptable"
1482
+ description: "Not found – the specified DID does not exist."
1392
1483
  """
1484
+ vo = request.environ['vo']
1393
1485
  try:
1394
- scope, name = parse_scope_name(scope_name, request.environ['vo'])
1486
+ scope, name = parse_scope_name(scope_name, vo)
1395
1487
  except ValueError as error:
1396
1488
  return generate_http_error_flask(400, error)
1397
1489
 
1398
1490
  parameters = json_parameters()
1399
- meta = param_get(parameters, 'meta')
1400
1491
 
1401
- try:
1402
- set_metadata_bulk(
1403
- scope=scope,
1404
- name=name,
1405
- meta=meta,
1406
- issuer=request.environ['issuer'],
1407
- recursive=param_get(parameters, 'recursive', default=False),
1408
- vo=request.environ['vo'],
1409
- )
1410
- except DataIdentifierNotFound as error:
1411
- return generate_http_error_flask(404, error)
1412
- except Duplicate as error:
1413
- return generate_http_error_flask(409, error)
1414
- except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
1415
- return generate_http_error_flask(400, error)
1492
+ if key is not None:
1493
+ value = param_get(parameters, 'value')
1494
+ try:
1495
+ set_metadata(
1496
+ scope=scope,
1497
+ name=name,
1498
+ key=key,
1499
+ value=value,
1500
+ issuer=request.environ['issuer'],
1501
+ recursive=param_get(parameters, 'recursive', default=False),
1502
+ vo=vo
1503
+ )
1504
+ except DataIdentifierNotFound as error:
1505
+ return generate_http_error_flask(404, error)
1506
+ except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
1507
+ return generate_http_error_flask(400, error)
1508
+ return 'Created', 201
1416
1509
 
1417
- return "Created", 201
1510
+ else:
1511
+ meta = param_get(parameters, 'meta')
1512
+ try:
1513
+ set_metadata_bulk(
1514
+ scope=scope,
1515
+ name=name,
1516
+ meta=meta,
1517
+ issuer=request.environ['issuer'],
1518
+ recursive=param_get(parameters, 'recursive', default=False),
1519
+ vo=vo,
1520
+ )
1521
+ except DataIdentifierNotFound as error:
1522
+ return generate_http_error_flask(404, error)
1523
+ except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
1524
+ return generate_http_error_flask(400, error)
1525
+ return "Created", 201
1418
1526
 
1419
- def delete(self, scope_name):
1527
+ def delete(self, scope_name, key=None):
1420
1528
  """
1421
1529
  ---
1422
1530
  summary: Delete metadata
1423
- description: "Deletes the specified metadata from the did."
1531
+ description: |
1532
+ Delete a specific metadata key from a data identifier (DID).
1533
+ This `key` must be provided via the query parameter `?key=...`.
1424
1534
  tags:
1425
1535
  - Data Identifiers
1426
1536
  parameters:
1427
1537
  - name: scope_name
1428
1538
  in: path
1429
- description: "The scope and the name of the did."
1539
+ description: "The scope and the name of the DID (e.g., `scope:name`)."
1540
+ required: true
1541
+ style: simple
1430
1542
  schema:
1431
1543
  type: string
1432
- style: simple
1433
1544
  - name: key
1434
1545
  in: query
1435
- description: "The key to delete."
1546
+ description: "The metadata key to delete."
1547
+ required: true
1548
+ style: form
1436
1549
  schema:
1437
1550
  type: string
1438
1551
  responses:
1439
1552
  200:
1440
- description: "OK"
1553
+ description: "OK – the metadata key was successfully removed."
1554
+ content:
1555
+ text/plain:
1556
+ schema:
1557
+ type: string
1558
+ enum: [""]
1441
1559
  400:
1442
- description: "scope_name could not be parsed."
1560
+ description: "Bad Request invalid scope_name."
1443
1561
  401:
1444
- description: "Invalid Auth Token"
1562
+ description: "Unauthorized – invalid Auth Token."
1445
1563
  404:
1446
- description: "Did or key not found"
1447
- 406:
1448
- description: "Not acceptable"
1564
+ description: >
1565
+ Not found – the specified DID or `key` does not exist, or no `key` query
1566
+ parameter provided.
1567
+ 405:
1568
+ description: "Method Not Allowed – the 'key' parameter is not supported with DELETE."
1449
1569
  409:
1450
- description: "Feature is not in current database."
1570
+ description: "Conflict action not supported by the utilized metadata plugin."
1451
1571
  """
1572
+ # Flask injects the `key` keyword argument here because the blueprint registers the
1573
+ # generic `/meta` endpoint with `defaults={'key': None}`. For DELETE requests the
1574
+ # API currently expects any metadata key to be supplied via the **query string**
1575
+ # (e.g. `...?key=myfield`), so a non‑None `key` coming from the path is impossible
1576
+ # today. We still keep this guard as a defensive measure in case someone later
1577
+ # extends the routing to allow `/meta/<key>` for DELETE as well.
1578
+ if key is not None:
1579
+ return generate_http_error_flask(405,
1580
+ 'MethodNotAllowed',
1581
+ 'DELETE not allowing keys')
1582
+
1583
+ vo = request.environ['vo']
1452
1584
  try:
1453
- scope, name = parse_scope_name(scope_name, request.environ['vo'])
1585
+ scope, name = parse_scope_name(scope_name, vo)
1454
1586
  except ValueError as error:
1455
1587
  return generate_http_error_flask(400, error)
1456
1588
 
1457
- if 'key' in request.args:
1458
- key = request.args['key']
1459
- else:
1589
+ if 'key' not in request.args:
1460
1590
  return generate_http_error_flask(404, KeyNotFound.__name__, 'No key provided to remove')
1461
1591
 
1592
+ delete_key = request.args['key']
1462
1593
  try:
1463
- delete_metadata(scope=scope, name=name, key=key, vo=request.environ['vo'])
1594
+ delete_metadata(scope=scope, name=name, key=delete_key, vo=vo)
1464
1595
  except (KeyNotFound, DataIdentifierNotFound) as error:
1465
1596
  return generate_http_error_flask(404, error)
1466
1597
  except NotImplementedError as error:
@@ -1469,85 +1600,6 @@ class Meta(ErrorHandlingMethodView):
1469
1600
  return '', 200
1470
1601
 
1471
1602
 
1472
- class SingleMeta(ErrorHandlingMethodView):
1473
- def post(self, scope_name, key):
1474
- """
1475
- ---
1476
- summary: Add metadata
1477
- description: "Add metadata to a did."
1478
- tags:
1479
- - Data Identifiers
1480
- parameters:
1481
- - name: scope_name
1482
- in: path
1483
- description: "The scope and the name of the did."
1484
- schema:
1485
- type: string
1486
- style: simple
1487
- - name: key
1488
- in: path
1489
- description: "The key for the metadata."
1490
- schema:
1491
- type: string
1492
- style: simple
1493
- requestBody:
1494
- content:
1495
- 'application/json':
1496
- schema:
1497
- type: object
1498
- required:
1499
- - value
1500
- properties:
1501
- value:
1502
- description: "The value to set."
1503
- type: object
1504
- responses:
1505
- 201:
1506
- description: "Created"
1507
- content:
1508
- application/json:
1509
- schema:
1510
- type: string
1511
- enum: ["Created"]
1512
- 401:
1513
- description: "Invalid Auth Token"
1514
- 404:
1515
- description: "Did not found"
1516
- 406:
1517
- description: "Not acceptable"
1518
- 409:
1519
- description: "Metadata already exists"
1520
- 400:
1521
- description: "Invalid key or value"
1522
- """
1523
- try:
1524
- scope, name = parse_scope_name(scope_name, request.environ['vo'])
1525
- except ValueError as error:
1526
- return generate_http_error_flask(400, error)
1527
-
1528
- parameters = json_parameters()
1529
- value = param_get(parameters, 'value')
1530
-
1531
- try:
1532
- set_metadata(
1533
- scope=scope,
1534
- name=name,
1535
- key=key,
1536
- value=value,
1537
- issuer=request.environ['issuer'],
1538
- recursive=param_get(parameters, 'recursive', default=False),
1539
- vo=request.environ['vo'],
1540
- )
1541
- except DataIdentifierNotFound as error:
1542
- return generate_http_error_flask(404, error)
1543
- except Duplicate as error:
1544
- return generate_http_error_flask(409, error)
1545
- except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
1546
- return generate_http_error_flask(400, error)
1547
-
1548
- return 'Created', 201
1549
-
1550
-
1551
1603
  class BulkDIDsMeta(ErrorHandlingMethodView):
1552
1604
 
1553
1605
  def post(self):
@@ -1566,17 +1618,17 @@ class BulkDIDsMeta(ErrorHandlingMethodView):
1566
1618
  - dids
1567
1619
  properties:
1568
1620
  dids:
1569
- description: "A list with all the dids and the metadata."
1621
+ description: "A list with all the DIDs and the metadata."
1570
1622
  type: array
1571
1623
  items:
1572
- description: "The did and associated metadata."
1624
+ description: "The DID and associated metadata."
1573
1625
  type: object
1574
1626
  properties:
1575
1627
  scope:
1576
- description: "The scope of the did."
1628
+ description: "The scope of the DID."
1577
1629
  type: string
1578
1630
  name:
1579
- description: "The name of the did."
1631
+ description: "The name of the DID."
1580
1632
  type: string
1581
1633
  meta:
1582
1634
  description: "The metadata to add. A dictionary with the meta key as key and the value as value."
@@ -1592,7 +1644,7 @@ class BulkDIDsMeta(ErrorHandlingMethodView):
1592
1644
  401:
1593
1645
  description: "Invalid Auth Token"
1594
1646
  404:
1595
- description: "Did not found"
1647
+ description: "DID not found"
1596
1648
  406:
1597
1649
  description: "Not acceptable"
1598
1650
  409:
@@ -1620,23 +1672,23 @@ class Rules(ErrorHandlingMethodView):
1620
1672
  """
1621
1673
  ---
1622
1674
  summary: Get rules
1623
- description: "Lists all rules of a given did."
1675
+ description: "Lists all rules of a given DID."
1624
1676
  tags:
1625
1677
  - Data Identifiers
1626
1678
  parameters:
1627
1679
  - name: scope_name
1628
1680
  in: path
1629
- description: "The scope and the name of the did."
1681
+ description: "The scope and the name of the DID."
1630
1682
  schema:
1631
1683
  type: string
1632
1684
  style: simple
1633
1685
  responses:
1634
1686
  200:
1635
- description: "The rules associated with a did."
1687
+ description: "The rules associated with a DID."
1636
1688
  content:
1637
1689
  application/x-json-stream:
1638
1690
  schema:
1639
- description: "The rules associated with a did."
1691
+ description: "The rules associated with a DID."
1640
1692
  type: array
1641
1693
  items:
1642
1694
  description: "A rule."
@@ -1644,7 +1696,7 @@ class Rules(ErrorHandlingMethodView):
1644
1696
  401:
1645
1697
  description: "Invalid Auth Token"
1646
1698
  404:
1647
- description: "Did or rule not found"
1699
+ description: "DID or rule not found"
1648
1700
  406:
1649
1701
  description: "Not acceptable"
1650
1702
  """
@@ -1684,24 +1736,24 @@ class BulkMeta(ErrorHandlingMethodView):
1684
1736
  - dids
1685
1737
  properties:
1686
1738
  dids:
1687
- description: "The dids."
1739
+ description: "The DIDs."
1688
1740
  type: array
1689
1741
  items:
1690
- description: "A did."
1742
+ description: "A DID."
1691
1743
  type: object
1692
1744
  properties:
1693
1745
  name:
1694
- description: "The name of the did."
1746
+ description: "The name of the DID."
1695
1747
  type: string
1696
1748
  scope:
1697
- description: "The scope of the did."
1749
+ description: "The scope of the DID."
1698
1750
  type: string
1699
1751
  inherit:
1700
1752
  description: "Concatenated the metadata of the parent if set to true."
1701
1753
  type: boolean
1702
1754
  default: false
1703
1755
  plugin:
1704
- description: "The did meta plugin to query or 'ALL' for all available plugins"
1756
+ description: "The DID meta plugin to query or 'ALL' for all available plugins"
1705
1757
  type: string
1706
1758
  default: "JSON"
1707
1759
  responses:
@@ -1710,17 +1762,17 @@ class BulkMeta(ErrorHandlingMethodView):
1710
1762
  content:
1711
1763
  application/json:
1712
1764
  schema:
1713
- description: "A list of metadata identifiers for the dids. Separated by new lines."
1765
+ description: "A list of metadata identifiers for the DIDs. Separated by new lines."
1714
1766
  type: array
1715
1767
  items:
1716
- description: "The metadata for one did."
1768
+ description: "The metadata for one DID."
1717
1769
  type: object
1718
1770
  400:
1719
1771
  description: "Cannot decode json parameter list"
1720
1772
  401:
1721
1773
  description: "Invalid Auth Token"
1722
1774
  404:
1723
- description: "Did not found"
1775
+ description: "DID not found"
1724
1776
  406:
1725
1777
  description: "Not acceptable"
1726
1778
  """
@@ -1754,7 +1806,7 @@ class AssociatedRules(ErrorHandlingMethodView):
1754
1806
  parameters:
1755
1807
  - name: scope_name
1756
1808
  in: path
1757
- description: "The scope and the name of the did."
1809
+ description: "The scope and the name of the DID."
1758
1810
  schema:
1759
1811
  type: string
1760
1812
  style: simple
@@ -1794,7 +1846,7 @@ class AssociatedRules(ErrorHandlingMethodView):
1794
1846
  401:
1795
1847
  description: "Invalid Auth Token"
1796
1848
  404:
1797
- description: "Did not found"
1849
+ description: "DID not found"
1798
1850
  406:
1799
1851
  description: "Not acceptable"
1800
1852
  """
@@ -1850,7 +1902,7 @@ class GUIDLookup(ErrorHandlingMethodView):
1850
1902
  401:
1851
1903
  description: "Invalid Auth Token"
1852
1904
  404:
1853
- description: "Did not found"
1905
+ description: "DID not found"
1854
1906
  406:
1855
1907
  description: "Not acceptable"
1856
1908
  """
@@ -2029,7 +2081,7 @@ class NewDIDs(ErrorHandlingMethodView):
2029
2081
  parameters:
2030
2082
  - name: type
2031
2083
  in: query
2032
- description: "The type of the did."
2084
+ description: "The type of the DID."
2033
2085
  schema:
2034
2086
  type: string
2035
2087
  required: false
@@ -2039,20 +2091,20 @@ class NewDIDs(ErrorHandlingMethodView):
2039
2091
  content:
2040
2092
  application/x-json-stream:
2041
2093
  schema:
2042
- description: "A list of the recent dids. Items are separated by new line characters."
2094
+ description: "A list of the recent DIDs. Items are separated by new line characters."
2043
2095
  type: array
2044
2096
  items:
2045
- description: "A did."
2097
+ description: "A DID."
2046
2098
  type: object
2047
2099
  properties:
2048
2100
  scope:
2049
- description: "The scope of the did."
2101
+ description: "The scope of the DID."
2050
2102
  type: string
2051
2103
  name:
2052
- description: "The name of the did."
2104
+ description: "The name of the DID."
2053
2105
  type: string
2054
2106
  did_type:
2055
- description: "The type of the did."
2107
+ description: "The type of the DID."
2056
2108
  type: string
2057
2109
  401:
2058
2110
  description: "Invalid Auth Token"
@@ -2073,25 +2125,25 @@ class Resurrect(ErrorHandlingMethodView):
2073
2125
  def post(self):
2074
2126
  """
2075
2127
  ---
2076
- summary: Resurrect dids
2077
- description: "Resurrect all given dids."
2128
+ summary: Resurrect DIDs
2129
+ description: "Resurrect all given DIDs."
2078
2130
  tags:
2079
2131
  - Data Identifiers
2080
2132
  requestBody:
2081
2133
  content:
2082
2134
  'application/json':
2083
2135
  schema:
2084
- description: "List of did to resurrect."
2136
+ description: "List of DIDs to resurrect."
2085
2137
  type: array
2086
2138
  items:
2087
- description: "A did to resurrect."
2139
+ description: "A DID to resurrect."
2088
2140
  type: object
2089
2141
  properties:
2090
2142
  scope:
2091
- description: "The scope of the did."
2143
+ description: "The scope of the DID."
2092
2144
  type: string
2093
2145
  name:
2094
- description: "The name of the did"
2146
+ description: "The name of the DID"
2095
2147
  type: string
2096
2148
  responses:
2097
2149
  201:
@@ -2130,13 +2182,13 @@ class Follow(ErrorHandlingMethodView):
2130
2182
  """
2131
2183
  ---
2132
2184
  summary: Get followers
2133
- description: "Get all followers for a specific did."
2185
+ description: "Get all followers for a specific DID."
2134
2186
  tags:
2135
2187
  - Data Identifiers
2136
2188
  parameters:
2137
2189
  - name: scope_name
2138
2190
  in: path
2139
- description: "The scope and the name of the did."
2191
+ description: "The scope and the name of the DID."
2140
2192
  schema:
2141
2193
  type: string
2142
2194
  style: simple
@@ -2146,21 +2198,21 @@ class Follow(ErrorHandlingMethodView):
2146
2198
  content:
2147
2199
  application/json:
2148
2200
  schema:
2149
- description: "A list of all followers of a did."
2201
+ description: "A list of all followers of a DID."
2150
2202
  type: array
2151
2203
  items:
2152
- description: "A follower of a did."
2204
+ description: "A follower of a DID."
2153
2205
  type: object
2154
2206
  properties:
2155
2207
  user:
2156
- description: "The user which follows the did."
2208
+ description: "The user which follows the DID."
2157
2209
  type: string
2158
2210
  400:
2159
2211
  description: "Value error"
2160
2212
  401:
2161
2213
  description: "Invalid Auth Token"
2162
2214
  404:
2163
- description: "Did not found"
2215
+ description: "DID not found"
2164
2216
  406:
2165
2217
  description: "Not acceptable"
2166
2218
  """
@@ -2187,7 +2239,7 @@ class Follow(ErrorHandlingMethodView):
2187
2239
  parameters:
2188
2240
  - name: scope_name
2189
2241
  in: path
2190
- description: "The scope and the name of the did."
2242
+ description: "The scope and the name of the DID."
2191
2243
  schema:
2192
2244
  type: string
2193
2245
  style: simple
@@ -2200,7 +2252,7 @@ class Follow(ErrorHandlingMethodView):
2200
2252
  - account
2201
2253
  properties:
2202
2254
  account:
2203
- description: "The account to follow the did."
2255
+ description: "The account to follow the DID."
2204
2256
  type: string
2205
2257
  responses:
2206
2258
  201:
@@ -2239,7 +2291,7 @@ class Follow(ErrorHandlingMethodView):
2239
2291
  parameters:
2240
2292
  - name: scope_name
2241
2293
  in: path
2242
- description: "The scope and the name of the did."
2294
+ description: "The scope and the name of the DID."
2243
2295
  schema:
2244
2296
  type: string
2245
2297
  style: simple
@@ -2252,7 +2304,7 @@ class Follow(ErrorHandlingMethodView):
2252
2304
  - account
2253
2305
  properties:
2254
2306
  account:
2255
- description: "The account to unfollow the did."
2307
+ description: "The account to unfollow the DID."
2256
2308
  type: string
2257
2309
  responses:
2258
2310
  200:
@@ -2298,9 +2350,8 @@ def blueprint():
2298
2350
  attachment_view = Attachment.as_view('attachment')
2299
2351
  bp.add_url_rule('/<path:scope_name>/dids', view_func=attachment_view, methods=['get', 'post', 'delete'])
2300
2352
  meta_view = Meta.as_view('meta')
2301
- bp.add_url_rule('/<path:scope_name>/meta', view_func=meta_view, methods=['get', 'post', 'delete'])
2302
- singlemeta_view = SingleMeta.as_view('singlemeta')
2303
- bp.add_url_rule('/<path:scope_name>/meta/<key>', view_func=singlemeta_view, methods=['post', ])
2353
+ bp.add_url_rule('/<path:scope_name>/meta', defaults={'key': None}, view_func=meta_view, methods=['get', 'post', 'delete'])
2354
+ bp.add_url_rule('/<path:scope_name>/meta/<key>', view_func=meta_view, methods=['post', ])
2304
2355
  bulkdidsmeta_view = BulkDIDsMeta.as_view('bulkdidsmeta')
2305
2356
  bp.add_url_rule('/bulkdidsmeta', view_func=bulkdidsmeta_view, methods=['post', ])
2306
2357
  rules_view = Rules.as_view('rules')