Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@ Allows to configure the zip export of metadata records and their attachments.

- **Total size of attachments allowed in zip export (MB)** Maximum total size of attachments allowed in zip export (in MB). If the total size of attachments linked to the selected metadata is above this value, exporting as zip (with attachments) is not allowed. Leave empty for no limit.

## Metadata workflow

The following settings control what metadata can be published when the metadata workflow is active. They are found under `Administration` --> `Settings` --> `Metadata Workflow`.

- **Allow publication of invalid metadata** When disabled, only metadata that passes all required XSD and schematron validation rules can be published. When enabled, metadata can be published regardless of its validation status. Templates are always exempt from this check, as they are typically incomplete by design.
- **Allow publication of non-approved metadata** When disabled, only metadata with an `Approved` workflow status can be published. When enabled, metadata can be published regardless of its workflow status. Templates are always exempt from this check, as they are not expected to go through the approval workflow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unclear to me if tempaltes may be subject to an approval workflow? I could very much imagine a team wishing to approve a new workflow before sharing it for wider use?

@tylerjmchugh tylerjmchugh Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is agreed that templates should respect the Allow publication of non-approved metadata setting, maybe the Allow submission/approval of invalid metadata setting needs to also exclude templates instead. With that setting disabled, currently an invalid template could never be approved so again it would be unpublishable.

Updated the PR description accordingly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the code so the "must be approved to publish" check is still respected. Instead I modified the "must be valid to approve" check to exclude templates.

So now an invalid template can be approved and then published.


## Harvesting

*Allow editing on harvested records*: Enables/Disables editing of harvested records in the catalogue. By default, harvested records cannot be edited.
Original file line number Diff line number Diff line change
Expand Up @@ -1352,18 +1352,28 @@ private void updateOwnership(Integer groupIdentifier,
}

/**
* For privileges to {@link ReservedGroup#all} group, check if it's allowed or not to publish invalid metadata.
* For privileges to {@link ReservedGroup#all} group, check if it's allowed or not to publish invalid or
* non-approved metadata. Templates (including sub-templates and templates of sub-templates) are exempt from
* these checks, as they are typically incomplete and not expected to be valid or approved.
*
* @param context
* @param messages
* @param metadata
* @param allowPublishInvalidMd
* @param allowPublishNonApprovedMd
* @throws Exception
* @param context the current service context
* @param messages the resource bundle for error messages
* @param metadata the metadata record being published
* @param allowPublishInvalidMd whether publishing invalid metadata is allowed (excluding templates)
* @param allowPublishNonApprovedMd whether publishing non-approved metadata is allowed (excluding templates)
* @throws Exception if the metadata is invalid or not approved and publishing is not allowed
*/
private void checkCanPublishToAllGroup(ServiceContext context, ResourceBundle messages, AbstractMetadata metadata,
boolean allowPublishInvalidMd, boolean allowPublishNonApprovedMd) throws Exception {

// Templates are typically incomplete and should not be subject to validation or approval checks
MetadataType metadataType = metadata.getDataInfo().getType();
if (metadataType == MetadataType.TEMPLATE
|| metadataType == MetadataType.SUB_TEMPLATE
|| metadataType == MetadataType.TEMPLATE_OF_SUB_TEMPLATE) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is starting to be a little silly, perhaps MetadataType should have a .isRequiresValidation() property :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest push

return;
}

