|
36 | 36 | import edu.harvard.iq.dataverse.globus.GlobusServiceBean; |
37 | 37 | import edu.harvard.iq.dataverse.globus.GlobusUtil; |
38 | 38 | import edu.harvard.iq.dataverse.ingest.IngestServiceBean; |
| 39 | +import edu.harvard.iq.dataverse.ingest.IngestUtil; |
39 | 40 | import edu.harvard.iq.dataverse.makedatacount.*; |
40 | 41 | import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry; |
41 | 42 | import edu.harvard.iq.dataverse.metrics.MetricsUtil; |
|
95 | 96 | import java.util.logging.Logger; |
96 | 97 | import java.util.regex.Pattern; |
97 | 98 | import java.util.stream.Collectors; |
98 | | - |
99 | 99 | import static edu.harvard.iq.dataverse.api.ApiConstants.*; |
100 | 100 | import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; |
101 | 101 |
|
@@ -4614,6 +4614,152 @@ public Response replaceFilesInDataset(@Context ContainerRequestContext crc, |
4614 | 4614 |
|
4615 | 4615 | } |
4616 | 4616 |
|
| 4617 | + @POST |
| 4618 | + @AuthRequired |
| 4619 | + @Path("{id}/files/metadata") |
| 4620 | + @Consumes(MediaType.APPLICATION_JSON) |
| 4621 | + public Response updateMultipleFileMetadata(@Context ContainerRequestContext crc, String jsonData, |
| 4622 | + @PathParam("id") String datasetId) { |
| 4623 | + try { |
| 4624 | + DataverseRequest req = createDataverseRequest(getRequestUser(crc)); |
| 4625 | + Dataset dataset = findDatasetOrDie(datasetId); |
| 4626 | + User authUser = getRequestUser(crc); |
| 4627 | + |
| 4628 | + // Verify that the user has EditDataset permission |
| 4629 | + if (!permissionSvc.requestOn(createDataverseRequest(authUser), dataset).has(Permission.EditDataset)) { |
| 4630 | + return error(Response.Status.FORBIDDEN, "You do not have permission to edit this dataset."); |
| 4631 | + } |
| 4632 | + |
| 4633 | + // Parse the JSON array |
| 4634 | + JsonArray jsonArray = JsonUtil.getJsonArray(jsonData); |
| 4635 | + |
| 4636 | + // Get the latest version of the dataset |
| 4637 | + DatasetVersion latestVersion = dataset.getLatestVersion(); |
| 4638 | + List<FileMetadata> currentFileMetadatas = latestVersion.getFileMetadatas(); |
| 4639 | + |
| 4640 | + // Quick checks to verify all file ids in the JSON array are valid |
| 4641 | + Set<Long> validFileIds = currentFileMetadatas.stream().map(fm -> fm.getDataFile().getId()) |
| 4642 | + .collect(Collectors.toSet()); |
| 4643 | + |
| 4644 | + // Extract all file IDs from the JSON array |
| 4645 | + Set<Long> jsonFileIds = jsonArray.stream().map(JsonValue::asJsonObject).map(jsonObj -> { |
| 4646 | + try { |
| 4647 | + return jsonObj.getJsonNumber("dataFileId").longValueExact(); |
| 4648 | + } catch (NumberFormatException e) { |
| 4649 | + return null; |
| 4650 | + } |
| 4651 | + }).collect(Collectors.toSet()); |
| 4652 | + |
| 4653 | + if (jsonFileIds.size() != jsonArray.size()) { |
| 4654 | + return error(BAD_REQUEST, "One or more invalid dataFileId values were provided"); |
| 4655 | + } |
| 4656 | + |
| 4657 | + // Check if all JSON file IDs are valid |
| 4658 | + if (!validFileIds.containsAll(jsonFileIds)) { |
| 4659 | + Set<Long> invalidIds = new HashSet<>(jsonFileIds); |
| 4660 | + invalidIds.removeAll(validFileIds); |
| 4661 | + return error(BAD_REQUEST, |
| 4662 | + "The following files are not part of the current version of the Dataset. dataFileIds: " + invalidIds); |
| 4663 | + } |
| 4664 | + |
| 4665 | + // Create editable fileMetadata if needed |
| 4666 | + if (!latestVersion.isDraft()) { |
| 4667 | + latestVersion = dataset.getOrCreateEditVersion(); |
| 4668 | + currentFileMetadatas = latestVersion.getFileMetadatas(); |
| 4669 | + } |
| 4670 | + |
| 4671 | + // Create a map of fileId to FileMetadata for quick lookup |
| 4672 | + Map<Long, FileMetadata> fileMetadataMap = currentFileMetadatas.stream() |
| 4673 | + .collect(Collectors.toMap(fm -> fm.getDataFile().getId(), fm -> fm)); |
| 4674 | + |
| 4675 | + boolean publicInstall = settingsSvc.isTrueForKey(SettingsServiceBean.Key.PublicInstall, false); |
| 4676 | + |
| 4677 | + int filesUpdated = 0; |
| 4678 | + for (JsonValue jsonValue : jsonArray) { |
| 4679 | + JsonObject jsonObj = jsonValue.asJsonObject(); |
| 4680 | + Long fileId = jsonObj.getJsonNumber("dataFileId").longValueExact(); |
| 4681 | + |
| 4682 | + FileMetadata fmd = fileMetadataMap.get(fileId); |
| 4683 | + |
| 4684 | + if (fmd == null) { |
| 4685 | + return error(BAD_REQUEST, |
| 4686 | + "File with dataFileId " + fileId + " is not part of the current version of the Dataset."); |
| 4687 | + } |
| 4688 | + |
| 4689 | + // Handle restriction |
| 4690 | + if (jsonObj.containsKey("restrict")) { |
| 4691 | + boolean restrict = jsonObj.getBoolean("restrict"); |
| 4692 | + if (restrict != fmd.isRestricted()) { |
| 4693 | + if (publicInstall && restrict) { |
| 4694 | + return error(BAD_REQUEST, "Restricting files is not permitted on a public installation."); |
| 4695 | + } |
| 4696 | + fmd.setRestricted(restrict); |
| 4697 | + if (!fmd.getDataFile().isReleased()) { |
| 4698 | + fmd.getDataFile().setRestricted(restrict); |
| 4699 | + } |
| 4700 | + |
| 4701 | + } else { |
| 4702 | + // This file is already restricted or already unrestricted |
| 4703 | + String text = restrict ? "restricted" : "unrestricted"; |
| 4704 | + return error(BAD_REQUEST, "File (dataFileId:" + fileId + ") is already " + text); |
| 4705 | + } |
| 4706 | + } |
| 4707 | + |
| 4708 | + // Load optional params |
| 4709 | + OptionalFileParams optionalFileParams = new OptionalFileParams(jsonObj.toString()); |
| 4710 | + |
| 4711 | + // Check for filename conflicts |
| 4712 | + String incomingLabel = null; |
| 4713 | + if (jsonObj.containsKey("label")) { |
| 4714 | + incomingLabel = jsonObj.getString("label"); |
| 4715 | + } |
| 4716 | + String incomingDirectoryLabel = null; |
| 4717 | + if (jsonObj.containsKey("directoryLabel")) { |
| 4718 | + incomingDirectoryLabel = jsonObj.getString("directoryLabel"); |
| 4719 | + } |
| 4720 | + String existingLabel = fmd.getLabel(); |
| 4721 | + String existingDirectoryLabel = fmd.getDirectoryLabel(); |
| 4722 | + String pathPlusFilename = IngestUtil.getPathAndFileNameToCheck(incomingLabel, incomingDirectoryLabel, |
| 4723 | + existingLabel, existingDirectoryLabel); |
| 4724 | + |
| 4725 | + // Create a copy of the fileMetadataMap without the current fmd |
| 4726 | + Map<Long, FileMetadata> fileMetadataMapCopy = new HashMap<>(fileMetadataMap); |
| 4727 | + fileMetadataMapCopy.remove(fileId); |
| 4728 | + |
| 4729 | + List<FileMetadata> fmdListMinusCurrentFile = new ArrayList<>(fileMetadataMapCopy.values()); |
| 4730 | + |
| 4731 | + if (IngestUtil.conflictsWithExistingFilenames(pathPlusFilename, fmdListMinusCurrentFile)) { |
| 4732 | + return error(BAD_REQUEST, BundleUtil.getStringFromBundle("files.api.metadata.update.duplicateFile", |
| 4733 | + Arrays.asList(pathPlusFilename))); |
| 4734 | + } |
| 4735 | + |
| 4736 | + // Apply optional params |
| 4737 | + optionalFileParams.addOptionalParams(fmd); |
| 4738 | + |
| 4739 | + // Store updated FileMetadata |
| 4740 | + fileMetadataMap.put(fileId, fmd); |
| 4741 | + filesUpdated++; |
| 4742 | + } |
| 4743 | + |
| 4744 | + latestVersion.setFileMetadatas(new ArrayList<>(fileMetadataMap.values())); |
| 4745 | + // Update the dataset version with all changes |
| 4746 | + UpdateDatasetVersionCommand updateCmd = new UpdateDatasetVersionCommand(dataset, req); |
| 4747 | + dataset = execCommand(updateCmd); |
| 4748 | + |
| 4749 | + return ok("File metadata updates have been completed for " + filesUpdated + " files."); |
| 4750 | + } catch (WrappedResponse wr) { |
| 4751 | + return error(BAD_REQUEST, |
| 4752 | + "An error has occurred attempting to update the requested DataFiles, likely related to permissions."); |
| 4753 | + } catch (JsonException ex) { |
| 4754 | + logger.log(Level.WARNING, "Dataset metadata update: exception while parsing JSON: {0}", ex); |
| 4755 | + return error(BAD_REQUEST, BundleUtil.getStringFromBundle("file.addreplace.error.parsing")); |
| 4756 | + } catch (DataFileTagException de) { |
| 4757 | + return error(BAD_REQUEST, de.getMessage()); |
| 4758 | + }catch (Exception e) { |
| 4759 | + logger.log(Level.WARNING, "Dataset metadata update: exception while processing:{0}", e); |
| 4760 | + return error(Response.Status.INTERNAL_SERVER_ERROR, "Error updating metadata for DataFiles: " + e); |
| 4761 | + } |
| 4762 | + } |
4617 | 4763 | /** |
4618 | 4764 | * API to find curation assignments and statuses |
4619 | 4765 | * |
|
0 commit comments