[Port to dtq-dev] Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository - #1325
Conversation
… REST repository (#1357) * Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabelRest repository * resolve Copilot comments * fixed PUT request in ClarinLicenseLabelRestRepository * added check for Clarin License Label -> Label string to be shorter that 5 characters * implement coorrect put method in ClarinLicenseLabelRestRepository * add constraints to license_label table: made label UNIQUE, make license_label not deletable when used in clarin licenses * fixed IT test failure * change order of deleting objects in test cleanup(): delete license objects before license_label objects (to satisfy license_label constraints) * resolve PR Copilot comments, fixed failing ClarinWorkspaceItemRestRepositoryIT * prevent creating duplicate Clarin License Labels in REST API * not necessary to trim label twice * minor fixes, suggested by Copilot * Rename SQL migration files to use today's date (2026.06.01) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> (cherry picked from commit b041c90)
…abel arg
The backport added a `label` String parameter to the createClarinLicense
test helper but left six 4-arg call sites unchanged, breaking testCompile
in dspace-server-webapp. Pass a label at each remaining call site
("lbl"; "lbl1"/"lbl2" for the paired-license test) to match the helper's
new signature, preserving the previously hard-coded "lbl" behaviour.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe PR adds label-based lookup capability for ClarinLicense and ClarinLicenseLabel entities across the data access, REST, and test layers. It introduces ChangesClarinLicense findByLabel and REST Validation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (6)
dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseLabelDAOImpl.java (1)
34-35: ⚡ Quick winAdd method Javadoc on the new public override.
For overridden public methods, a brief
/** {@inheritdoc} */is sufficient to satisfy documentation requirements.As per coding guidelines, "Provide Javadoc comments for all public classes and methods".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseLabelDAOImpl.java` around lines 34 - 35, Add a Javadoc comment to the public overridden method findByLabel in class ClarinLicenseLabelDAOImpl: place a brief /** {`@inheritDoc`} */ directly above the method signature of public ClarinLicenseLabel findByLabel(Context context, String label) throws SQLException to satisfy the coding guideline requiring Javadoc on public methods.Source: Coding guidelines
dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseLabelDAO.java (1)
26-26: ⚡ Quick winDocument the new public DAO contract with Javadoc.
Please add method-level Javadoc for
findByLabel(...)to match API documentation requirements.As per coding guidelines, "Provide Javadoc comments for all public classes and methods".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseLabelDAO.java` at line 26, Add Javadoc for the public DAO method findByLabel in ClarinLicenseLabelDAO: describe the purpose (find a ClarinLicenseLabel by its label), document parameters (Context context, String label), document return value (ClarinLicenseLabel or null if not found), and list thrown exceptions (throws SQLException). Place the Javadoc immediately above the method declaration in the ClarinLicenseLabelDAO interface and use standard tags (`@param`, `@return`, `@throws`) to satisfy the API documentation requirement.Source: Coding guidelines
dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseLabelServiceImpl.java (1)
80-83: ⚡ Quick winAdd Javadoc for the new public service method.
Please add method documentation (or
{@inheritdoc}) forfindByLabel(...).As per coding guidelines, "Provide Javadoc comments for all public classes and methods".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseLabelServiceImpl.java` around lines 80 - 83, Add Javadoc to the public service method findByLabel in ClarinLicenseLabelServiceImpl: update the method declaration for public ClarinLicenseLabel findByLabel(Context context, String label) to include a Javadoc block (or {`@inheritDoc`}) describing the purpose, parameters (context, label), return value, and SQLException thrown; reference the DAO call clarinLicenseLabelDAO.findByLabel in the comment if helpful to explain behavior.Source: Coding guidelines
dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseDAO.java (1)
31-31: ⚡ Quick winAdd Javadoc to the new public DAO method.
findByLabel(...)is public API surface and should be documented for contract clarity.Suggested update
+ /** + * Find CLARIN licenses by associated label. + * + * `@param` context current DSpace context + * `@param` label license label + * `@return` matching licenses + * `@throws` SQLException if database access fails + */ List<ClarinLicense> findByLabel(Context context, String label) throws SQLException;As per coding guidelines, "Provide Javadoc comments for all public classes and methods".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseDAO.java` at line 31, Add Javadoc for the new public DAO method findByLabel in the ClarinLicenseDAO interface: document the method's purpose (lookup licenses by label), describe each parameter (Context context, String label), state the return value (List<ClarinLicense> matching the label, possibly empty), and document the SQLException thrown; ensure the Javadoc appears above the method signature in ClarinLicenseDAO and follows project tag conventions (`@param`, `@return`, `@throws`).Source: Coding guidelines
dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseServiceImpl.java (1)
101-104: ⚡ Quick winDocument
findByLabel(...)with Javadoc.This new public method should include method-level Javadoc (or
{@inheritdoc}) to keep public API docs complete.As per coding guidelines, "Provide Javadoc comments for all public classes and methods".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseServiceImpl.java` around lines 101 - 104, Add method-level Javadoc to the public method findByLabel in ClarinLicenseServiceImpl: either add a descriptive Javadoc block explaining purpose, parameters (Context context, String label), return value (List<ClarinLicense>), and thrown SQLException, or use {`@inheritDoc`} if the interface already documents it; ensure the Javadoc appears immediately above the findByLabel method and references the parameters and exception so the public API documentation remains complete.Source: Coding guidelines
dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.java (1)
170-180: 💤 Low valueAdd Javadoc for the private helper method.
While less critical than public methods, documenting the validation logic in
checkLabelAndTitlewould improve maintainability.📝 Suggested Javadoc
+ /** + * Validates that the label and title are not blank and that the label length + * does not exceed MAX_LABEL_LENGTH. + * + * `@param` clarinLicenseLabelRest the REST object to validate + * `@throws` DSpaceBadRequestException if validation fails + */ private void checkLabelAndTitle(ClarinLicenseLabelRest clarinLicenseLabelRest) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.java` around lines 170 - 180, Add Javadoc to the private helper checkLabelAndTitle in ClarinLicenseLabelRestRepository describing its purpose (validate non-null/empty trimmed label and title), the behavior (throws DSpaceBadRequestException on missing/blank fields or when label exceeds MAX_LABEL_LENGTH), and note the trimming of label via Optional and the use of MAX_LABEL_LENGTH; keep the comment concise and place it immediately above the checkLabelAndTitle method.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseDAOImpl.java`:
- Around line 62-76: The public method findByLabel in ClarinLicenseDAOImpl is
missing Javadoc; add a standard Javadoc block above the method explaining the
purpose of findByLabel(Context context, String label), describing the parameters
(context and label), the return value (List<ClarinLicense>), and the thrown
SQLException, and include any behavioural notes (e.g., matching semantics or
null/empty handling) so the documentation meets project guidelines and documents
the contract of the overridden DAO method.
In
`@dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.06.01__license_label_constraint.sql`:
- Around line 17-18: The migration unconditionally drops/adds the UNIQUE
constraint on license_label.label which will fail if duplicate labels exist;
before adding license_label_label_unique run a preflight duplicate check (SELECT
label, COUNT(*) ... HAVING COUNT(*) > 1) and implement a deterministic
dedup/upsert step to remove or merge duplicates (e.g. keep the earliest id or
newest timestamp) for rows with the same label, then re-run the ALTER TABLE to
add the UNIQUE constraint; reference the table name license_label and the
constraint name license_label_label_unique when adding the preflight check and
deterministic cleanup migration.
In
`@dspace-api/src/test/java/org/dspace/builder/util/AbstractBuilderCleanupUtil.java`:
- Line 20: The cleanup map in AbstractBuilderCleanupUtil now includes
ClarinLicenseBuilder but is missing ClarinLicenseLabelBuilder, causing FK
deletion order issues; update the cleanup map in the AbstractBuilderCleanupUtil
class to add ClarinLicenseLabelBuilder immediately after the existing
ClarinLicenseBuilder entry so that ClarinLicenseBuilder (licenses) are removed
before ClarinLicenseLabelBuilder (labels), ensuring deletions obey the
foreign-key constraint referenced by ClarinLicenseLabelRestRepository; locate
the map population code (the entries involving ClarinLicenseBuilder) and insert
the ClarinLicenseLabelBuilder entry right after it.
In
`@dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.java`:
- Around line 112-148: Add a Javadoc comment to the public method put in
ClarinLicenseLabelRestRepository: document the purpose of the endpoint, describe
each parameter (Context context, HttpServletRequest request, String apiCategory,
String model, Integer id, JsonNode jsonNode), explain the return value
(ClarinLicenseLabelRest via converter.toRest), and list thrown exceptions
(SQLException, AuthorizeException, DSpaceBadRequestException,
ClarinLicenseLabelNotFoundException). Keep the description concise and mention
relevant behavior such as parsing with objectMapper.treeToValue, validation via
checkLabelAndTitle, uniqueness check via clarinLicenseLabelService.findByLabel,
and that the entity is updated with updateClarinLicenseLabel and
clarinLicenseLabelService.update.
- Around line 150-168: Add Javadoc to the public method delete(Context context,
Integer id) in ClarinLicenseLabelRestRepository: document the purpose of the
method (deletes a ClarinLicenseLabel by id), describe parameters `@param` context
and `@param` id, and list thrown exceptions with `@throws` for AuthorizeException,
ClarinLicenseLabelNotFoundException, DSpaceBadRequestException and any
runtime/SQL-related exceptions that can propagate (e.g., RuntimeException
wrapping SQLException); also include a brief note about the
`@PreAuthorize`("hasAuthority('ADMIN')") security requirement. Ensure the Javadoc
sits immediately above the delete method signature.
---
Nitpick comments:
In
`@dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseLabelServiceImpl.java`:
- Around line 80-83: Add Javadoc to the public service method findByLabel in
ClarinLicenseLabelServiceImpl: update the method declaration for public
ClarinLicenseLabel findByLabel(Context context, String label) to include a
Javadoc block (or {`@inheritDoc`}) describing the purpose, parameters (context,
label), return value, and SQLException thrown; reference the DAO call
clarinLicenseLabelDAO.findByLabel in the comment if helpful to explain behavior.
In
`@dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseServiceImpl.java`:
- Around line 101-104: Add method-level Javadoc to the public method findByLabel
in ClarinLicenseServiceImpl: either add a descriptive Javadoc block explaining
purpose, parameters (Context context, String label), return value
(List<ClarinLicense>), and thrown SQLException, or use {`@inheritDoc`} if the
interface already documents it; ensure the Javadoc appears immediately above the
findByLabel method and references the parameters and exception so the public API
documentation remains complete.
In
`@dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseDAO.java`:
- Line 31: Add Javadoc for the new public DAO method findByLabel in the
ClarinLicenseDAO interface: document the method's purpose (lookup licenses by
label), describe each parameter (Context context, String label), state the
return value (List<ClarinLicense> matching the label, possibly empty), and
document the SQLException thrown; ensure the Javadoc appears above the method
signature in ClarinLicenseDAO and follows project tag conventions (`@param`,
`@return`, `@throws`).
In
`@dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseLabelDAO.java`:
- Line 26: Add Javadoc for the public DAO method findByLabel in
ClarinLicenseLabelDAO: describe the purpose (find a ClarinLicenseLabel by its
label), document parameters (Context context, String label), document return
value (ClarinLicenseLabel or null if not found), and list thrown exceptions
(throws SQLException). Place the Javadoc immediately above the method
declaration in the ClarinLicenseLabelDAO interface and use standard tags
(`@param`, `@return`, `@throws`) to satisfy the API documentation requirement.
In
`@dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseLabelDAOImpl.java`:
- Around line 34-35: Add a Javadoc comment to the public overridden method
findByLabel in class ClarinLicenseLabelDAOImpl: place a brief /** {`@inheritDoc`}
*/ directly above the method signature of public ClarinLicenseLabel
findByLabel(Context context, String label) throws SQLException to satisfy the
coding guideline requiring Javadoc on public methods.
In
`@dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.java`:
- Around line 170-180: Add Javadoc to the private helper checkLabelAndTitle in
ClarinLicenseLabelRestRepository describing its purpose (validate non-null/empty
trimmed label and title), the behavior (throws DSpaceBadRequestException on
missing/blank fields or when label exceeds MAX_LABEL_LENGTH), and note the
trimming of label via Optional and the use of MAX_LABEL_LENGTH; keep the comment
concise and place it immediately above the checkLabelAndTitle method.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 22405db3-31ea-40ca-aa5e-3395ae46e0db
📒 Files selected for processing (16)
dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseLabelServiceImpl.javadspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseServiceImpl.javadspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseDAO.javadspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseLabelDAO.javadspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseDAOImpl.javadspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseLabelDAOImpl.javadspace-api/src/main/java/org/dspace/content/service/clarin/ClarinLicenseLabelService.javadspace-api/src/main/java/org/dspace/content/service/clarin/ClarinLicenseService.javadspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.06.01__license_label_constraint.sqldspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2026.06.01__license_label_constraint.sqldspace-api/src/test/java/org/dspace/builder/util/AbstractBuilderCleanupUtil.javadspace-server-webapp/src/main/java/org/dspace/app/rest/exception/ClarinLicenseLabelNotFoundException.javadspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.javadspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinLicenseLabelRestRepositoryIT.javadspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.javadspace-server-webapp/src/test/java/org/dspace/app/rest/ProvenanceServiceIT.java
There was a problem hiding this comment.
Pull request overview
This PR ports Issue 1343 to dtq-dev by expanding the CLARIN License Label REST support (adding PUT/DELETE), adding label-based lookup in the CLARIN License service/DAO layer, and enforcing stricter validation/constraints around license labels.
Changes:
- Add/update REST API behavior for
ClarinLicenseLabel(PUT + DELETE), including label/title validation, max label length enforcement, uniqueness checks, and “in-use” deletion protection. - Add DAO/service methods to find licenses by a given label (to support deletion checks and label-based retrieval).
- Add DB migration to enforce FK restrict semantics and a UNIQUE constraint on
license_label.label, plus expanded integration tests.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| dspace-server-webapp/src/test/java/org/dspace/app/rest/ProvenanceServiceIT.java | Updates test helpers to create licenses with explicit labels and adjusts cleanup order for FK constraints. |
| dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.java | Updates workspace item REST integration tests to create licenses with explicit label values. |
| dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinLicenseLabelRestRepositoryIT.java | Adds integration coverage for create/update/delete scenarios, including validation and “label in use” deletion behavior. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinLicenseLabelRestRepository.java | Implements PUT/DELETE endpoints and centralizes validation + update logic for license labels. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/ClarinLicenseLabelNotFoundException.java | Adds a dedicated 404 exception for missing license labels. |
| dspace-api/src/test/java/org/dspace/builder/util/AbstractBuilderCleanupUtil.java | Registers ClarinLicenseBuilder for automated builder cleanup in tests. |
| dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2026.06.01__license_label_constraint.sql | Adds/replaces FK + UNIQUE constraints for Postgres to enforce restrict semantics and label uniqueness. |
| dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.06.01__license_label_constraint.sql | Adds/replaces FK + UNIQUE constraints for H2 to enforce restrict semantics and label uniqueness. |
| dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinLicenseService.java | Adds findByLabel() to the CLARIN license service API. |
| dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinLicenseLabelService.java | Adds findByLabel() to the CLARIN license label service API. |
| dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseLabelDAOImpl.java | Implements findByLabel() query for license labels via Criteria API. |
| dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseDAOImpl.java | Implements findByLabel() query for licenses via join to license labels. |
| dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseLabelDAO.java | Adds findByLabel() to the DAO interface. |
| dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseDAO.java | Adds findByLabel() to the DAO interface. |
| dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseServiceImpl.java | Wires the new findByLabel() through to the DAO. |
| dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseLabelServiceImpl.java | Wires the new findByLabel() through to the DAO. |
milanmajchrak
left a comment
There was a problem hiding this comment.
Please check the copilot comments
* UFAL/Fixed failing integration test (ufal#1332) (#1249) * Add debug messages to fauling test (cherry picked from commit 4cc3694) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Fix OpenAIRE integration: null handling and HTTP client lifecycle (#1248) * Fix OpenAIRE integration: null handling and HTTP client lifecycle (ufal#1330) * Add test for OpenAIRE connector * Initial plan * Add null check for OpenAIRE response to prevent NullPointerException Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Fix HTTP client lifecycle to prevent premature connection closure Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Keep the try with resources but copy the response into an in memory stream and return that * license:check --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> (cherry picked from commit 02984db) * Handle NumberFormatException in OpenAIREFundingDataProvider.getNumberOfResults and use explicit UTF-8 charset in OpenAIRERestConnectorTest --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: milanmajchrak <milan.majchrak@dataquest.sk> * UFAL/Added a comment to do not forget mounting the file which is changed via ocnfiguration feature (#1247) * UFAL/Issue 1315: Store file preview to database when file preview is created on Item Page load. (ufal#1316) (#1241) * Issue ufal/clarin-dspace1315: Store file preview to database when file preview is created on item page load * assert text improvement * PR comments: commit context only when any of the file preview is successfully created * change variable name (cherry picked from commit aab626b) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Issue 1313: fixed error when file preview is not generated for bitstream with store_number = 77 (ufal#1318) (#1240) * Issue ufal#1313: fixed error when file preview is not generated for bitstream with store number = 77 * resolve MR comments (cherry picked from commit 04d64f7) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Nw version metadata issues (#1236) * Issue ufal#1266: dc.date.available and dc.relation.replaces metadata not cleared properly (ufal#1307) * Issue ufal#1266: dc.date.available and dc.relation.replaces metadata not cleaned properly in new item version * resolve MR comments - update ignoredMetadataFields in versioning-service.xml * update ClarinVersionedHandleIdentifierProviderIT test to check dc.identifier.uri metadata for new version (cherry picked from commit 7ffaf9a) * Issue 1319: do not copy dc.identifier.doi metadata when new item version is created (cherry picked from commit 1b7ed17) --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Fix: add bitstream download-by-handle endpoint for curl instructions (#1252) * fix: add bitstream download-by-handle endpoint for curl instructions Adds GET /api/core/bitstreams/handle/{prefix}/{suffix}/{filename} endpoint that directly serves bitstream content by item handle and filename. This resolves the issue where curl download instructions generated by the UI produced URLs pointing to non-existent backend endpoints, resulting in 404 errors when users attempted to download files via command line. The new endpoint resolves the handle to an Item, finds the bitstream by exact filename in ORIGINAL bundles, and streams the raw content with correct Content-Type and Content-Disposition headers. Refs: dataquest-dev/dspace-angular#1210 * Fixed compliing errors * Small refactoring - use constants and removed unnecessary changes * added comments, return 404 status instead of 402 * unauthorized instead of forbidden * fix: use RFC 5987 Content-Disposition for non-ASCII filenames curl -J on Windows cannot create files with non-ASCII characters (e.g. diacritics like e/a) from a raw UTF-8 Content-Disposition filename header. Uses filename*=UTF-8''percent-encoded-name (RFC 5987/6266) which curl properly decodes. Also includes an ASCII fallback in filename param. * fix: move context.complete() after streaming to prevent truncated downloads context.complete() was called before bitstreamService.retrieve(), closing the DB connection and causing 'end of response with X bytes missing' errors. Now context.complete() is called only after the full content has been streamed. For S3 redirect and HEAD paths, context.complete() remains before return since no streaming is needed. * fix: use real UTF-8 filename in Content-Disposition instead of ASCII fallback The filename parameter now contains the original name (with diacritics like e/a) instead of replacing non-ASCII chars with underscores. Characters in the ISO-8859-1 range are transmitted correctly by Tomcat and understood by curl on Western/Central-European systems. The filename* parameter still provides RFC 5987 percent-encoded UTF-8 for modern clients (curl 7.56+). * fix: revert to ASCII fallback in Content-Disposition, add edge-case tests Content-Disposition filename parameter now uses ASCII fallback (non-ASCII replaced with underscore) per RFC 6266. Modern clients use filename* (RFC 5987) which has the full UTF-8 name. The curl command no longer relies on Content-Disposition at all (uses -o instead of -OJ). New integration tests for edge cases: - Multiple dots in filename (archive.v2.1.tar.gz) - Double quotes in filename (escaped in Content-Disposition) - CJK characters (beyond ISO-8859-1) - Same filename in ORIGINAL and TEXT bundles (only ORIGINAL served) * fix: resolve compilation errors and fix IT test assertions - Remove duplicate HttpStatus import (apache vs spring) - Add missing MediaType import (spring) - Fix Content-Type assertion to include charset=UTF-8 - Use URI.create() for pre-encoded URLs in tests to prevent double-encoding (%25) rejection by StrictHttpFirewall All 15 integration tests pass. * test: add complex filename test (diacritics, plus, hash, unmatched paren) New IT test for filename 'Media (+)#9) ano' verifying correct URL decoding, Content-Disposition encoding, and content delivery. 16/16 tests pass. * fix authorization, comments, tests * fix: change expected status from 401 to 403 for authenticated non-admin user The test downloadBitstreamByHandleUnauthorizedForNonAdmin uses getClient(token) which means the user IS authenticated. The controller correctly returns 403 (Forbidden) for authenticated users without access, not 401 (Unauthorized). 401 is only for anonymous/unauthenticated requests. --------- Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> * Reduce warn logs noise (#1268) * Log 404 responses at DEBUG instead of WARN to reduce log noise * Log 404 responses at DEBUG instead of WARN (configurable via logging.server.debug-404) * Skip stack trace extraction for suppressed 404 debug logs * Replace custom debug-404 property with dedicated Log4j2 logger (org.dspace.app.rest.NotFound) * Suppress 404 warn logs via dedicated Log4j2 logger (org.dspace.app.rest.NotFound) * Turn off that warn logs for the dspace.log * Updated log name to be more unique * The row lenght was updated to be less than 120 chars (#1274) * Reduce noisy WARN logs to DEBUG level (#1269) Changed two frequently occurring WARN log messages to DEBUG level: - Context.java: 'Initializing a context while an active transaction exists' - ClarinItemServiceImpl.java: 'Cannot update item dates metadata because the approximate date is empty' * Added oai bundle exclude feature * Updated docs * Fix OAI bundle exclusion docs and isolate OAIPMHBundleExposureIT config state * Fix indentation in OAIPMHBundleExposureIT field declaration * Updated docs * fix failing Curation tests (ufal#1353) (#1304) * fix RequiredMetadataIT failure * different fix for failing curator tests * change response to see last bitstream format results * cleaning custom bitstream format creation in PreviewContentServiceImplIT test * add debug messages * IIIFCacheEventConsumer: don't consume events when event subject is null (cherry picked from commit 50db8cd) **NOTE**: This is without the `dspace-api/src/test/java/org/dspace/curate/ItemMetadataQACheckerIT.java` change will add that one into #1237 Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Remove 'clariah' submission process (#1305) Removed the 'clariah' submission process it is not used (cherry picked from commit cae96d5) * UFAL/Issue 1349: admin user is not allowed to delete himself/herself (ufal#1350) (#1306) * Issue 1349: admin user is not allowed to delete himself/herself * improve the fix: test context.getCurrentUser() for null * throw IllegalStateException rather than AuthorizeException, and allow client to see the error message (cherry picked from commit b913627) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue 1354: add dc.relation.isreplacedby only when item is installed (ufal#1356) (#1308) * Issue 1354: add dc.relation.isreplacedby only when item is installed * set dc.relation.replaces on new item creation * fixed JavaDoc * fixed failing tests * test if dc.relation.isreplacedby metadata are only added when new item version is installed * use Context#reloadEntity rather than calling find method * removing unused field * also removing the now unused import --------- (cherry picked from commit 3e204e5) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Issue 1339: fixed NPE when hidden item metadata are checked for the item with deleted submitter (ufal#1344) (#1290) * Issue 1339: fixed NPE when hidden item metadata are checked for the item with deleted submitter (cherry picked from commit 64fda50) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue 1321: disable File preview for files where user has no Bitstream READ permission (ufal#1327) (#1280) * Issue 1321: disable File preview for files where the user has no Bitstream READ permission * alow file preview in case only the License agreement is needed * don't allow to create file preview for non-authorized user, nor for item that requires license confirmation * fixed failing FilePreviewIT test. Now only the user with file READ permission can generate file preview * add more tests for HTML file preview * add test for HTML File preview * improve warning messages * extend test to see if non admin user can see already generated file preview --------- (cherry picked from commit 50d7bbc) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/issue 1324: curation task - implement 3 types of reporters to allow proper report writing to selected destination (ufal#1326) (#1264) * issue 1324: implement 3 types of reporters to allow proper writing to file or to console * don't throw exception when not needed * no AbstractUnitTest required - AbstractDSpaceTest is sufficient * improve append(str) method in reporters, by using StringUtils.chomp() method (cherry picked from commit 6f19d1f) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue ufal#1292 link/unlink items with version relationship (ufal#1304) (#1253) * Issue 1292: script to allow link two items into version relationship * implement link and unlink actions * ItemVersionLinkerIT test * improve ItemVersionLinkerIT, fix ScriptRestRepositoryIT * improve test to be more realistic * improve options description * better call of itemService.clearMetadata() * clear correctly dc.relation.replaces and dc.relation.isreplacedby * use dc.identifier.uri metadata value rather than item.getHandle() to set dc.relation.replaces and dc.relation.isreplacedby * code-cleanup * add also as a cli script * Use Item.ANY instead of null tested with the production db dump on the items mentions in the issue (11234/1-5537). It was returning: ``` The script has started Item '11234/1-5537' has no handle assigned. ``` because it's dc.identifier.uri.* --------- (cherry picked from commit 903b35a) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/[Port to dtq-dev] Port ItemMetadataQAChecker curation task from v5 to v7 (#1237) * Port ItemMetadataQAChecker curation task from v5 to v7 (ufal#1312) * Add ItemMetadataQAChecker curation task with tests --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> (cherry picked from commit d5517be) * Issue ufal#1310 curation task to check relation metadata (ufal#1325) * issue 1310: check versioning releationship for items with relation metadata * improve implementation + test * More readable, I think. * update logging add the handle of the referenced item where possible * a test case to cover "no related item" * improve the failure message --------- Co-authored-by: Ondřej Košarko <ko_ok@centrum.cz> (cherry picked from commit c97f406) * fix failing Curation tests (ufal#1353) * fix RequiredMetadataIT failure * different fix for failing curator tests * change response to see last bitstream format results * cleaning custom bitstream format creation in PreviewContentServiceImplIT test * resolve MR comments * add debug messages * more debug messages * IIIFCacheEventConsumer: don't consume events when event subject is null (cherry picked from commit 50db8cd) **NOTE**: this is just `dspace-api/src/test/java/org/dspace/curate/ItemMetadataQACheckerIT.java` the rest is in #1304 * removed empty line --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Separate CLARIN license payload from sections.license (#1319) * fix(submission): separate CLARIN license payload from sections.license * fix(clarin-license): rename step path to /select, rename DataClarinLicense to ClarinDataLicense, and clean up comments * fix(clarin-license): align DTO name with Rest suffix convention * fix(submission): align CLARIN section DTO naming and apply Copilot review fixes * Align CLARIN license patch semantics and tighten section path handling * Fix checkstyle issue * Stabilize unknown CLARIN license metadata assertion * Added doc and checked null value * Harden CLARIN license patch handling and logging * UFAL/Fix clarin-license IT: expect 422 for empty value on select patch (#1323) * Expect 422 for empty value on clarin-license select patch * Treat blank value as clear on clarin-license section select * UFAL/Fix refbox buttons (ufal#1367) (#1318) * adding test and fixing the issue fixes ufal#1366 there was a conflict between the produces=application/json and response.setContentType("application/xml") * Strengthen citations endpoint test assertions for ufal#1366 regression coverage Agent-Logs-Url: https://github.com/ufal/clarin-dspace/sessions/e385ef9e-8186-4899-b811-fc82bbfa942b --------- (cherry picked from commit 8400982) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Health report, report diff fixes (#1254) * fix(health-report): fix CLI args, multi-check support, and report-diff comparison logic * Fix ReportDiff setup and date validation * fix failed integration test * added tests, used -c 1 2 instead of -c 1 -c 2 * used UNLIMITED_VALUES unstead of MAX_VALUE * improved doc * used multilist for -c , removed unused method * improved doc * WIP updated health report and report diff * Complete update of health-report and report-diff * Sorting reports and updating tests, plus enable multiple -c in report-diff * Improved docs, output and info and logic * Improved comparision of reports w/o changes, or with only one report specified * Updated tests * Removed unused Report and refactor getChecks * Address review comments: simplify null checks, deduplicate skipped-checks section, validate report IDs before defaulting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> Co-authored-by: milanmajchrak <milan.majchrak@dataquest.sk> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Fix flaky tests in IT pipeline (#1321) * Fixed integration tests because they use to fail sometimes * test: stabilize flaky CI tests (Hibernate cleanup retry, Shibboleth auth sequence reset, ORCID assertion hardening) * test: fix flaky ITs at the source (live ORCID, Shibboleth config-reload) + Hibernate CME diagnostics ORCID CachingOrcidRestConnectorTest no longer hits the live ORCID sandbox: search/getLabel/search_fail mock the HTTP layer (httpGet made protected) with a canned expanded-search response, so they are deterministic instead of asserting against fluctuating sandbox data. Shibboleth WWW-Authenticate flakiness: add a test-only config-definition.xml with config-reload=false. Runtime setProperty(...AuthenticationMethod...) overrides were silently discarded whenever the auto-reload listener rebuilt the combined config (restoring clarin-dspace.cfg's [Password, ClarinShib] default), intermittently leaking 'password realm' into the header. Verified: with auto-reload off the override survives; the explicit reloadConfig() reset in @after still works. Hibernate ConcurrentModificationException in @after cleanup: the per-session JDBC ResourceRegistry is not thread-safe, so the CME means two threads touch one Session. Capture a full thread dump on CME (target/cme-dumps/) to identify the colliding thread in CI; keep a resilient retry so an already-passed test isn't failed by this teardown race. (Context.finalize() ruled out: sessions are thread-local.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: revert IT-env config-reload=false override Disabling config auto-reload globally in the test environment broke AuthorizeConfigIT.testReloadConfiguration, which deliberately verifies that AuthorizeConfiguration picks up live changes written to local.cfg via the auto-reload mechanism. Auto-reload is a tested feature here, so it must not be disabled to work around the Shibboleth WWW-Authenticate flakiness. The Shibboleth flakiness (runtime setProperty override discarded when the combined config is rebuilt) needs a reload-safe fix in the auth test instead; tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: make Shibboleth auth-sequence override reload-safe (fix WWW-Authenticate flakiness) The flaky 'password realm' leak in AuthenticationRestControllerIT had this root cause: configurationService.setProperty(plugin.sequence...AuthenticationMethod, ...) only updates the in-memory view of the combined configuration. That view is discarded whenever it is rebuilt, and the auto-reload listener rebuilds it as soon as any reloadable cfg file's mtime changes mid-run (e.g. another test writing local.cfg). When that rebuild lands between the override and the request, clarin-dspace.cfg's default [PasswordAuthentication, ClarinShibAuthentication] returns and 'password realm' leaks into the header. The previous clear-then-set helper did not help (it is equivalent to a plain setProperty). Fix: set the sequence via a JVM system property (highest-precedence override layer, re-read on every rebuild) + reloadConfig(), and clear it in @after. This survives auto-reload without disabling it (so AuthorizeConfigIT, which verifies auto-reload, still passes). Verified in the real /api/authn/status endpoint: an explicit reloadConfig() after a setProperty override reproduces the leak, while the system-property approach keeps the header Shibboleth-only across rebuilds. Full AuthenticationRestControllerIT (43 tests) passes, and running it alongside ClarinAuthenticationRestControllerIT / AnonymousAdditionalAuthorizationFilterIT confirms the property does not leak across classes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: add Hibernate concurrency monitor + CI upload to pinpoint @after CME The intermittent ConcurrentModificationException in @after cleanup is a genuine cross-thread data race on Hibernate's per-session, non-thread-safe JDBC ResourceRegistry (xref): a second thread mutates the test thread's session while it commits/rolls back. Verified against hibernate-core-5.6.15 sources that the releaseResources forEach lambda never touches xref, so single-thread re-entrancy is impossible (this disproves the earlier HHH-15116 single-thread theory). The window is microseconds, so it does not reproduce locally even with deliberate cross-thread session sharing; it only surfaces under CI load. A live thread dump of a running IT JVM shows NO legitimate background thread ever touches Hibernate (all are Solr/HTTP/Jetty/JVM). So the culprit is a transient thread, and any non-test thread caught inside Hibernate JDBC/session code is by definition the offender. - HibernateConcurrencyMonitor: JVM-wide background sampler that records (de-duped) any non-test thread found inside org.hibernate.{resource.jdbc,engine.jdbc, internal.SessionImpl}; flushed to target/cme-dumps/ on CME and at JVM shutdown. Pure observer, never changes test behaviour. - AbstractIntegrationTestWithDatabase: start the monitor and mark the JUnit thread in setUp; flush it alongside the existing thread dump on a captured CME. - build.yml: always-upload **/target/cme-dumps/** (not gated on failure) so a successful cleanup retry no longer hides the diagnostic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: don't close iterate() Hibernate stream from a finalize() (root cause of flaky CME) Root cause of the intermittent ConcurrentModificationException in @after integration-test cleanup, identified via the HibernateConcurrencyMonitor CI dumps: the GC Finalizer thread, running org.dspace.core.AbstractHibernateDAO$1.finalize(), closed the Hibernate Stream returned by AbstractHibernateDAO.iterate(). Closing a stream closes its ScrollableResults, which mutates the owning Session's per-session, non-thread-safe JDBC ResourceRegistry (xref) - but on the Finalizer thread, concurrently with the thread that owns the session. When that collided with the owning thread's commit/rollback (releaseResources -> xref.forEach), it threw ConcurrentModificationException. The CI dumps showed this exact finalizer stack as the only non-test thread inside Hibernate in dspace-api, and present in dspace-server-webapp too. This was confirmed genuine cross-thread access (not the previously assumed single-thread/HHH bug): verified against hibernate-core-5.6.15 sources that the releaseResources forEach lambda never touches xref, so single-thread re-entrancy is impossible. Fix: close the backing stream on the owning thread when iteration is exhausted, and remove the finalize() override. An iterator abandoned before exhaustion is released safely when its Context/Session is closed (releaseResources then runs on the owning thread). Adds AbstractHibernateDAOIteratorIT to guard against reintroducing a stream-closing finalizer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: remove broken Context.finalize() that leaked finalizer-thread sessions Context.finalize() ran on the GC Finalizer thread and called dbConnection.isTransActionAlive()/abort(), which resolve sessionFactory.getCurrentSession() to a brand-new session bound to the Finalizer thread - never the (now-unreachable) thread that opened the Context. So it could not roll back the Context's transaction anyway; it only opened and leaked a throwaway Hibernate session on the Finalizer thread, and threw IllegalStateException once the SessionFactory was closed (seen in the CI thread dumps used to diagnose the flaky integration-test ConcurrentModificationException). Abandoned Contexts are cleaned up safely when their owning thread's session ends; callers already close Contexts via complete()/abort()/try-with-resources (Context is AutoCloseable). Removes the now-redundant ContextTest.testFinalize (close()/abort() are covered by testClose/testAbort/testAbort2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: remove flaky-CME diagnostic scaffolding and teardown retry (root cause fixed) The intermittent @after ConcurrentModificationException is now fixed at its source (AbstractHibernateDAO.iterate no longer closes its Hibernate stream from a finalizer; broken Context.finalize() removed). The temporary diagnostics that pinpointed it are no longer needed: - Restore AbstractIntegrationTestWithDatabase.destroy() to its plain form (drop the 3x cleanup retry and the per-CME thread dump) and remove the HibernateConcurrencyMonitor wiring. - Delete HibernateConcurrencyMonitor. - Revert the build.yml always-upload of target/cme-dumps. CI keeps -Dfailsafe.rerunFailingTestsCount=2 as the generic flaky-test safety net. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * revert: keep Context.finalize() (out of scope, not the CME cause) Reverts the Context.finalize() removal (and the ContextTest.testFinalize deletion). The flaky @after ConcurrentModificationException is fully fixed by the AbstractHibernateDAO.iterate() change alone; Context.finalize() runs on a single GC Finalizer thread against its own finalizer-thread session and provably cannot cause that cross-thread xref race. Removing a finalizer from this core, widely-used class is a riskier change that does not belong in a flaky-test fix, so leave Context untouched. The (pre-existing, harmless) finalizer-thread session it opens can be addressed separately if desired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: address review comments on flaky-test fix - AbstractHibernateDAOIteratorIT: add Javadoc to the test method and walk the iterator's full class hierarchy (up to Object) when asserting no finalize() override, so a finalizer reintroduced on a superclass/helper is also caught (per CodeRabbit review). - AuthenticationRestControllerIT: wrap an over-length (122 char) Javadoc line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Security patches from vanilla DSpace 7.6.7 (CVE-2026-49830, CVE-2026-49831) (#1340) * ORE aggregated resource URI validation (cherry picked from commit 7ac17f6) * Velocity and template safety for Email and LDN messages * Safer Velocity configuration * New "message.templates.allowed-config" config * Remove "UnmodifiableConfiguration" in favour of a simple Map of whitelisted Config keys/values * Centralise Velocity config in core Utils * Small javadoc changes (cherry picked from commit b2d6141) (cherry picked from commit 5b31db5) * Better null checking in allowed config props (cherry picked from commit 6b66531) (cherry picked from commit 46a0dfb) * Access configurationService at runtime, not rely on class setup (cherry picked from commit 5803819) (cherry picked from commit 4be430f) * Remove strict mode Velocity engine configuration (allow nulls) (cherry picked from commit 655fc62) * Filter requests for JSPs or traversal (cherry picked from commit cf9be85) (cherry picked from commit dc3e455) * Add additional logging to GlobalRequestSecurityFilter (cherry picked from commit 295a046) (cherry picked from commit 0b1deae) * Fix import order (cherry picked from commit e2e6a79) (cherry picked from commit 2e40077) * Update sitemap traversal test expectations (cherry picked from commit 56ae287) (cherry picked from commit 1a3dfd7) * Backport GlobalRequestSecurityFilter for javax (cherry picked from commit 8a2eee9) * Add secure file access methods (cherry picked from commit 22bec44) * Backport Curation I/O using secure file access Removes some JDK >= 16 usage (cherry picked from commit 55905a2) * Curation config support for allowed base paths (cherry picked from commit 4502224) * Move curation -r reporter param to CLI only (cherry picked from commit 277af82) * Fix import order (cherry picked from commit a757221) * Ignore CurationScriptIT -T taskFile tests, to rewrite w/ CLI (cherry picked from commit 6437472) (cherry picked from commit 37cd6eb) * Move taskfile -T option to CLI script config only (cherry picked from commit 00e4979) (cherry picked from commit 27708ea) * UFAL/Allow lr.help.mail in email template config allowlist The 7.6.7 Velocity hardening restricts templates to an allowlisted "config" map (Utils.getAllowedTemplateConfig). UFAL/CLARIN templates (clarin_download_link_admin, clarin_token, matomo_report, share_submission) reference config.get('lr.help.mail'), which vanilla DSpace does not ship, so it was missing from the allowlist and those emails would render a null help address. Add it to dspace.cfg only; Utils.java stays identical to upstream. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Kim Shepherd <kim@shepherd.nz> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Autolabel for new issues (#1341) Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> * [Port to dtq-dev] Issue 1364: tgz file preview fix (#1338) * Issue 1364: tgz file preview fix (ufal#1372) * Issue 1364: tgz file preview fix * resolve MR comments + fixed test * Update help message for force preview option * get rid of the password requirement on FilePreview script --------- Co-authored-by: Ondřej Košarko <kosarko@ufal.mff.cuni.cz> (cherry picked from commit 00a2a37) * PR Comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository (#1325) * Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository (ufal#1357) * Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabelRest repository * resolve Copilot comments * fixed PUT request in ClarinLicenseLabelRestRepository * added check for Clarin License Label -> Label string to be shorter that 5 characters * implement coorrect put method in ClarinLicenseLabelRestRepository * add constraints to license_label table: made label UNIQUE, make license_label not deletable when used in clarin licenses * change order of deleting objects in test cleanup(): delete license objects before license_label objects (to satisfy license_label constraints) * resolve PR Copilot comments, fixed failing ClarinWorkspaceItemRestRepositoryIT * prevent creating duplicate Clarin License Labels in REST API * not necessary to trim label twice * minor fixes, suggested by Copilot * Rename SQL migration files to use today's date (2026.06.01) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> (cherry picked from commit b041c90) * Fix test compilation: update createClarinLicense call sites for new label arg The backport added a `label` String parameter to the createClarinLicense test helper but left six 4-arg call sites unchanged, breaking testCompile in dspace-server-webapp. Pass a label at each remaining call site ("lbl"; "lbl1"/"lbl2" for the paired-license test) to match the helper's new signature, preserving the previously hard-coded "lbl" behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * PR comments: code cleanup --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * AI-Skills/Wire private AI skills submodule (.dspace-skills) (#1343) * test: de-flake ORCID cache tests and ZIP-download IT (#1344) * test: de-flake ORCID cache tests and ZIP-download IT Two independent flaky tests keep turning the dtq-dev pipeline red after #1321: 1. CachingOrcidRestConnectorTest.testCachable / testCacheableWithError still hit the live ORCID sandbox (#1321 only mocked getLabel/search/search_fail). They use the real Spring @Cacheable bean (to exercise the CGLIB caching proxy), so they could not be spied. Point the bean's apiURL at a local MockWebServer serving the canned orcid-expanded-search.xml instead -- keeps the real caching proxy and HTTP transport under test, removes the network dependency. No production change. 2. MetadataBitstreamControllerIT.downloadAllZip compared the response to a locally-built ZIP byte-for-byte; a ZIP entry's DOS timestamp (2s resolution) defaults to "now" on both sides and differs across a 2s boundary. Assert the unzipped entry name + content instead of raw bytes. Test-only changes. Verified locally (ORCID class 8/8 green, repeated offline runs; webapp test module compiles; checkstyle clean). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: assert exactly one ZIP entry in downloadAllZip Address CodeRabbit: a Map keyed by entry name could mask duplicate ZIP entries (same filename overwrites). Track the entry count separately and assert it is 1, so an unexpected extra entry fails the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: de-flake SSR authorization and Solr TopCountries ITs Two more intermittent failures on dtq-dev, both addressed at the root cause (test-only changes): 1. AuthorizationRestRepositoryIT.findByObjectSSRTest flaked with 400 instead of 200. The test sets dspace.server.ssr.url (used by Utils.getBaseObjectRestFromUri to resolve the request URI) and the AlwaysThrowExceptionFeature.turnoff flag via configurationService.setProperty(...). Such in-memory overrides are silently dropped when the combined config is rebuilt by the auto-reload listener (fires on any reloadable cfg file mtime change mid-run). When ssr.url is dropped the URI no longer resolves -> 400; if turnoff were also dropped the /search/object path would let alwaysexception throw -> 500. Fix: set both via JVM system properties (+ reloadConfig) so they sit in the highest-precedence override layer and survive auto-reload, cleared in @after. Same pattern as #1321's Shibboleth fix (AuthenticationRestControllerIT#setAuthenticationMethodSequence). Applied to all three SSR tests. 2. StatisticsRestRepositoryIT.topCountriesReport_Community_Visited flaked with an empty report (points: []). postView() commits with waitSearcher=false, so the just-posted view events can be invisible to the immediately-following report query (and a dropped solr-statistics.autoCommit override would skip the commit entirely). Fix: after posting the view events, force solrLoggerService.commit() (waitSearcher =true) so the events are flushed and visible before the report is queried. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * [Backport dtq-dev] Issue 1360: allow to change license in workflow item, in PATCH operation (ufal#1365) (#1327) * Issue 1360: allow to change license in workflow item, in PATCH operation (ufal#1365) * Issue 1360: allow to change license in workflow item, in PATCH operation * improve fix + Integration test * resolve Copilot comments * resolve more MR comments * return 404 in case PATCH request references non existing license * improve error message for task claimed by other user * resolve second round of Copilot comments * small code refactoring * fixed failing test (cherry picked from commit 40672c3) * resolve PR comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Issue ufal#1317 metadata health check (#1307) * Issue ufal#1317 metadata health check (ufal#1338) * Issue 1317: health-check for metadata - initial commit * implement MetadataCheck report * improve MetadataCheck * improve MetadataCheck with more sophisticated selection of error/warning messages * code cleanup * rename qa-metadata-error-patterns.json to metadata-check-patterns.json * implement copilot suggestions * add test for Metadata check to HealthReportIT * improved documentation * added test * improve documentation * set default error dispersion quota to 5 (cherry picked from commit 39157a5) * add JavaDoc description * resolve coderabbitai comment * update report-diff-fields.json * resolve Copilot comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * test: de-flake ItemHandleCheckerIT (mock the live handle resolver) (#1346) * test: de-flake ItemHandleCheckerIT (mock the live handle resolver) ItemHandleCheckerIT.testItemHandleNotFound intermittently failed on dtq-dev with a synthetic 617 (SocketTimeoutException) instead of 404. The checkhandles task (ItemHandleChecker) issues a HEAD request to each item's handle URL (handle.canonical.prefix + handle) with a 3s read timeout; the test pointed the prefix at the live http://hdl.handle.net/ and asserted the resolver returns 404 (non-existent handle) and 302->200 (a real handle). When the live resolver was slow/unreachable the HEAD timed out -> 617 -> red pipeline. Same class of flake as the ORCID tests; not a regression (the merge commit passed many other runs). Fix (test-only): serve the handle URLs from a local okhttp3 MockWebServer. setUp sets handle.canonical.prefix to the mock base URL; a path-based dispatcher returns 302 (+Location to a -target path) for the redirect handle, 200 for the target, and 404 otherwise. The real/invalid/ignored URLs are derived from the mock base instead of hard-coded hdl.handle.net literals; the server is closed in @after. All six tests keep their original assertions and behavior; only the live-network hop is removed. Verified locally: 6/6 green across 4 runs, no external network involved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: restore handle.canonical.prefix in ItemHandleCheckerIT teardown Address CodeRabbit: setUp overwrites the shared handle.canonical.prefix with the per-run mock-server URL. Capture the previous value and restore it in destroy() (after closing the mock server) so a later test in the same JVM is never left pointing at the now-closed localhost port. (The superclass destroy() reloadConfig() already resets it, but restoring explicitly makes the test self-contained.) Re-verified locally: 6/6 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * UFAL/Obtain special groups from user context when new token is generated (on token refresh) (ufal#1378) (#1347) * Issue 1373: obtain special groups from user context when new token is generated (on token refresh) * resolve Copilot comments * resolve Copilot Comments: compute special groups only when when user is authenticated * Remove HttpSession dependency from ClarinShibAuthentication Use request-scoped attributes for shib.authenticated instead of HttpSession/JSESSIONID, aligning with upstream ShibAuthentication. Follow-up to ufal#1373/ufal#1378. * Guard against null special groups in Context.getSpecialGroups A special-group UUID may reference a Group that has since been deleted; GroupService.find returns null in that case. The list was built with an unconditional add, so it could contain null elements, which caused an NPE downstream (e.g. SpecialGroupClaimProvider.getValue maps group.getID() while generating the JWT sg claim on token refresh). Filter nulls once here so every caller is covered. Follow-up to ufal#1373/ufal#1378. --------- (cherry picked from commit 4c294b2) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/fix: DOI Organizer creates duplicate dc.identifier.doi metadata (ufal#1368) (#1350) * Issue 1361 fix: DOI Organizer creates duplicate dc.identifier.doi metadata * copilot comments * Issue 1361: make DOI metadata save additive, report duplicates via QA saveDOIToObject now adds dc.identifier.doi only when that exact value is not already present, and no longer deletes metadata. The previous fix cleared existing values when more than one was found or when a different DOI was present; since this method runs after the DOI has already been registered with the external agency, silently dropping a (possibly legacy/citable) identifier is lossy and irreversible. The operation stays idempotent, so re-registration no longer creates duplicate values. Items that legitimately end up with more than one dc.identifier.doi value are now surfaced for manual review by adding dc.identifier.doi to the ItemMetadataQAChecker noDuplicate list (metadataqa curation task) rather than being cleaned up silently in the write path. Tests: flip the replace test to assert a pre-existing different DOI is preserved alongside the new one, keep the idempotency test, and add a QA checker IT asserting an item with two DOIs fails curation. * local field renaming --------- (cherry picked from commit 3b7db4c) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> --------- Co-authored-by: Ondřej Košarko <ko_ok@centrum.cz> Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> Co-authored-by: Kasinhou <129340513+Kasinhou@users.noreply.github.com> Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Kim Shepherd <kim@shepherd.nz> Co-authored-by: jurinecko <juraj.roka@dataquest.sk>
* UFAL/Fixed failing integration test (ufal#1332) (#1249) * Add debug messages to fauling test (cherry picked from commit 4cc3694) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Fix OpenAIRE integration: null handling and HTTP client lifecycle (#1248) * Fix OpenAIRE integration: null handling and HTTP client lifecycle (ufal#1330) * Add test for OpenAIRE connector * Initial plan * Add null check for OpenAIRE response to prevent NullPointerException Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Fix HTTP client lifecycle to prevent premature connection closure Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Keep the try with resources but copy the response into an in memory stream and return that * license:check --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> (cherry picked from commit 02984db) * Handle NumberFormatException in OpenAIREFundingDataProvider.getNumberOfResults and use explicit UTF-8 charset in OpenAIRERestConnectorTest --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: milanmajchrak <milan.majchrak@dataquest.sk> * UFAL/Added a comment to do not forget mounting the file which is changed via ocnfiguration feature (#1247) * UFAL/Issue 1315: Store file preview to database when file preview is created on Item Page load. (ufal#1316) (#1241) * Issue ufal/clarin-dspace1315: Store file preview to database when file preview is created on item page load * assert text improvement * PR comments: commit context only when any of the file preview is successfully created * change variable name (cherry picked from commit aab626b) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Issue 1313: fixed error when file preview is not generated for bitstream with store_number = 77 (ufal#1318) (#1240) * Issue ufal#1313: fixed error when file preview is not generated for bitstream with store number = 77 * resolve MR comments (cherry picked from commit 04d64f7) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Nw version metadata issues (#1236) * Issue ufal#1266: dc.date.available and dc.relation.replaces metadata not cleared properly (ufal#1307) * Issue ufal#1266: dc.date.available and dc.relation.replaces metadata not cleaned properly in new item version * resolve MR comments - update ignoredMetadataFields in versioning-service.xml * update ClarinVersionedHandleIdentifierProviderIT test to check dc.identifier.uri metadata for new version (cherry picked from commit 7ffaf9a) * Issue 1319: do not copy dc.identifier.doi metadata when new item version is created (cherry picked from commit 1b7ed17) --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Fix: add bitstream download-by-handle endpoint for curl instructions (#1252) * fix: add bitstream download-by-handle endpoint for curl instructions Adds GET /api/core/bitstreams/handle/{prefix}/{suffix}/{filename} endpoint that directly serves bitstream content by item handle and filename. This resolves the issue where curl download instructions generated by the UI produced URLs pointing to non-existent backend endpoints, resulting in 404 errors when users attempted to download files via command line. The new endpoint resolves the handle to an Item, finds the bitstream by exact filename in ORIGINAL bundles, and streams the raw content with correct Content-Type and Content-Disposition headers. Refs: dataquest-dev/dspace-angular#1210 * Fixed compliing errors * Small refactoring - use constants and removed unnecessary changes * added comments, return 404 status instead of 402 * unauthorized instead of forbidden * fix: use RFC 5987 Content-Disposition for non-ASCII filenames curl -J on Windows cannot create files with non-ASCII characters (e.g. diacritics like e/a) from a raw UTF-8 Content-Disposition filename header. Uses filename*=UTF-8''percent-encoded-name (RFC 5987/6266) which curl properly decodes. Also includes an ASCII fallback in filename param. * fix: move context.complete() after streaming to prevent truncated downloads context.complete() was called before bitstreamService.retrieve(), closing the DB connection and causing 'end of response with X bytes missing' errors. Now context.complete() is called only after the full content has been streamed. For S3 redirect and HEAD paths, context.complete() remains before return since no streaming is needed. * fix: use real UTF-8 filename in Content-Disposition instead of ASCII fallback The filename parameter now contains the original name (with diacritics like e/a) instead of replacing non-ASCII chars with underscores. Characters in the ISO-8859-1 range are transmitted correctly by Tomcat and understood by curl on Western/Central-European systems. The filename* parameter still provides RFC 5987 percent-encoded UTF-8 for modern clients (curl 7.56+). * fix: revert to ASCII fallback in Content-Disposition, add edge-case tests Content-Disposition filename parameter now uses ASCII fallback (non-ASCII replaced with underscore) per RFC 6266. Modern clients use filename* (RFC 5987) which has the full UTF-8 name. The curl command no longer relies on Content-Disposition at all (uses -o instead of -OJ). New integration tests for edge cases: - Multiple dots in filename (archive.v2.1.tar.gz) - Double quotes in filename (escaped in Content-Disposition) - CJK characters (beyond ISO-8859-1) - Same filename in ORIGINAL and TEXT bundles (only ORIGINAL served) * fix: resolve compilation errors and fix IT test assertions - Remove duplicate HttpStatus import (apache vs spring) - Add missing MediaType import (spring) - Fix Content-Type assertion to include charset=UTF-8 - Use URI.create() for pre-encoded URLs in tests to prevent double-encoding (%25) rejection by StrictHttpFirewall All 15 integration tests pass. * test: add complex filename test (diacritics, plus, hash, unmatched paren) New IT test for filename 'Media (+)#9) ano' verifying correct URL decoding, Content-Disposition encoding, and content delivery. 16/16 tests pass. * fix authorization, comments, tests * fix: change expected status from 401 to 403 for authenticated non-admin user The test downloadBitstreamByHandleUnauthorizedForNonAdmin uses getClient(token) which means the user IS authenticated. The controller correctly returns 403 (Forbidden) for authenticated users without access, not 401 (Unauthorized). 401 is only for anonymous/unauthenticated requests. --------- Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> * Reduce warn logs noise (#1268) * Log 404 responses at DEBUG instead of WARN to reduce log noise * Log 404 responses at DEBUG instead of WARN (configurable via logging.server.debug-404) * Skip stack trace extraction for suppressed 404 debug logs * Replace custom debug-404 property with dedicated Log4j2 logger (org.dspace.app.rest.NotFound) * Suppress 404 warn logs via dedicated Log4j2 logger (org.dspace.app.rest.NotFound) * Turn off that warn logs for the dspace.log * Updated log name to be more unique * The row lenght was updated to be less than 120 chars (#1274) * Reduce noisy WARN logs to DEBUG level (#1269) Changed two frequently occurring WARN log messages to DEBUG level: - Context.java: 'Initializing a context while an active transaction exists' - ClarinItemServiceImpl.java: 'Cannot update item dates metadata because the approximate date is empty' * Added oai bundle exclude feature * Updated docs * Fix OAI bundle exclusion docs and isolate OAIPMHBundleExposureIT config state * Fix indentation in OAIPMHBundleExposureIT field declaration * Updated docs * fix failing Curation tests (ufal#1353) (#1304) * fix RequiredMetadataIT failure * different fix for failing curator tests * change response to see last bitstream format results * cleaning custom bitstream format creation in PreviewContentServiceImplIT test * add debug messages * IIIFCacheEventConsumer: don't consume events when event subject is null (cherry picked from commit 50db8cd) **NOTE**: This is without the `dspace-api/src/test/java/org/dspace/curate/ItemMetadataQACheckerIT.java` change will add that one into #1237 Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Remove 'clariah' submission process (#1305) Removed the 'clariah' submission process it is not used (cherry picked from commit cae96d5) * UFAL/Issue 1349: admin user is not allowed to delete himself/herself (ufal#1350) (#1306) * Issue 1349: admin user is not allowed to delete himself/herself * improve the fix: test context.getCurrentUser() for null * throw IllegalStateException rather than AuthorizeException, and allow client to see the error message (cherry picked from commit b913627) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue 1354: add dc.relation.isreplacedby only when item is installed (ufal#1356) (#1308) * Issue 1354: add dc.relation.isreplacedby only when item is installed * set dc.relation.replaces on new item creation * fixed JavaDoc * fixed failing tests * test if dc.relation.isreplacedby metadata are only added when new item version is installed * use Context#reloadEntity rather than calling find method * removing unused field * also removing the now unused import --------- (cherry picked from commit 3e204e5) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Issue 1339: fixed NPE when hidden item metadata are checked for the item with deleted submitter (ufal#1344) (#1290) * Issue 1339: fixed NPE when hidden item metadata are checked for the item with deleted submitter (cherry picked from commit 64fda50) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue 1321: disable File preview for files where user has no Bitstream READ permission (ufal#1327) (#1280) * Issue 1321: disable File preview for files where the user has no Bitstream READ permission * alow file preview in case only the License agreement is needed * don't allow to create file preview for non-authorized user, nor for item that requires license confirmation * fixed failing FilePreviewIT test. Now only the user with file READ permission can generate file preview * add more tests for HTML file preview * add test for HTML File preview * improve warning messages * extend test to see if non admin user can see already generated file preview --------- (cherry picked from commit 50d7bbc) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/issue 1324: curation task - implement 3 types of reporters to allow proper report writing to selected destination (ufal#1326) (#1264) * issue 1324: implement 3 types of reporters to allow proper writing to file or to console * don't throw exception when not needed * no AbstractUnitTest required - AbstractDSpaceTest is sufficient * improve append(str) method in reporters, by using StringUtils.chomp() method (cherry picked from commit 6f19d1f) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * Issue ufal#1292 link/unlink items with version relationship (ufal#1304) (#1253) * Issue 1292: script to allow link two items into version relationship * implement link and unlink actions * ItemVersionLinkerIT test * improve ItemVersionLinkerIT, fix ScriptRestRepositoryIT * improve test to be more realistic * improve options description * better call of itemService.clearMetadata() * clear correctly dc.relation.replaces and dc.relation.isreplacedby * use dc.identifier.uri metadata value rather than item.getHandle() to set dc.relation.replaces and dc.relation.isreplacedby * code-cleanup * add also as a cli script * Use Item.ANY instead of null tested with the production db dump on the items mentions in the issue (11234/1-5537). It was returning: ``` The script has started Item '11234/1-5537' has no handle assigned. ``` because it's dc.identifier.uri.* --------- (cherry picked from commit 903b35a) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/[Port to dtq-dev] Port ItemMetadataQAChecker curation task from v5 to v7 (#1237) * Port ItemMetadataQAChecker curation task from v5 to v7 (ufal#1312) * Add ItemMetadataQAChecker curation task with tests --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> (cherry picked from commit d5517be) * Issue ufal#1310 curation task to check relation metadata (ufal#1325) * issue 1310: check versioning releationship for items with relation metadata * improve implementation + test * More readable, I think. * update logging add the handle of the referenced item where possible * a test case to cover "no related item" * improve the failure message --------- Co-authored-by: Ondřej Košarko <ko_ok@centrum.cz> (cherry picked from commit c97f406) * fix failing Curation tests (ufal#1353) * fix RequiredMetadataIT failure * different fix for failing curator tests * change response to see last bitstream format results * cleaning custom bitstream format creation in PreviewContentServiceImplIT test * resolve MR comments * add debug messages * more debug messages * IIIFCacheEventConsumer: don't consume events when event subject is null (cherry picked from commit 50db8cd) **NOTE**: this is just `dspace-api/src/test/java/org/dspace/curate/ItemMetadataQACheckerIT.java` the rest is in #1304 * removed empty line --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/Separate CLARIN license payload from sections.license (#1319) * fix(submission): separate CLARIN license payload from sections.license * fix(clarin-license): rename step path to /select, rename DataClarinLicense to ClarinDataLicense, and clean up comments * fix(clarin-license): align DTO name with Rest suffix convention * fix(submission): align CLARIN section DTO naming and apply Copilot review fixes * Align CLARIN license patch semantics and tighten section path handling * Fix checkstyle issue * Stabilize unknown CLARIN license metadata assertion * Added doc and checked null value * Harden CLARIN license patch handling and logging * UFAL/Fix clarin-license IT: expect 422 for empty value on select patch (#1323) * Expect 422 for empty value on clarin-license select patch * Treat blank value as clear on clarin-license section select * UFAL/Fix refbox buttons (ufal#1367) (#1318) * adding test and fixing the issue fixes ufal#1366 there was a conflict between the produces=application/json and response.setContentType("application/xml") * Strengthen citations endpoint test assertions for ufal#1366 regression coverage Agent-Logs-Url: https://github.com/ufal/clarin-dspace/sessions/e385ef9e-8186-4899-b811-fc82bbfa942b --------- (cherry picked from commit 8400982) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> * Health report, report diff fixes (#1254) * fix(health-report): fix CLI args, multi-check support, and report-diff comparison logic * Fix ReportDiff setup and date validation * fix failed integration test * added tests, used -c 1 2 instead of -c 1 -c 2 * used UNLIMITED_VALUES unstead of MAX_VALUE * improved doc * used multilist for -c , removed unused method * improved doc * WIP updated health report and report diff * Complete update of health-report and report-diff * Sorting reports and updating tests, plus enable multiple -c in report-diff * Improved docs, output and info and logic * Improved comparision of reports w/o changes, or with only one report specified * Updated tests * Removed unused Report and refactor getChecks * Address review comments: simplify null checks, deduplicate skipped-checks section, validate report IDs before defaulting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> Co-authored-by: milanmajchrak <milan.majchrak@dataquest.sk> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Fix flaky tests in IT pipeline (#1321) * Fixed integration tests because they use to fail sometimes * test: stabilize flaky CI tests (Hibernate cleanup retry, Shibboleth auth sequence reset, ORCID assertion hardening) * test: fix flaky ITs at the source (live ORCID, Shibboleth config-reload) + Hibernate CME diagnostics ORCID CachingOrcidRestConnectorTest no longer hits the live ORCID sandbox: search/getLabel/search_fail mock the HTTP layer (httpGet made protected) with a canned expanded-search response, so they are deterministic instead of asserting against fluctuating sandbox data. Shibboleth WWW-Authenticate flakiness: add a test-only config-definition.xml with config-reload=false. Runtime setProperty(...AuthenticationMethod...) overrides were silently discarded whenever the auto-reload listener rebuilt the combined config (restoring clarin-dspace.cfg's [Password, ClarinShib] default), intermittently leaking 'password realm' into the header. Verified: with auto-reload off the override survives; the explicit reloadConfig() reset in @after still works. Hibernate ConcurrentModificationException in @after cleanup: the per-session JDBC ResourceRegistry is not thread-safe, so the CME means two threads touch one Session. Capture a full thread dump on CME (target/cme-dumps/) to identify the colliding thread in CI; keep a resilient retry so an already-passed test isn't failed by this teardown race. (Context.finalize() ruled out: sessions are thread-local.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: revert IT-env config-reload=false override Disabling config auto-reload globally in the test environment broke AuthorizeConfigIT.testReloadConfiguration, which deliberately verifies that AuthorizeConfiguration picks up live changes written to local.cfg via the auto-reload mechanism. Auto-reload is a tested feature here, so it must not be disabled to work around the Shibboleth WWW-Authenticate flakiness. The Shibboleth flakiness (runtime setProperty override discarded when the combined config is rebuilt) needs a reload-safe fix in the auth test instead; tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: make Shibboleth auth-sequence override reload-safe (fix WWW-Authenticate flakiness) The flaky 'password realm' leak in AuthenticationRestControllerIT had this root cause: configurationService.setProperty(plugin.sequence...AuthenticationMethod, ...) only updates the in-memory view of the combined configuration. That view is discarded whenever it is rebuilt, and the auto-reload listener rebuilds it as soon as any reloadable cfg file's mtime changes mid-run (e.g. another test writing local.cfg). When that rebuild lands between the override and the request, clarin-dspace.cfg's default [PasswordAuthentication, ClarinShibAuthentication] returns and 'password realm' leaks into the header. The previous clear-then-set helper did not help (it is equivalent to a plain setProperty). Fix: set the sequence via a JVM system property (highest-precedence override layer, re-read on every rebuild) + reloadConfig(), and clear it in @after. This survives auto-reload without disabling it (so AuthorizeConfigIT, which verifies auto-reload, still passes). Verified in the real /api/authn/status endpoint: an explicit reloadConfig() after a setProperty override reproduces the leak, while the system-property approach keeps the header Shibboleth-only across rebuilds. Full AuthenticationRestControllerIT (43 tests) passes, and running it alongside ClarinAuthenticationRestControllerIT / AnonymousAdditionalAuthorizationFilterIT confirms the property does not leak across classes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: add Hibernate concurrency monitor + CI upload to pinpoint @after CME The intermittent ConcurrentModificationException in @after cleanup is a genuine cross-thread data race on Hibernate's per-session, non-thread-safe JDBC ResourceRegistry (xref): a second thread mutates the test thread's session while it commits/rolls back. Verified against hibernate-core-5.6.15 sources that the releaseResources forEach lambda never touches xref, so single-thread re-entrancy is impossible (this disproves the earlier HHH-15116 single-thread theory). The window is microseconds, so it does not reproduce locally even with deliberate cross-thread session sharing; it only surfaces under CI load. A live thread dump of a running IT JVM shows NO legitimate background thread ever touches Hibernate (all are Solr/HTTP/Jetty/JVM). So the culprit is a transient thread, and any non-test thread caught inside Hibernate JDBC/session code is by definition the offender. - HibernateConcurrencyMonitor: JVM-wide background sampler that records (de-duped) any non-test thread found inside org.hibernate.{resource.jdbc,engine.jdbc, internal.SessionImpl}; flushed to target/cme-dumps/ on CME and at JVM shutdown. Pure observer, never changes test behaviour. - AbstractIntegrationTestWithDatabase: start the monitor and mark the JUnit thread in setUp; flush it alongside the existing thread dump on a captured CME. - build.yml: always-upload **/target/cme-dumps/** (not gated on failure) so a successful cleanup retry no longer hides the diagnostic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: don't close iterate() Hibernate stream from a finalize() (root cause of flaky CME) Root cause of the intermittent ConcurrentModificationException in @after integration-test cleanup, identified via the HibernateConcurrencyMonitor CI dumps: the GC Finalizer thread, running org.dspace.core.AbstractHibernateDAO$1.finalize(), closed the Hibernate Stream returned by AbstractHibernateDAO.iterate(). Closing a stream closes its ScrollableResults, which mutates the owning Session's per-session, non-thread-safe JDBC ResourceRegistry (xref) - but on the Finalizer thread, concurrently with the thread that owns the session. When that collided with the owning thread's commit/rollback (releaseResources -> xref.forEach), it threw ConcurrentModificationException. The CI dumps showed this exact finalizer stack as the only non-test thread inside Hibernate in dspace-api, and present in dspace-server-webapp too. This was confirmed genuine cross-thread access (not the previously assumed single-thread/HHH bug): verified against hibernate-core-5.6.15 sources that the releaseResources forEach lambda never touches xref, so single-thread re-entrancy is impossible. Fix: close the backing stream on the owning thread when iteration is exhausted, and remove the finalize() override. An iterator abandoned before exhaustion is released safely when its Context/Session is closed (releaseResources then runs on the owning thread). Adds AbstractHibernateDAOIteratorIT to guard against reintroducing a stream-closing finalizer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: remove broken Context.finalize() that leaked finalizer-thread sessions Context.finalize() ran on the GC Finalizer thread and called dbConnection.isTransActionAlive()/abort(), which resolve sessionFactory.getCurrentSession() to a brand-new session bound to the Finalizer thread - never the (now-unreachable) thread that opened the Context. So it could not roll back the Context's transaction anyway; it only opened and leaked a throwaway Hibernate session on the Finalizer thread, and threw IllegalStateException once the SessionFactory was closed (seen in the CI thread dumps used to diagnose the flaky integration-test ConcurrentModificationException). Abandoned Contexts are cleaned up safely when their owning thread's session ends; callers already close Contexts via complete()/abort()/try-with-resources (Context is AutoCloseable). Removes the now-redundant ContextTest.testFinalize (close()/abort() are covered by testClose/testAbort/testAbort2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: remove flaky-CME diagnostic scaffolding and teardown retry (root cause fixed) The intermittent @after ConcurrentModificationException is now fixed at its source (AbstractHibernateDAO.iterate no longer closes its Hibernate stream from a finalizer; broken Context.finalize() removed). The temporary diagnostics that pinpointed it are no longer needed: - Restore AbstractIntegrationTestWithDatabase.destroy() to its plain form (drop the 3x cleanup retry and the per-CME thread dump) and remove the HibernateConcurrencyMonitor wiring. - Delete HibernateConcurrencyMonitor. - Revert the build.yml always-upload of target/cme-dumps. CI keeps -Dfailsafe.rerunFailingTestsCount=2 as the generic flaky-test safety net. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * revert: keep Context.finalize() (out of scope, not the CME cause) Reverts the Context.finalize() removal (and the ContextTest.testFinalize deletion). The flaky @after ConcurrentModificationException is fully fixed by the AbstractHibernateDAO.iterate() change alone; Context.finalize() runs on a single GC Finalizer thread against its own finalizer-thread session and provably cannot cause that cross-thread xref race. Removing a finalizer from this core, widely-used class is a riskier change that does not belong in a flaky-test fix, so leave Context untouched. The (pre-existing, harmless) finalizer-thread session it opens can be addressed separately if desired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: address review comments on flaky-test fix - AbstractHibernateDAOIteratorIT: add Javadoc to the test method and walk the iterator's full class hierarchy (up to Object) when asserting no finalize() override, so a finalizer reintroduced on a superclass/helper is also caught (per CodeRabbit review). - AuthenticationRestControllerIT: wrap an over-length (122 char) Javadoc line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Security patches from vanilla DSpace 7.6.7 (CVE-2026-49830, CVE-2026-49831) (#1340) * ORE aggregated resource URI validation (cherry picked from commit 7ac17f6) * Velocity and template safety for Email and LDN messages * Safer Velocity configuration * New "message.templates.allowed-config" config * Remove "UnmodifiableConfiguration" in favour of a simple Map of whitelisted Config keys/values * Centralise Velocity config in core Utils * Small javadoc changes (cherry picked from commit b2d6141) (cherry picked from commit 5b31db5) * Better null checking in allowed config props (cherry picked from commit 6b66531) (cherry picked from commit 46a0dfb) * Access configurationService at runtime, not rely on class setup (cherry picked from commit 5803819) (cherry picked from commit 4be430f) * Remove strict mode Velocity engine configuration (allow nulls) (cherry picked from commit 655fc62) * Filter requests for JSPs or traversal (cherry picked from commit cf9be85) (cherry picked from commit dc3e455) * Add additional logging to GlobalRequestSecurityFilter (cherry picked from commit 295a046) (cherry picked from commit 0b1deae) * Fix import order (cherry picked from commit e2e6a79) (cherry picked from commit 2e40077) * Update sitemap traversal test expectations (cherry picked from commit 56ae287) (cherry picked from commit 1a3dfd7) * Backport GlobalRequestSecurityFilter for javax (cherry picked from commit 8a2eee9) * Add secure file access methods (cherry picked from commit 22bec44) * Backport Curation I/O using secure file access Removes some JDK >= 16 usage (cherry picked from commit 55905a2) * Curation config support for allowed base paths (cherry picked from commit 4502224) * Move curation -r reporter param to CLI only (cherry picked from commit 277af82) * Fix import order (cherry picked from commit a757221) * Ignore CurationScriptIT -T taskFile tests, to rewrite w/ CLI (cherry picked from commit 6437472) (cherry picked from commit 37cd6eb) * Move taskfile -T option to CLI script config only (cherry picked from commit 00e4979) (cherry picked from commit 27708ea) * UFAL/Allow lr.help.mail in email template config allowlist The 7.6.7 Velocity hardening restricts templates to an allowlisted "config" map (Utils.getAllowedTemplateConfig). UFAL/CLARIN templates (clarin_download_link_admin, clarin_token, matomo_report, share_submission) reference config.get('lr.help.mail'), which vanilla DSpace does not ship, so it was missing from the allowlist and those emails would render a null help address. Add it to dspace.cfg only; Utils.java stays identical to upstream. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Kim Shepherd <kim@shepherd.nz> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Autolabel for new issues (#1341) Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> * [Port to dtq-dev] Issue 1364: tgz file preview fix (#1338) * Issue 1364: tgz file preview fix (ufal#1372) * Issue 1364: tgz file preview fix * resolve MR comments + fixed test * Update help message for force preview option * get rid of the password requirement on FilePreview script --------- Co-authored-by: Ondřej Košarko <kosarko@ufal.mff.cuni.cz> (cherry picked from commit 00a2a37) * PR Comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository (#1325) * Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository (ufal#1357) * Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabelRest repository * resolve Copilot comments * fixed PUT request in ClarinLicenseLabelRestRepository * added check for Clarin License Label -> Label string to be shorter that 5 characters * implement coorrect put method in ClarinLicenseLabelRestRepository * add constraints to license_label table: made label UNIQUE, make license_label not deletable when used in clarin licenses * change order of deleting objects in test cleanup(): delete license objects before license_label objects (to satisfy license_label constraints) * resolve PR Copilot comments, fixed failing ClarinWorkspaceItemRestRepositoryIT * prevent creating duplicate Clarin License Labels in REST API * not necessary to trim label twice * minor fixes, suggested by Copilot * Rename SQL migration files to use today's date (2026.06.01) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> (cherry picked from commit b041c90) * Fix test compilation: update createClarinLicense call sites for new label arg The backport added a `label` String parameter to the createClarinLicense test helper but left six 4-arg call sites unchanged, breaking testCompile in dspace-server-webapp. Pass a label at each remaining call site ("lbl"; "lbl1"/"lbl2" for the paired-license test) to match the helper's new signature, preserving the previously hard-coded "lbl" behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * PR comments: code cleanup --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * AI-Skills/Wire private AI skills submodule (.dspace-skills) (#1343) * test: de-flake ORCID cache tests and ZIP-download IT (#1344) * test: de-flake ORCID cache tests and ZIP-download IT Two independent flaky tests keep turning the dtq-dev pipeline red after #1321: 1. CachingOrcidRestConnectorTest.testCachable / testCacheableWithError still hit the live ORCID sandbox (#1321 only mocked getLabel/search/search_fail). They use the real Spring @Cacheable bean (to exercise the CGLIB caching proxy), so they could not be spied. Point the bean's apiURL at a local MockWebServer serving the canned orcid-expanded-search.xml instead -- keeps the real caching proxy and HTTP transport under test, removes the network dependency. No production change. 2. MetadataBitstreamControllerIT.downloadAllZip compared the response to a locally-built ZIP byte-for-byte; a ZIP entry's DOS timestamp (2s resolution) defaults to "now" on both sides and differs across a 2s boundary. Assert the unzipped entry name + content instead of raw bytes. Test-only changes. Verified locally (ORCID class 8/8 green, repeated offline runs; webapp test module compiles; checkstyle clean). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: assert exactly one ZIP entry in downloadAllZip Address CodeRabbit: a Map keyed by entry name could mask duplicate ZIP entries (same filename overwrites). Track the entry count separately and assert it is 1, so an unexpected extra entry fails the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: de-flake SSR authorization and Solr TopCountries ITs Two more intermittent failures on dtq-dev, both addressed at the root cause (test-only changes): 1. AuthorizationRestRepositoryIT.findByObjectSSRTest flaked with 400 instead of 200. The test sets dspace.server.ssr.url (used by Utils.getBaseObjectRestFromUri to resolve the request URI) and the AlwaysThrowExceptionFeature.turnoff flag via configurationService.setProperty(...). Such in-memory overrides are silently dropped when the combined config is rebuilt by the auto-reload listener (fires on any reloadable cfg file mtime change mid-run). When ssr.url is dropped the URI no longer resolves -> 400; if turnoff were also dropped the /search/object path would let alwaysexception throw -> 500. Fix: set both via JVM system properties (+ reloadConfig) so they sit in the highest-precedence override layer and survive auto-reload, cleared in @after. Same pattern as #1321's Shibboleth fix (AuthenticationRestControllerIT#setAuthenticationMethodSequence). Applied to all three SSR tests. 2. StatisticsRestRepositoryIT.topCountriesReport_Community_Visited flaked with an empty report (points: []). postView() commits with waitSearcher=false, so the just-posted view events can be invisible to the immediately-following report query (and a dropped solr-statistics.autoCommit override would skip the commit entirely). Fix: after posting the view events, force solrLoggerService.commit() (waitSearcher =true) so the events are flushed and visible before the report is queried. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * [Backport dtq-dev] Issue 1360: allow to change license in workflow item, in PATCH operation (ufal#1365) (#1327) * Issue 1360: allow to change license in workflow item, in PATCH operation (ufal#1365) * Issue 1360: allow to change license in workflow item, in PATCH operation * improve fix + Integration test * resolve Copilot comments * resolve more MR comments * return 404 in case PATCH request references non existing license * improve error message for task claimed by other user * resolve second round of Copilot comments * small code refactoring * fixed failing test (cherry picked from commit 40672c3) * resolve PR comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Issue ufal#1317 metadata health check (#1307) * Issue ufal#1317 metadata health check (ufal#1338) * Issue 1317: health-check for metadata - initial commit * implement MetadataCheck report * improve MetadataCheck * improve MetadataCheck with more sophisticated selection of error/warning messages * code cleanup * rename qa-metadata-error-patterns.json to metadata-check-patterns.json * implement copilot suggestions * add test for Metadata check to HealthReportIT * improved documentation * added test * improve documentation * set default error dispersion quota to 5 (cherry picked from commit 39157a5) * add JavaDoc description * resolve coderabbitai comment * update report-diff-fields.json * resolve Copilot comments --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * test: de-flake ItemHandleCheckerIT (mock the live handle resolver) (#1346) * test: de-flake ItemHandleCheckerIT (mock the live handle resolver) ItemHandleCheckerIT.testItemHandleNotFound intermittently failed on dtq-dev with a synthetic 617 (SocketTimeoutException) instead of 404. The checkhandles task (ItemHandleChecker) issues a HEAD request to each item's handle URL (handle.canonical.prefix + handle) with a 3s read timeout; the test pointed the prefix at the live http://hdl.handle.net/ and asserted the resolver returns 404 (non-existent handle) and 302->200 (a real handle). When the live resolver was slow/unreachable the HEAD timed out -> 617 -> red pipeline. Same class of flake as the ORCID tests; not a regression (the merge commit passed many other runs). Fix (test-only): serve the handle URLs from a local okhttp3 MockWebServer. setUp sets handle.canonical.prefix to the mock base URL; a path-based dispatcher returns 302 (+Location to a -target path) for the redirect handle, 200 for the target, and 404 otherwise. The real/invalid/ignored URLs are derived from the mock base instead of hard-coded hdl.handle.net literals; the server is closed in @after. All six tests keep their original assertions and behavior; only the live-network hop is removed. Verified locally: 6/6 green across 4 runs, no external network involved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: restore handle.canonical.prefix in ItemHandleCheckerIT teardown Address CodeRabbit: setUp overwrites the shared handle.canonical.prefix with the per-run mock-server URL. Capture the previous value and restore it in destroy() (after closing the mock server) so a later test in the same JVM is never left pointing at the now-closed localhost port. (The superclass destroy() reloadConfig() already resets it, but restoring explicitly makes the test self-contained.) Re-verified locally: 6/6 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * UFAL/Obtain special groups from user context when new token is generated (on token refresh) (ufal#1378) (#1347) * Issue 1373: obtain special groups from user context when new token is generated (on token refresh) * resolve Copilot comments * resolve Copilot Comments: compute special groups only when when user is authenticated * Remove HttpSession dependency from ClarinShibAuthentication Use request-scoped attributes for shib.authenticated instead of HttpSession/JSESSIONID, aligning with upstream ShibAuthentication. Follow-up to ufal#1373/ufal#1378. * Guard against null special groups in Context.getSpecialGroups A special-group UUID may reference a Group that has since been deleted; GroupService.find returns null in that case. The list was built with an unconditional add, so it could contain null elements, which caused an NPE downstream (e.g. SpecialGroupClaimProvider.getValue maps group.getID() while generating the JWT sg claim on token refresh). Filter nulls once here so every caller is covered. Follow-up to ufal#1373/ufal#1378. --------- (cherry picked from commit 4c294b2) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * UFAL/fix: DOI Organizer creates duplicate dc.identifier.doi metadata (ufal#1368) (#1350) * Issue 1361 fix: DOI Organizer creates duplicate dc.identifier.doi metadata * copilot comments * Issue 1361: make DOI metadata save additive, report duplicates via QA saveDOIToObject now adds dc.identifier.doi only when that exact value is not already present, and no longer deletes metadata. The previous fix cleared existing values when more than one was found or when a different DOI was present; since this method runs after the DOI has already been registered with the external agency, silently dropping a (possibly legacy/citable) identifier is lossy and irreversible. The operation stays idempotent, so re-registration no longer creates duplicate values. Items that legitimately end up with more than one dc.identifier.doi value are now surfaced for manual review by adding dc.identifier.doi to the ItemMetadataQAChecker noDuplicate list (metadataqa curation task) rather than being cleaned up silently in the write path. Tests: flip the replace test to assert a pre-existing different DOI is preserved alongside the new one, keep the idempotency test, and add a QA checker IT asserting an item with two DOIs fails curation. * local field renaming --------- (cherry picked from commit 3b7db4c) Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> * [Port to dtq-dev] Issue ufal#1351 simple ror authority (#1349) * Issue ufal#1351 simple ror authority (ufal#1352) * Issue 1351: SimpleRORAuthority * integration test * code cleanup * add debug messages to find test failure * Revert "add debug messages to find test failure" This reverts commit 286fde4. * test failures * Revert "test failures" This reverts commit 8808f5e. * resolve Copilot comments * resolve PR comments, add ROR lookup to Publisher field * rollback changes in VocabularyEntryLinkRepository * fixing failing tests * implement PR Comments * implementation improvement * resolve PR comments (O.Kosarko) * Address review nits: shared ObjectMapper, commons-lang3, IT cleanup - Reuse a single static ObjectMapper in SimpleRORAuthority instead of constructing one per call. - Switch to the non-deprecated org.apache.commons.lang3.LocaleUtils. - Reset the ChoiceAuthority plugin configuration in @afterclass so VocabularyEntryLinkRepositoryIT no longer leaks the SimpleRORAuthority registration into other integration tests. * implement cache for gertLabel() * resolve PR Comments --------- Co-authored-by: Ondrej Kosarko <kosarko@ufal.mff.cuni.cz> (cherry picked from commit 25a5a25) * fix potential NPE Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix possible NPE in getBestMatch * fix possible NPE and some typos * add license header * Don't cache the fallback * resolved CodeRabbit comment --------- Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Ondřej Košarko <ko_ok@centrum.cz> Co-authored-by: Milan Kuchtiak <kuchtiak@ufal.mff.cuni.cz> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: kosarko <1842385+kosarko@users.noreply.github.com> Co-authored-by: Paurikova2 <michaela.paurikova@dataquest.sk> Co-authored-by: Kasinhou <129340513+Kasinhou@users.noreply.github.com> Co-authored-by: Matus Kasak <matus.kasak@dataquest.sk> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Kim Shepherd <kim@shepherd.nz> Co-authored-by: jurinecko <juraj.roka@dataquest.sk> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… base (#1376) Cherry-pick of eebe17d "[Port to dtq-dev] Issue 1343: add PUT and DELETE endpoint methods to ClarinLicenseLabel REST repository (#1325)", adapted for DSpace 9. This port was dropped when CLARIN was merged into the v9 base: dtq-dev-9-base carries every other CLARIN 7.6 migration but not this one. Diffing the migration sets against dtq-dev shows exactly one missing: V7.6_2026.06.01__license_label_constraint.sql which is why importing a dev-5 (CLARIN 7.6) dump onto this branch dies with FlywayValidateException: Detected applied migration not resolved locally: 7.6.2026.06.01. The deploy workflow currently works around that with `dspace database repair`. That masks the gap rather than fixing it -- and would mask the next dropped migration just as quietly -- so fix the cause: bring the port back. The rest of #1325 was missing too (REST repository had no put, no DELETE, no DAO/service methods, no ClarinLicenseLabelNotFoundException). Adapted for v9 (javax -> jakarta; the branch is fully Jakarta EE -- 283 files import jakarta.servlet.http.HttpServletRequest and none import the javax one): - ClarinLicenseDAOImpl javax.persistence.* -> jakarta.persistence.* The only real cherry-pick conflict. Adds Predicate and SetJoin, which the new findByLabel needs. - ClarinLicenseLabelDAOImpl javax.persistence.* -> jakarta.persistence.* This one merged CLEANLY and silently: 9-base had no persistence imports at all, so git had nothing to conflict with, and it would simply not have compiled. - ClarinLicenseLabelNotFoundException javax.ws.rs -> jakarta.ws.rs - ClarinLicenseLabelRestRepository javax.servlet -> jakarta.servlet Import order follows the v9 convention checkstyle enforces: jakarta.* belongs to the third-party group, lexicographically between com.* and org.*. Verified locally: dspace-api compile, dspace-server-webapp compile and test-compile, checkstyle on both -- all clean. Co-authored-by: Milan Majchrák <minptai7@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port of ufal#1357 by @kuchtiak-ufal to
dtq-dev.Summary by CodeRabbit