if (!allowPublishInvalidMd) {
boolean hasValidation =
(metadataValidationRepository.count(MetadataValidationSpecs.hasMetadataId(metadata.getId())) > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@
import org.fao.geonet.api.records.model.SharingResponse;
import org.fao.geonet.domain.Group;
import org.fao.geonet.domain.GroupType;
import org.fao.geonet.domain.ISODate;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.domain.MetadataType;
import org.fao.geonet.domain.MetadataValidation;
import org.fao.geonet.domain.MetadataValidationId;
import org.fao.geonet.domain.MetadataValidationStatus;
import org.fao.geonet.domain.OperationAllowed;
import org.fao.geonet.domain.Profile;
import org.fao.geonet.domain.ReservedGroup;
Expand All @@ -44,7 +49,9 @@
import org.fao.geonet.kernel.setting.Settings;
import org.fao.geonet.repository.MetadataRepository;
import org.fao.geonet.repository.MetadataStatusRepository;
import org.fao.geonet.repository.MetadataValidationRepository;
import org.fao.geonet.repository.OperationAllowedRepository;
import org.fao.geonet.repository.StatusValueRepository;
import org.fao.geonet.repository.UserRepositoryTest;
import org.fao.geonet.services.AbstractServiceIntegrationTest;
import org.junit.Before;
Expand Down Expand Up @@ -87,6 +94,12 @@ public class MetadataSharingApiTest extends AbstractServiceIntegrationTest {
@Autowired
private MetadataStatusRepository metadataStatusRepository;

@Autowired
private MetadataValidationRepository metadataValidationRepository;

@Autowired
private StatusValueRepository statusValueRepository;

@Autowired
private SettingManager settingManager;

Expand Down Expand Up @@ -643,4 +656,82 @@ private void grantUserAdminInNewGroup(User user, String groupName) {
.setProfile(Profile.UserAdmin)
.setUser(user));
}

/**
* Verifies that publishing a TEMPLATE succeeds even when the metadata has a required invalid
* validation record and {@code allowPublishInvalidMd} is {@code false}.
* Templates are exempt from validation checks.
*/
@Test
public void publishInvalidTemplateSucceedsWhenPublishInvalidMdDisabled() throws Exception {
// Disable publishing of invalid metadata – the strict mode that triggered the bug.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the bug is addressed this comment will not make sense :P

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest push

settingManager.setValue(Settings.METADATA_WORKFLOW_ALLOW_PUBLISH_INVALID_MD, false);

// Change the metadata type to TEMPLATE.
Metadata template = metadataRepository.findById(metadataId).get();
template.getDataInfo().setType(MetadataType.TEMPLATE);
metadataRepository.save(template);

// Persist a required, INVALID validation record so the check would fail for normal metadata.
MetadataValidation invalidValidation = new MetadataValidation()
.setId(new MetadataValidationId(metadataId, "xsd"))
.setStatus(MetadataValidationStatus.INVALID)
.setRequired(true)
.setNumTests(1)
.setNumFailures(1);
metadataValidationRepository.save(invalidValidation);

MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MockHttpSession mockHttpSession = loginAs(reviewerUser);

// Publishing the template must succeed (HTTP 204) despite the invalid validation record.
mockMvc.perform(put("/srv/api/records/" + metadataUuid + "/publish")
.session(mockHttpSession))
.andExpect(status().isNoContent());

// Confirm publication privileges were actually granted.
List<OperationAllowed> ops = operationAllowedRepository.findAllById_MetadataId(metadataId);
boolean published = ops.stream().anyMatch(op -> ReservedGroup.isReserved(op.getId().getGroupId()));
assertTrue("Template should be published even when it has an invalid validation record", published);
}

/**
* Verifies that publishing a TEMPLATE succeeds even when its workflow status is DRAFT
* (non-approved) and {@code allowPublishNonApprovedMd} is {@code false}.
* Templates are exempt from approval status checks.
*/
@Test
public void publishNonApprovedTemplateSucceedsWhenPublishNonApprovedMdDisabled() throws Exception {
// Disable publishing of non-approved metadata – the strict mode that triggered the bug.
settingManager.setValue(Settings.METADATA_WORKFLOW_ALLOW_PUBLISH_NON_APPROVED_MD, false);

// Change the metadata type to TEMPLATE.
Metadata template = metadataRepository.findById(metadataId).get();
template.getDataInfo().setType(MetadataType.TEMPLATE);
metadataRepository.save(template);

// Assign a DRAFT (non-approved) workflow status so the check would fail for normal metadata.
MetadataStatus draftStatus = new MetadataStatus();
draftStatus.setMetadataId(metadataId);
draftStatus.setChangeDate(new ISODate());
draftStatus.setUserId(1);
draftStatus.setChangeMessage("draft status for template publish test");
draftStatus.setOwner(1);
draftStatus.setUuid(metadataUuid);
draftStatus.setStatusValue(statusValueRepository.findById(Integer.parseInt(StatusValue.Status.DRAFT)).get());
metadataStatusRepository.save(draftStatus);

MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MockHttpSession mockHttpSession = loginAs(reviewerUser);

// Publishing the template must succeed (HTTP 204) despite the non-approved status.
mockMvc.perform(put("/srv/api/records/" + metadataUuid + "/publish")
.session(mockHttpSession))
.andExpect(status().isNoContent());

// Confirm publication privileges were actually granted.
List<OperationAllowed> ops = operationAllowedRepository.findAllById_MetadataId(metadataId);
boolean published = ops.stream().anyMatch(op -> ReservedGroup.isReserved(op.getId().getGroupId()));
assertTrue("Template should be published even when its workflow status is not approved", published);
}
}
4 changes: 2 additions & 2 deletions web-ui/src/main/resources/catalog/locales/en-admin.json
Original file line number Diff line number Diff line change
Expand Up @@ -937,9 +937,9 @@
"metadata/workflow/allowSubmitApproveInvalidMd": "Allow submission/approval of invalid metadata",
"metadata/workflow/allowSubmitApproveInvalidMd-help": "Allows the submission/approval of metadata that is not valid according to xsd or schematron rules.",
"metadata/workflow/allowPublishNonApprovedMd": "Allow publication of non-approved metadata",
"metadata/workflow/allowPublishNonApprovedMd-help": "Allows the publication of metadata that is not approved.",
"metadata/workflow/allowPublishNonApprovedMd-help": "Allows the publication of metadata that is not approved. Excluding templates.",
"metadata/workflow/allowPublishInvalidMd": "Allow publication of invalid metadata",
"metadata/workflow/allowPublishInvalidMd-help": "Allows the publication of metadata that is not valid according to xsd or schematron rules.",
"metadata/workflow/allowPublishInvalidMd-help": "Allows the publication of metadata that is not valid according to xsd or schematron rules. Excluding templates.",
"metadata/workflow/draftWhenInGroup": "Activate workflow for record created in ",
"metadata/workflow/enable": "Enable workflow",
"draftWhenInGroup-all": "Any group",
Expand Down
Loading