invenio-app-rdm 14.0.0b2.dev1__py2.py3-none-any.whl → 14.0.0b2.dev3__py2.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.
Files changed (18) hide show
  1. invenio_app_rdm/__init__.py +1 -1
  2. invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/deposit.html +3 -0
  3. invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/detail.html +5 -2
  4. invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/creatibutors.html +1 -1
  5. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js +7 -1
  6. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/CreateAccessLink.js +15 -2
  7. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksSearchResultContainer.js +21 -1
  8. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksTab.js +3 -1
  9. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessRequests/AccessRequestsTab.js +11 -2
  10. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/ShareModal.js +14 -0
  11. invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/AccessRequestExpiration.js +8 -3
  12. invenio_app_rdm/upgrade_scripts/migrate_13_0_to_14_0.py +133 -54
  13. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/METADATA +10 -1
  14. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/RECORD +18 -18
  15. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/WHEEL +0 -0
  16. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/entry_points.txt +0 -0
  17. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/licenses/LICENSE +0 -0
  18. {invenio_app_rdm-14.0.0b2.dev1.dist-info → invenio_app_rdm-14.0.0b2.dev3.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,6 @@
17
17
  #
18
18
  # See PEP 0440 for details - https://www.python.org/dev/peps/pep-0440
19
19
 
20
- __version__ = "14.0.0b2.dev1"
20
+ __version__ = "14.0.0b2.dev3"
21
21
 
22
22
  __all__ = ("__version__",)
@@ -69,6 +69,9 @@
69
69
  value='{{ permissions | tojson }}'>
70
70
  {%- endif %}
71
71
 
72
+ <input type="hidden" id="deposits-share-btn-require-link-expiration"
73
+ data-share-btn-require-link-expiration='{{ config.RDM_RECORDS_REQUIRE_SECRET_LINKS_EXPIRATION | tojson }}'>
74
+
72
75
  <div id="deposit-form"></div>
73
76
 
74
77
  {%- endblock page_body %}
@@ -48,6 +48,9 @@
48
48
 
49
49
 
50
50
  {%- block page_body %}
51
+ <span id="detail-share-btn-require-link-expiration"
52
+ data-share-btn-require-link-expiration='{{ config.RDM_RECORDS_REQUIRE_SECRET_LINKS_EXPIRATION | tojson }}'>
53
+
51
54
  <section id="banners" class="banners" aria-label="{{ _('Information banner') }}">
52
55
  <!-- COMMUNITY HEADER: hide it when displaying the submission request -->
53
56
  {% if not is_preview_submission_request %}
@@ -262,13 +265,13 @@
262
265
  {# Title #}
263
266
  {%- block record_title -%}
264
267
  <section id="record-title-section"
265
- aria-label="{{ _('Record title and creators') }}">
268
+ aria-label="{{ _('Record title, authors and contributors') }}">
266
269
  <h1 id="record-title"
267
270
  class="wrap-overflowing-text">{{ metadata.title }}</h1>
268
271
 
269
272
  {% if record_ui["ui"]["creators"] or record_ui["ui"]["contributors"] %}
270
273
  <section id="creatibutors"
271
- aria-label="{{ _('Creators and contributors') }}">
274
+ aria-label="{{ _('Authors and contributors') }}">
272
275
  {%- include "invenio_app_rdm/records/details/creatibutors.html" %}
273
276
  </section>
274
277
  {% endif %}
@@ -13,7 +13,7 @@
13
13
  {% if record_ui["ui"]["creators"] and record_ui["ui"]["creators"]["creators"] %}
14
14
  <div class="row ui accordion affiliations">
15
15
  <div class="sixteen wide mobile twelve wide tablet thirteen wide computer column">
16
- <h3 class="sr-only">{{ _('Creators') }}</h3>
16
+ <h3 class="sr-only">{{ _('Authors/Creators') }}</h3>
17
17
  <ul class="creatibutors">
18
18
  {{ show_creatibutors(record_ui["ui"]["creators"]["creators"], show_affiliations=True, show_role=True) }}
19
19
  </ul>
@@ -303,8 +303,11 @@ export class RDMDepositForm extends Component {
303
303
  fieldPath="metadata.creators"
304
304
  >
305
305
  <CreatibutorsField
306
- label={i18next.t("Creators")}
306
+ label={i18next.t("Authors/Creators")}
307
307
  labelIcon="user"
308
+ addButtonHelpText={i18next.t(
309
+ "Use the Authors/Creators field for names that should appear in the citation. Use the Contributors field below for other names."
310
+ )}
308
311
  fieldPath="metadata.creators"
309
312
  roleOptions={this.vocabularies.metadata.creators.role}
310
313
  schema="creators"
@@ -423,6 +426,9 @@ export class RDMDepositForm extends Component {
423
426
  >
424
427
  <CreatibutorsField
425
428
  addButtonLabel={i18next.t("Add contributor")}
429
+ addButtonHelpText={i18next.t(
430
+ "Contributors are not included in the citation, but are shown on the record page."
431
+ )}
426
432
  label={i18next.t("Contributors")}
427
433
  labelIcon="user plus"
428
434
  fieldPath="metadata.contributors"
@@ -25,7 +25,17 @@ export class CreateAccessLink extends Component {
25
25
 
26
26
  render() {
27
27
  const { permission, expiresAt, description } = this.state;
28
- const { handleCreation, loading, dropdownOptions } = this.props;
28
+ const {
29
+ hasLinkExpirationError,
30
+ handleCreation,
31
+ loading,
32
+ dropdownOptions,
33
+ isAccessLinksExpirationRequired,
34
+ } = this.props;
35
+ const linkExpirationDateHelptext =
36
+ isAccessLinksExpirationRequired === true
37
+ ? i18next.t("Expiration date: YYYY-MM-DD (required).")
38
+ : i18next.t("Expiration date: YYYY-MM-DD or never if blank (optional).");
29
39
  return (
30
40
  <Table.Row>
31
41
  <Table.Cell width={16}>
@@ -45,6 +55,7 @@ export class CreateAccessLink extends Component {
45
55
  </Grid.Column>
46
56
  <Grid.Column width={4}>
47
57
  <Input
58
+ className={`${hasLinkExpirationError ? "error" : ""}`}
48
59
  id="access-request-expires-at"
49
60
  onChange={(e, data) => {
50
61
  this.setState({ expiresAt: data.value });
@@ -56,7 +67,7 @@ export class CreateAccessLink extends Component {
56
67
  htmlFor="access-request-expires-at"
57
68
  className="helptext mb-0 mt-10"
58
69
  >
59
- {i18next.t("Expiration date: YYYY-MM-DD or never if blank (optional).")}
70
+ {linkExpirationDateHelptext}
60
71
  </label>
61
72
  </Grid.Column>
62
73
  <Grid.Column width={4}>
@@ -95,4 +106,6 @@ CreateAccessLink.propTypes = {
95
106
  loading: PropTypes.bool.isRequired,
96
107
  dropdownOptions: PropTypes.array.isRequired,
97
108
  record: PropTypes.object.isRequired,
109
+ hasLinkExpirationError: PropTypes.bool.isRequired,
110
+ isAccessLinksExpirationRequired: PropTypes.bool.isRequired,
98
111
  };
@@ -140,9 +140,26 @@ export class LinksSearchResultContainer extends Component {
140
140
  return options;
141
141
  };
142
142
 
143
+ checkIfLinkExpirationError = (error) => {
144
+ const response = error?.response;
145
+ const data = response?.data;
146
+ const errors = data?.errors;
147
+ const hasExpirationError = errors?.some(
148
+ (errorObject) => errorObject?.field === "expires_at"
149
+ );
150
+ return hasExpirationError;
151
+ };
152
+
143
153
  render() {
144
- const { results, record, onItemAddedOrDeleted, onPermissionChanged } = this.props;
154
+ const {
155
+ results,
156
+ record,
157
+ onItemAddedOrDeleted,
158
+ onPermissionChanged,
159
+ isAccessLinksExpirationRequired,
160
+ } = this.props;
145
161
  const { loading, error } = this.state;
162
+ const hasLinkExpirationDateError = this.checkIfLinkExpirationError(error);
146
163
  return (
147
164
  <>
148
165
  {error && this.errorMessage()}
@@ -197,10 +214,12 @@ export class LinksSearchResultContainer extends Component {
197
214
 
198
215
  <Table color="green">
199
216
  <CreateAccessLink
217
+ hasLinkExpirationError={hasLinkExpirationDateError}
200
218
  handleCreation={this.handleCreation}
201
219
  loading={loading}
202
220
  record={record}
203
221
  dropdownOptions={this.generateDropdownOptions()}
222
+ isAccessLinksExpirationRequired={isAccessLinksExpirationRequired}
204
223
  />
205
224
  </Table>
206
225
  </>
@@ -213,4 +232,5 @@ LinksSearchResultContainer.propTypes = {
213
232
  record: PropTypes.object.isRequired,
214
233
  onItemAddedOrDeleted: PropTypes.func.isRequired,
215
234
  onPermissionChanged: PropTypes.func.isRequired,
235
+ isAccessLinksExpirationRequired: PropTypes.bool.isRequired,
216
236
  };
@@ -68,7 +68,7 @@ export class LinksTab extends Component {
68
68
  };
69
69
 
70
70
  render() {
71
- const { record, results } = this.props;
71
+ const { record, results, isAccessLinksExpirationRequired } = this.props;
72
72
  const { loading, error } = this.state;
73
73
  return (
74
74
  <>
@@ -89,6 +89,7 @@ export class LinksTab extends Component {
89
89
  record={record}
90
90
  onItemAddedOrDeleted={this.onLinksAddedOrDeleted}
91
91
  onPermissionChanged={this.onPermissionChanged}
92
+ isAccessLinksExpirationRequired={isAccessLinksExpirationRequired}
92
93
  />
93
94
  )}
94
95
  </Modal.Content>
@@ -101,4 +102,5 @@ LinksTab.propTypes = {
101
102
  record: PropTypes.string.isRequired,
102
103
  results: PropTypes.array.isRequired,
103
104
  updateLinksState: PropTypes.func.isRequired,
105
+ isAccessLinksExpirationRequired: PropTypes.bool.isRequired,
104
106
  };
@@ -72,19 +72,24 @@ export class AccessRequestsTab extends Component {
72
72
  };
73
73
 
74
74
  initFormValues = () => {
75
- const { record } = this.props;
75
+ const { record, isAccessLinksExpirationRequired } = this.props;
76
76
 
77
77
  const settings = record.parent.access.settings;
78
78
 
79
79
  if (!_has(settings, "secret_link_expiration")) {
80
80
  settings["secret_link_expiration"] = 0;
81
+ } else if (
82
+ settings["secret_link_expiration"] === 0 &&
83
+ isAccessLinksExpirationRequired
84
+ ) {
85
+ settings["secret_link_expiration"] = 30;
81
86
  }
82
87
  return { ...settings };
83
88
  };
84
89
 
85
90
  render() {
86
91
  const { loading, error, actionSuccess } = this.state;
87
- const { handleClose } = this.props;
92
+ const { handleClose, isAccessLinksExpirationRequired } = this.props;
88
93
  return (
89
94
  <Formik
90
95
  onSubmit={this.handleSubmit}
@@ -175,6 +180,9 @@ export class AccessRequestsTab extends Component {
175
180
  <AccessRequestExpirationSelect
176
181
  inline
177
182
  value={values.secret_link_expiration}
183
+ isAccessLinksExpirationRequired={
184
+ isAccessLinksExpirationRequired
185
+ }
178
186
  />
179
187
  </Form.Field>
180
188
  </Grid.Column>
@@ -227,4 +235,5 @@ AccessRequestsTab.propTypes = {
227
235
  record: PropTypes.string.isRequired,
228
236
  successCallback: PropTypes.func.isRequired,
229
237
  handleClose: PropTypes.func.isRequired,
238
+ isAccessLinksExpirationRequired: PropTypes.bool.isRequired,
230
239
  };
@@ -85,9 +85,21 @@ export class ShareModal extends Component {
85
85
  this.setState({ record: updatedRecord });
86
86
  };
87
87
 
88
+ checkIfIsAccessLinksExpirationRequired = () => {
89
+ return (
90
+ document.getElementById("deposits-share-btn-require-link-expiration")?.dataset
91
+ ?.shareBtnRequireLinkExpiration === "true" ||
92
+ document.getElementById("detail-share-btn-require-link-expiration")?.dataset
93
+ ?.shareBtnRequireLinkExpiration === "true" ||
94
+ false
95
+ );
96
+ };
97
+
88
98
  panes = (record, permissions) => {
89
99
  const { handleClose, groupsEnabled } = this.props;
90
100
  const { linksResults, groupsResults, usersResults } = this.state;
101
+ const isAccessLinksExpirationRequired =
102
+ this.checkIfIsAccessLinksExpirationRequired();
91
103
 
92
104
  let numUsers = 0;
93
105
  let numGroups = 0;
@@ -161,6 +173,7 @@ export class ShareModal extends Component {
161
173
  results={linksResults}
162
174
  record={record}
163
175
  updateLinksState={this.updateLinksState}
176
+ isAccessLinksExpirationRequired={isAccessLinksExpirationRequired}
164
177
  />
165
178
  </Tab.Pane>
166
179
  ),
@@ -178,6 +191,7 @@ export class ShareModal extends Component {
178
191
  record={record}
179
192
  handleClose={handleClose}
180
193
  successCallback={this.handleRecordUpdate}
194
+ isAccessLinksExpirationRequired={isAccessLinksExpirationRequired}
181
195
  />
182
196
  </Tab.Pane>
183
197
  ),
@@ -6,8 +6,10 @@ import { SelectField } from "react-invenio-forms";
6
6
  export class AccessRequestExpirationSelect extends Component {
7
7
  constructor(props) {
8
8
  super(props);
9
- const { expirationOptions } = props;
10
- this.expirationOptions = expirationOptions;
9
+ const { expirationOptions, isAccessLinksExpirationRequired } = props;
10
+ this.expirationOptions = isAccessLinksExpirationRequired
11
+ ? expirationOptions.filter((option) => option.value !== "0")
12
+ : expirationOptions;
11
13
  }
12
14
 
13
15
  handleOnChange = ({ data, formikProps }) => {
@@ -16,7 +18,9 @@ export class AccessRequestExpirationSelect extends Component {
16
18
 
17
19
  render() {
18
20
  const { inline, expirationOptions, value } = this.props;
19
- const expirationSetting = value ? value.toString() : expirationOptions[0].value;
21
+ const expirationSetting = value
22
+ ? value.toString()
23
+ : this.expirationOptions[0].value;
20
24
  return (
21
25
  <SelectField
22
26
  label={i18next.t("Link expiration")}
@@ -41,6 +45,7 @@ AccessRequestExpirationSelect.propTypes = {
41
45
  ),
42
46
  inline: PropTypes.bool,
43
47
  value: PropTypes.string,
48
+ isAccessLinksExpirationRequired: PropTypes.bool.isRequired,
44
49
  };
45
50
 
46
51
  AccessRequestExpirationSelect.defaultProps = {
@@ -20,68 +20,91 @@ This script has been tested for the following scenarios:
20
20
  4. Records with multiple versions
21
21
  """
22
22
 
23
- import time
24
-
25
23
  from click import secho
26
24
  from invenio_access.permissions import system_identity
27
25
  from invenio_db import db
28
26
  from invenio_drafts_resources.resources.records.errors import DraftNotCreatedError
29
27
  from invenio_rdm_records.proxies import current_rdm_records_service as records_service
30
- from invenio_search.engine import dsl
28
+ from invenio_rdm_records.records.api import RDMDraft, RDMRecord
29
+ from invenio_search.api import RecordsSearchV2
31
30
 
32
31
 
33
- def run_upgrade(has, migrate_record, migrate_draft):
32
+ def run_upgrade(migrate_record, migrate_draft):
34
33
  """Run upgrade on selected records and drafts.
35
34
 
36
35
  Args:
37
- has (dsl.Q): Query filter to select records/drafts to update.
38
36
  migrate_record (callable): Function to migrate a record.
39
37
  migrate_draft (callable): Function to migrate a draft.
40
38
  """
39
+ errored_record_ids = []
40
+ errored_draft_ids = []
41
+
41
42
  # Handle published records
42
- published_records = records_service.scan(
43
- identity=system_identity,
44
- params={"allversions": True},
45
- extra_filter=has,
46
- )
47
- for result in published_records.hits:
43
+ published_records = (
44
+ RecordsSearchV2(index=records_service.record_cls.index._name)
45
+ .filter("term", deletion_status="P")
46
+ .filter(
47
+ "query_string",
48
+ query="metadata.resource_type.id:publication-thesis OR metadata.related_identifiers.resource_type.id:publication-thesis",
49
+ )
50
+ .source(["id"])
51
+ .scan()
52
+ ) # Only need to fetch the record IDs to make the query faster
53
+ # Convert the search results to a list to avoid keeping the scroll context open, as it errors out after 15 minutes
54
+ published_record_ids = [result["id"] for result in published_records]
55
+ for record_id in published_record_ids:
48
56
  try:
49
- migrate_record(result)
57
+ migrate_record(record_id)
50
58
  except Exception as error:
51
59
  secho(f"> Error {repr(error)}", fg="red")
52
- error = f"Record {result['id']} failed to update"
60
+ secho(f"Record {record_id} failed to update", fg="red")
61
+ errored_record_ids.append((record_id, error))
53
62
 
54
63
  # Handle draft records
55
- draft_records = records_service._search(
56
- identity=system_identity,
57
- action="scan",
58
- params={"allversions": True},
59
- search_preference=None,
60
- record_cls=records_service.draft_cls,
61
- search_opts=records_service.config.search_drafts,
62
- extra_filter=has,
63
- permission_action="read_draft",
64
- ).scan()
65
- for result in draft_records:
64
+ draft_records = (
65
+ RecordsSearchV2(index=records_service.draft_cls.index._name)
66
+ .filter("term", has_draft=False)
67
+ .filter(
68
+ "query_string",
69
+ query="metadata.resource_type.id:publication-thesis OR metadata.related_identifiers.resource_type.id:publication-thesis",
70
+ )
71
+ .source(["id"])
72
+ .scan()
73
+ )
74
+ # Convert the search results to a list to avoid keeping the scroll context open, as it errors out after 15 minutes
75
+ draft_record_ids = [result["id"] for result in draft_records]
76
+ for draft_id in draft_record_ids:
66
77
  try:
67
- migrate_draft(result)
78
+ migrate_draft(draft_id)
68
79
  except Exception as error:
69
80
  secho(f"> Error {repr(error)}", fg="red")
70
- error = f"Draft {result['id']} failed to update"
81
+ secho(f"Draft {draft_id} failed to update", fg="red")
82
+ errored_draft_ids.append((draft_id, error))
83
+
84
+ print(f"Errored record IDs:", *errored_record_ids, sep="\n")
85
+ print(f"Errored draft IDs:", *errored_draft_ids, sep="\n")
71
86
 
72
87
 
73
88
  def run_update_for_resource_type():
74
89
  """Run update for resource type."""
75
90
 
76
- def migrate_resource_type_in_record(hit_result):
91
+ def migrate_resource_type_in_record(record_id):
77
92
  """
78
93
  Update resource type from publication-thesis to publication-dissertation.
79
94
 
80
95
  We go through the service layer to automatically trigger the DOI update and re-indexing.
81
96
  """
82
- secho(f"Updating resource type for record {hit_result['id']}", fg="yellow")
83
- record = records_service.read(system_identity, hit_result["id"])
84
- if record.data["metadata"]["resource_type"]["id"] != "publication-thesis":
97
+ secho(f"Updating resource type for record {record_id}", fg="yellow")
98
+ record = records_service.read(system_identity, record_id)
99
+ if record.data["metadata"]["resource_type"][
100
+ "id"
101
+ ] != "publication-thesis" and not any(
102
+ related_identifier.get("resource_type", {}).get("id")
103
+ == "publication-thesis"
104
+ for related_identifier in record.data["metadata"].get(
105
+ "related_identifiers", []
106
+ )
107
+ ):
85
108
  secho(
86
109
  f"Skipping record <{record.id}> because it doesn't have resource-type 'publication-thesis'!",
87
110
  fg="yellow",
@@ -97,31 +120,78 @@ def run_update_for_resource_type():
97
120
  fg="yellow",
98
121
  )
99
122
  # Update the record directly without affecting the draft
100
- record._record["metadata"]["resource_type"][
101
- "id"
102
- ] = "publication-dissertation"
123
+ if (
124
+ record._record["metadata"]["resource_type"]["id"]
125
+ == "publication-thesis"
126
+ ):
127
+ record._record["metadata"]["resource_type"][
128
+ "id"
129
+ ] = "publication-dissertation"
130
+ for related_identifier in record._record["metadata"].get(
131
+ "related_identifiers", []
132
+ ):
133
+ if (
134
+ related_identifier.get("resource_type", {}).get("id")
135
+ == "publication-thesis"
136
+ ):
137
+ related_identifier["resource_type"][
138
+ "id"
139
+ ] = "publication-dissertation"
103
140
  # Save the record changes and reindex
141
+ secho(
142
+ f"Record <{record.id}> has been updated... committing changes.",
143
+ fg="green",
144
+ )
104
145
  record._record.commit()
146
+ # Step 2: Update the resource type in the draft
147
+ if draft._record["metadata"]["resource_type"]["id"] == "publication-thesis":
148
+ draft._record["metadata"]["resource_type"][
149
+ "id"
150
+ ] = "publication-dissertation"
151
+ for related_identifier in draft._record["metadata"].get(
152
+ "related_identifiers", []
153
+ ):
154
+ if (
155
+ related_identifier.get("resource_type", {}).get("id")
156
+ == "publication-thesis"
157
+ ):
158
+ related_identifier["resource_type"][
159
+ "id"
160
+ ] = "publication-dissertation"
161
+ # After updating the record, update the draft's fork_version_id to match the record's new version_id, to avoid conflicts when publishing
162
+ draft._record.fork_version_id = record._record.revision_id
163
+ draft._record.commit()
164
+ # Commit the changes for both the record and the draft in one transaction
105
165
  db.session.commit()
106
166
  records_service.indexer.index(record._record)
167
+ records_service.indexer.index(draft._record)
168
+ secho(f"Draft <{draft.id}> has been updated successfully.", fg="green")
107
169
  # Update DOI metadata if record has DOI
108
170
  if hasattr(record, "pids") and record.pids.get("doi", None):
109
171
  records_service.pids.register_or_update(
110
172
  system_identity, record.id, "doi", parent=False
111
173
  )
112
- # Step 2: Update the resource type in the draft
113
- secho(f"Updating resource type for draft {draft.id}", fg="yellow")
114
- draft.data["metadata"]["resource_type"]["id"] = "publication-dissertation"
115
- # After updating the record, update the draft's fork_version_id to match the record's new version_id, to avoid conflicts when publishing
116
- draft._record.fork_version_id = record._record.revision_id
117
- updated_draft = records_service.update_draft(
118
- system_identity, draft.id, draft.data
119
- )
120
- secho(f"Draft {draft.id} has been updated successfully.", fg="green")
174
+ secho(
175
+ f"DOI metadata for record {record.id} has been updated successfully.",
176
+ fg="green",
177
+ )
121
178
  except DraftNotCreatedError:
122
179
  # If the draft didn't exist, we simply edit and publish the record
123
180
  draft = records_service.edit(system_identity, record.id)
124
- draft.data["metadata"]["resource_type"]["id"] = "publication-dissertation"
181
+ if draft.data["metadata"]["resource_type"]["id"] == "publication-thesis":
182
+ draft.data["metadata"]["resource_type"][
183
+ "id"
184
+ ] = "publication-dissertation"
185
+ for related_identifier in draft.data["metadata"].get(
186
+ "related_identifiers", []
187
+ ):
188
+ if (
189
+ related_identifier.get("resource_type", {}).get("id")
190
+ == "publication-thesis"
191
+ ):
192
+ related_identifier["resource_type"][
193
+ "id"
194
+ ] = "publication-dissertation"
125
195
  updated_draft = records_service.update_draft(
126
196
  system_identity, draft.id, draft.data
127
197
  )
@@ -129,36 +199,45 @@ def run_update_for_resource_type():
129
199
 
130
200
  secho(f"Record <{record.id}> has been updated successfully.", fg="green")
131
201
 
132
- def migrate_resource_type_in_draft(hit_result):
202
+ def migrate_resource_type_in_draft(draft_id):
133
203
  """
134
204
  Update resource type from publication-thesis to publication-dissertation.
135
205
 
136
206
  We go through the service layer to automatically trigger the DOI update and re-indexing.
137
207
  """
138
- secho(f"Updating resource type for draft {hit_result['id']}", fg="yellow")
139
- draft = records_service.edit(system_identity, hit_result["id"])
140
- if draft.data["metadata"]["resource_type"]["id"] != "publication-thesis":
208
+ secho(f"Updating resource type for draft {draft_id}", fg="yellow")
209
+ draft = records_service.edit(system_identity, draft_id)
210
+ if draft.data["metadata"]["resource_type"][
211
+ "id"
212
+ ] != "publication-thesis" and not any(
213
+ related_identifier.get("resource_type", {}).get("id")
214
+ == "publication-thesis"
215
+ for related_identifier in draft.data["metadata"].get(
216
+ "related_identifiers", []
217
+ )
218
+ ):
141
219
  secho(
142
220
  f"Skipping draft <{draft.id}> because it doesn't have resource-type 'publication-thesis'!",
143
221
  fg="yellow",
144
222
  )
145
223
  return
146
224
 
147
- draft.data["metadata"]["resource_type"]["id"] = "publication-dissertation"
225
+ if draft.data["metadata"]["resource_type"]["id"] == "publication-thesis":
226
+ draft.data["metadata"]["resource_type"]["id"] = "publication-dissertation"
227
+ for related_identifier in draft.data["metadata"].get("related_identifiers", []):
228
+ if (
229
+ related_identifier.get("resource_type", {}).get("id")
230
+ == "publication-thesis"
231
+ ):
232
+ related_identifier["resource_type"]["id"] = "publication-dissertation"
148
233
  updated_draft = records_service.update_draft(
149
234
  system_identity, draft.id, draft.data
150
235
  )
151
236
  secho(f"Draft <{updated_draft.id}> has been updated successfully.", fg="green")
152
237
 
153
- # Query records/drafts with resource type publication-thesis
154
- has_resource_type = dsl.Q(
155
- "query_string", query="metadata.resource_type.id:publication-thesis"
156
- )
157
-
158
238
  secho("Resource type update has started.", fg="green")
159
239
 
160
240
  run_upgrade(
161
- has_resource_type,
162
241
  migrate_resource_type_in_record,
163
242
  migrate_resource_type_in_draft,
164
243
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: invenio-app-rdm
3
- Version: 14.0.0b2.dev1
3
+ Version: 14.0.0b2.dev3
4
4
  Summary: Invenio Research Data Management.
5
5
  Home-page: https://github.com/inveniosoftware/invenio-app-rdm
6
6
  Author: CERN
@@ -101,6 +101,15 @@ https://inveniordm.docs.cern.ch
101
101
  Changes
102
102
  =======
103
103
 
104
+ Version v14.0.0b2.dev3 (released 2025-11-04)
105
+
106
+ - feat(share links): handle optional/required expiration date
107
+ - feat(form): rename creators to authors and help text
108
+
109
+ Version v14.0.0b2.dev2 (released 2025-10-24)
110
+
111
+ - upgrade_scripts: v14: optimize scan to avoid scroll context overhead
112
+
104
113
  Version v14.0.0b2.dev1 (released 2025-10-21)
105
114
 
106
115
  - deposit-form: updated related works options vocab
@@ -1,4 +1,4 @@
1
- invenio_app_rdm/__init__.py,sha256=YKw26EOYsN7GAX40s95XuSugzggJs6SM10HE0xQ7P-s,704
1
+ invenio_app_rdm/__init__.py,sha256=qtDll3HSdeeEVfPnlDtEDzlzYu5KLi5SLl5nkaIrQlg,704
2
2
  invenio_app_rdm/cli.py,sha256=G6QqNU2W6n6ICtTMnpeKFXIsdorncDmVXwwwsGH5F2k,2746
3
3
  invenio_app_rdm/config.py,sha256=kxAliLtzXLRysO8qxWxoSt1FhOjuDfzUi8xr40BBIYE,53632
4
4
  invenio_app_rdm/ext.py,sha256=K7syn5CU5If7yOclFeNOCZX_u5q6VB7NJEQVm41mlng,5286
@@ -50,8 +50,8 @@ invenio_app_rdm/records_ui/sitemap.py,sha256=erWpwi8lx17ATicBo3dTwMiEEwHTilL8xTA
50
50
  invenio_app_rdm/records_ui/utils.py,sha256=04Q_mI3SvfuNlmSziIJldr94UI2EKXZIdHAm4qHrEN0,3469
51
51
  invenio_app_rdm/records_ui/previewer/__init__.py,sha256=T32i_ssGKONDpNB3gECpn20ubHvGYYVrNuIgCADioOM,267
52
52
  invenio_app_rdm/records_ui/previewer/iiif_simple.py,sha256=lGxB3g0hNVJDWnq5jV_KrKPwC-LR1C51DMjas1-UpBM,1589
53
- invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/deposit.html,sha256=jdtme926G943raYhGa-evTK9NfWdyDOWEoONLtb-o2Q,2791
54
- invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/detail.html,sha256=RXUfOAKKEcljINo1b6irPgHqmnNDt0BNWpTk6lTs_nY,20865
53
+ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/deposit.html,sha256=vCz8EJsitKPFpEqp1yR2uPC97QpMvc941dK2Bgujj2c,2977
54
+ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/detail.html,sha256=pyyAjZ8eW_HS9Pajoiw1c1n4P0EcLdx6Phh8ZHPZkUE,21046
55
55
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/draft_not_found.html,sha256=_FPflgqVZ556Xw349mHPSFb0FOhxYkIHfmUUTX53_LU,624
56
56
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/export.html,sha256=2h-FGJvNKS9ASZ0mErL2vz5jXQYiLL8u8rTO2_D3FVQ,1166
57
57
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/iiif_preview.html,sha256=RningdsVBXsJ8qnQjzurf0Ty8R5Tq08eS31s53c3DNE,444
@@ -61,7 +61,7 @@ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/tombsto
61
61
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/access-form.html,sha256=rLkoNmouAMV8S6fAU3_PtGuqDjFTACniyiosGAKjcN0,2317
62
62
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/citation.html,sha256=QBbRNCBBdE7JJirLrIdCWlhcmR37qh_2QXg7AnTtwdw,576
63
63
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/contact.html,sha256=czuC-Ec5zJaKzFOaqhz7JqhWiCS3U3NKaQmPw9-rzks,403
64
- invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/creatibutors.html,sha256=43fnhdtCdec6d3s9B__7biS4vp0opvcMYh-1_jncYbA,2231
64
+ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/creatibutors.html,sha256=2IKZ9dCJxcWiC80vL10qED6ajFJZ-YUDGlCui_8GmiM,2239
65
65
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/description.html,sha256=UGUy-EOWggvBRCZT-H418yMW4PzYgn-5QFcmgZx1P8U,930
66
66
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/details.html,sha256=6hWOr-iRzGnIqlVUC_ZZd7JHbp5e4LNHYNXhK-rPoeg,12289
67
67
  invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/doi.html,sha256=bveXC9JvZVjPKQrtZ8FFUV-fIHEN4nB1VSyomR_obxA,473
@@ -181,7 +181,7 @@ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/RecordDel
181
181
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/RecordsResultsListItem.js,sha256=RTSQBlGQY7ww7fVGHDvDfWQNyJ07mnEoyboTGIcCgD4,6694
182
182
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/RecordDeletion/DeletionModal.js,sha256=kXME7Lr51ygS6PdA355Q2gh7bVcHLOBBW1ZClI_R4_E,12131
183
183
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/RecordDeletion/DeletionRadioGroup.js,sha256=qMFdPQkVQQsaS0P9KdPyFcuunZmGlEALjfABPueuoVU,1227
184
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js,sha256=nCr9aLp8jUZSvGUjn2lhQizf8X6qIFGDMrMJQ7pCnDE,34480
184
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js,sha256=wC3-MSDufkBkj3C1tDkuppzTpUaizhJNGe71dcnOQNw,34914
185
185
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/ShareDraftButton.js,sha256=ICMV4Ixe-nTe6q7COZ0oyAQf2nVp2cez_-iUZobwUD0,1998
186
186
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/config.js,sha256=rd2wqiwmYOkh4kWe8AiGWJar2kA8R8TkGMnX5XZvihs,1473
187
187
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/index.js,sha256=r9MvsucIXEyW7Bbb8vuEP2ZTRMzA-GJCn7GEpvqO0tY,1710
@@ -211,13 +211,13 @@ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/RecordC
211
211
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/RecordCommunitySubmission/RecordCommunitySubmissionModal.js,sha256=LM1RACmC3PS_o4txek-czaLvWD8OgjOM76aVK5jk8oE,5117
212
212
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/RemoveFromCommunity/RemoveFromCommunityAction.js,sha256=O5aHzH-oQsagurnU0e4pFc4B_4BRTbPuk0Ifk_T_WFw,5859
213
213
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/ShareButton.js,sha256=TKa1b_NUGD-DUqrqvQE2SwDI6Gr-HP246ymhDvQtj3A,1785
214
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/ShareModal.js,sha256=5Gq2TGsOlkvrwg2fURyv7wOaO2QH22_ZWzrjE2nCDiY,6627
214
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/ShareModal.js,sha256=pmHn5MQnQ41cuHt6iUWxloimkpZILzm4-TE_eqgwcuw,7249
215
215
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/AccessDropdown.js,sha256=0-Fune91rH-7B57kYvZxNlIemg-xLgxZ5LIbHGJY2PE,3068
216
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/CreateAccessLink.js,sha256=2Lmc9dCjv-83cagHUjdi_SGZkheRTGdywQUZGJxkihg,3368
216
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/CreateAccessLink.js,sha256=-YESwT_KpCnjGUUvVr8q5v4L_mIkH_GTORhPfdsK_cM,3833
217
217
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksSearchItem.js,sha256=Ay_A5zeLSCCo7x-9b1R9rV-XkbJmAP0w5MdmK182Lls,5272
218
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksSearchResultContainer.js,sha256=xr5dfml-v7NU2PzCKIB2_BeYFnFghnsqwKMgLErONQI,6786
219
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksTab.js,sha256=Ki1HN02B4_xFNy3YdPp3Mz2YLO-LxUhmNqRKKrvtVlQ,2883
220
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessRequests/AccessRequestsTab.js,sha256=tbSeqk7tnApZqLFi7NEegrwAGFKJ0sficF_3DB1Ld-0,8405
218
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksSearchResultContainer.js,sha256=-F5DdibhLVfKoXFoSkBS79CurQo9v4WkIhoIilL1VM4,7433
219
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessLinks/LinksTab.js,sha256=XoGy-bjp6dPyUygfzd3HCV5BMBds0tQPxiriudpNUrQ,3058
220
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessRequests/AccessRequestsTab.js,sha256=pGP7pMEEEgNgEHY0zk69Sc4C7YQxq4D0DSxu4gUpACg,8852
221
221
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessUsersGroups/AccessUsersGroups.js,sha256=tqUTVCNmfTZqY6aqDvZ3FOFl13EwT23AUWASpccdwMY,6886
222
222
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessUsersGroups/AddUserGroupAccessModal.js,sha256=qpaeKpIX2FUhztkBJtD03WlZ_YOziE0_1CF4cGwMb6Y,5839
223
223
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/AccessUsersGroups/GroupsTab.js,sha256=ZqiuZjjr1SZnTs3cBhX7ZckixAVa2KErEZXKY00A3oE,2358
@@ -226,7 +226,7 @@ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOp
226
226
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/landing_page/ShareOptions/api/api.js,sha256=WpRWWdlN_8TqeaMdB7RV2rQJSluetA91qIuJcAddfLY,926
227
227
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/overridableRegistry/index.js,sha256=xktX9vqs7xPTrKmGD93T-faSmg07LNsmK3GepA9F6j0,424
228
228
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/overridableRegistry/mapping.js,sha256=kRIVYx1pkzq6kNry3M6Cn5hykDkNJAaG7sQ0BdwGSj8,434
229
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/AccessRequestExpiration.js,sha256=rakfZqfulHvuW60i3oTF0ptQvFChDoacPEw5iJkMq9U,1721
229
+ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/AccessRequestExpiration.js,sha256=1h-Vkn-34-D3d-nfvg0de7-yi29NAifc2BJ-D4Z0kbQ,1940
230
230
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/index.js,sha256=FZ_XVB-5V7k_wOYeiI06RXQn3aIeh7beyBhcK5AIvCg,75
231
231
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/timeline/AccessRequestTimelineEdit.js,sha256=xd0uVbKLC23Y3RHlHDs0NdQ2vq9PNhimPwANkEtLSJ8,5727
232
232
  invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/requests/timeline/AccessRequestTimelineRead.js,sha256=CN_IIXwIeMDFxBxsal070uPVrpDH1_Rh7DSJi4hSjXA,1404
@@ -475,7 +475,7 @@ invenio_app_rdm/upgrade_scripts/fix_migrated_records_from_8_0_to_9_0.py,sha256=p
475
475
  invenio_app_rdm/upgrade_scripts/migrate_10_0_to_11_0.py,sha256=TX6FCWXY4qM4z7IYzDO5qaMTheo3zAjFrmR1sXaEf4U,1333
476
476
  invenio_app_rdm/upgrade_scripts/migrate_11_0_to_12_0.py,sha256=Tp7jfT2JHrYCFzF2qIYqG7yr7k-GhX2zkw61CWJGA78,6941
477
477
  invenio_app_rdm/upgrade_scripts/migrate_12_0_to_13_0.py,sha256=pyO68jyGyKXVTcja8tpi2XgNx_FxXk7JhgDTV-wx3xM,8205
478
- invenio_app_rdm/upgrade_scripts/migrate_13_0_to_14_0.py,sha256=TGq3Sfze6Sn97d45TloD7iyNHuaLK-O8O8tXJJiJytQ,7715
478
+ invenio_app_rdm/upgrade_scripts/migrate_13_0_to_14_0.py,sha256=-JyKmXQolkeh0dUKdEekVhVGTYZ4AncyjZdy4n5DIeQ,11356
479
479
  invenio_app_rdm/upgrade_scripts/migrate_1_0_records_to_2_0.py,sha256=mRDv_Ao5zMgA6X0aogMfvhspO1CIApKtDW_ziJp5fjI,3325
480
480
  invenio_app_rdm/upgrade_scripts/migrate_2_0_to_3_0.py,sha256=jL_2I61Q9qt3fjBzYYueeT4EMQ9FlNPxYE4nzDQbLEY,2698
481
481
  invenio_app_rdm/upgrade_scripts/migrate_3_0_to_4_0.py,sha256=BNjGufwLBvLHnu0gz5b_Are-FuxYjXlCtkLgNQckV3U,4768
@@ -496,9 +496,9 @@ invenio_app_rdm/users_ui/views/__init__.py,sha256=SMdY2NJj9GICfr3Xuok7qdNYVtA2bJ
496
496
  invenio_app_rdm/users_ui/views/dashboard.py,sha256=iUn2PrODAwb8ugmMosJKAjPhUzjCiWiAWoXQr9RUFuc,1793
497
497
  invenio_app_rdm/users_ui/views/ui.py,sha256=W_eXM8dLVIrNHQB2UEh37C9BYoHauft6RyvcDNFHovA,1742
498
498
  invenio_app_rdm/utils/files.py,sha256=CruDyO2gDVadSlWEJD-WHpWHeOQ0juh-Ei9jz3D9yjc,3923
499
- invenio_app_rdm-14.0.0b2.dev1.dist-info/licenses/LICENSE,sha256=AZXFHRrZa5s4m9DV7zZr4bPGTMUvcEPCodeV_AmFI8k,1204
500
- invenio_app_rdm-14.0.0b2.dev1.dist-info/METADATA,sha256=ythPvg1U9pqyZyITAJJTZPqMDJQ3_GB5HSNqvaNvcuA,19345
501
- invenio_app_rdm-14.0.0b2.dev1.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
502
- invenio_app_rdm-14.0.0b2.dev1.dist-info/entry_points.txt,sha256=MwtT1SN5saWOgTYhNb5y0YGA9VGAi0kXN0cykIfsb4U,2405
503
- invenio_app_rdm-14.0.0b2.dev1.dist-info/top_level.txt,sha256=quZejDUw2vLfKQboNIuVLJ9fxZifdnCT_s2PNf1dfmk,16
504
- invenio_app_rdm-14.0.0b2.dev1.dist-info/RECORD,,
499
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/licenses/LICENSE,sha256=AZXFHRrZa5s4m9DV7zZr4bPGTMUvcEPCodeV_AmFI8k,1204
500
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/METADATA,sha256=CQC3NZ42F9LazYTcrf_rP06jwHIXm3FcVc8DJUlUMd0,19627
501
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
502
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/entry_points.txt,sha256=MwtT1SN5saWOgTYhNb5y0YGA9VGAi0kXN0cykIfsb4U,2405
503
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/top_level.txt,sha256=quZejDUw2vLfKQboNIuVLJ9fxZifdnCT_s2PNf1dfmk,16
504
+ invenio_app_rdm-14.0.0b2.dev3.dist-info/RECORD,,