Skip to content

Commit

Permalink
Add list function for renaming media of multiple processes
Browse files Browse the repository at this point in the history
  • Loading branch information
solth committed Nov 15, 2023
1 parent efa5917 commit c516746
Show file tree
Hide file tree
Showing 20 changed files with 533 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

package org.kitodo.exceptions;

/**
* This exception is thrown when too many processes are selected for a specific list action.
*/
public class TooManyProcessesSelectedException extends RuntimeException {

/**
* Constructor with message.
*
* @param message String containing exception message
*/
public TooManyProcessesSelectedException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,12 @@ public enum ParameterCore implements ParameterInterface {
* Secret is used to encrypt or decrypt LDAP manager passwords which are stored in the database in encrypted form.
* Once the secret value is set, it should not be changed since encrypted data can no longer be decrypted.
*/
SECURITY_SECRET_LDAPMANAGERPASSWORD(new Parameter<>("security.secret.ldapManagerPassword", ""));
SECURITY_SECRET_LDAPMANAGERPASSWORD(new Parameter<>("security.secret.ldapManagerPassword", "")),

/* Optional parameter can be used to limit the number of processes for which media renaming can be conducted as a
* list function. Values different from positive integers are interpreted as "unlimited".
*/
MAX_NUMBER_OF_PROCESSES_FOR_MEDIA_RENAMING(new Parameter<>("maxNumberOfProcessesForMediaRenaming", -1));

private final Parameter<?> parameter;

Expand Down
29 changes: 29 additions & 0 deletions Kitodo/src/main/java/org/kitodo/production/forms/ProcessForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.kitodo.data.exceptions.DataException;
import org.kitodo.exceptions.InvalidImagesException;
import org.kitodo.exceptions.MediaNotFoundException;
import org.kitodo.exceptions.TooManyProcessesSelectedException;
import org.kitodo.production.controller.SecurityAccessController;
import org.kitodo.production.dto.ProcessDTO;
import org.kitodo.production.dto.TaskDTO;
Expand Down Expand Up @@ -1182,4 +1183,32 @@ private int getProcessId(Object process) {
public FilterMenu getFilterMenu() {
return filterMenu;
}

/**
* Rename media files of all selected processes.
*/
public void renameMedia() {
try {
ServiceManager.getFileService().renameMedia(getSelectedProcesses());
PrimeFaces.current().executeScript("PF('notifications').renderMessage({'summary':'"
+ Helper.getTranslation("renamingMediaFilesOfSelectedProcessesStarted")
+ "','severity':'info'})");
} catch (TooManyProcessesSelectedException e) {
Helper.setErrorMessage(e);
}
}

/**
* Return media renaming confirmation message with number of processes affected.
*
* @return media renaming confirmation message
*/
public String getMediaRenamingConfirmMessage() {
return Helper.getTranslation("renameMediaForProcessesConfirmMessage",
String.valueOf(getSelectedProcesses().size()));
}

public void checkNumberOfProcessesSelectedForMediaRenaming() {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand All @@ -33,6 +34,7 @@
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
Expand All @@ -58,17 +60,21 @@
import org.kitodo.exceptions.CommandException;
import org.kitodo.exceptions.InvalidImagesException;
import org.kitodo.exceptions.MediaNotFoundException;
import org.kitodo.exceptions.TooManyProcessesSelectedException;
import org.kitodo.production.dto.ProcessDTO;
import org.kitodo.production.file.BackupFileRotation;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.helper.metadata.ImageHelper;
import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetsModsDigitalDocumentHelper;
import org.kitodo.production.helper.metadata.pagination.Paginator;
import org.kitodo.production.helper.tasks.TaskManager;
import org.kitodo.production.metadata.MetadataEditor;
import org.kitodo.production.metadata.MetadataLock;
import org.kitodo.production.model.Subfolder;
import org.kitodo.production.services.ServiceManager;
import org.kitodo.production.services.command.CommandService;
import org.kitodo.production.services.data.RulesetService;
import org.kitodo.production.thread.RenameMediaThread;
import org.kitodo.serviceloader.KitodoServiceLoader;
import org.kitodo.utils.MediaUtil;

Expand Down Expand Up @@ -1524,6 +1530,44 @@ public int renameMediaFiles(Process process, Workpiece workpiece, DualHashBidiMa
return numberOfRenamedMedia;
}

/**
* Rename media files of given processes.
* @param processes Processes whose media is renamed
*/
public void renameMedia(List<Process> processes) {
processes = lockAndSortProcessesForRenaming(processes);
int limit = ConfigCore.getIntParameterOrDefaultValue(ParameterCore.MAX_NUMBER_OF_PROCESSES_FOR_MEDIA_RENAMING);
if (0 < limit && limit < processes.size()) {
throw new TooManyProcessesSelectedException(
Helper.getTranslation("tooManyProcessesSelectedForMediaRenaming", String.valueOf(limit),
String.valueOf(processes.size())));
} else {
TaskManager.addTask(new RenameMediaThread(processes));
}
}

private List<Process> lockAndSortProcessesForRenaming(List<Process> processes) {
processes.sort(Comparator.comparing(Process::getId));
List<Integer> lockedProcesses = new LinkedList<>();
for (Process process : processes) {
int processId = process.getId();
if (MetadataLock.isLocked(processId)) {
lockedProcesses.add(processId);
if (ConfigCore.getBooleanParameterOrDefaultValue(ParameterCore.ANONYMIZE)) {
logger.error("Unable to lock process " + processId + " for media renaming because it is currently "
+ "being worked on by another user");
} else {
User currentUser = MetadataLock.getLockUser(processId);
logger.error("Unable to lock process " + processId + " for media renaming because it is currently "
+ "being worked on by another user (" + currentUser.getFullName() + ")");
}
} else {
MetadataLock.setLocked(processId, ServiceManager.getUserService().getCurrentUser());
}
}
return processes.stream().filter(p -> !lockedProcesses.contains(p.getId())).collect(Collectors.toList());
}

/**
* Revert renaming of media files when the user leaves the metadata editor without saving. This method uses a
* provided map object to rename media files identified by the map entries values to the corresponding map entries
Expand All @@ -1534,6 +1578,7 @@ public int renameMediaFiles(Process process, Workpiece workpiece, DualHashBidiMa
*/
public void revertRenaming(BidiMap<URI, URI> filenameMappings, Workpiece workpiece) {
// revert media variant URIs for all media files in workpiece to previous, original values
logger.info("Reverting to original media filenames of process " + workpiece.getId());
for (PhysicalDivision physicalDivision : workpiece
.getAllPhysicalDivisionChildrenFilteredByTypes(PhysicalDivision.TYPES)) {
for (Entry<MediaVariant, URI> mediaVariantURIEntry : physicalDivision.getMediaFiles().entrySet()) {
Expand All @@ -1545,8 +1590,14 @@ public void revertRenaming(BidiMap<URI, URI> filenameMappings, Workpiece workpie
try {
List<URI> tempUris = new LinkedList<>();
for (Entry<URI, URI> mapping : filenameMappings.entrySet()) {
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()
+ TEMP_EXTENSION));
if (mapping.getKey().toString().endsWith(TEMP_EXTENSION)) {
// if current URI has '.tmp' extension, directly revert to original name (without '.tmp' extension)
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()));
} else {
// rename to new filename with '.tmp' extension otherwise
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()
+ TEMP_EXTENSION));
}
}
for (URI tempUri : tempUris) {
fileManagementModule.rename(tempUri, StringUtils.removeEnd(tempUri.toString(), TEMP_EXTENSION));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

package org.kitodo.production.thread;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Objects;

import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.api.dataformat.Workpiece;
import org.kitodo.data.database.beans.Process;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.helper.LocaleHelper;
import org.kitodo.production.helper.tasks.EmptyTask;
import org.kitodo.production.metadata.MetadataLock;
import org.kitodo.production.services.ServiceManager;

/**
* This class is used to rename media files of multiple processes in a separate thread whose progress can be monitored
* in the task manager.
*/
public class RenameMediaThread extends EmptyTask {

private static final Logger logger = LogManager.getLogger(RenameMediaThread.class);
private final List<Process> processes;
private static final String THREAD_NAME = "renameMediaThread";
private static final String ERRORS_OCCURRED_KEY = "errorsOccurredCheckLog";
private static final String PROCESSES = "processes";

public RenameMediaThread(List<Process> processes) {
super(processes.size() + " " + Helper.getString(LocaleHelper.getCurrentLocale(), PROCESSES));
this.processes = processes;
}

@Override
protected void setNameDetail(String detail) {
String localThreadName = Helper.getString(LocaleHelper.getCurrentLocale(), THREAD_NAME);
super.setName(localThreadName + ": " + detail);
}

/**
* Run method of this thread. Iterates over processes and renames all media files in each process using the regular
* "media renaming" functionality of the FileService.
*/
@Override
public void run() {
for (Process process : processes) {
int processId = process.getId();
URI metaXmlUri = ServiceManager.getProcessService().getMetadataFileUri(process);
DualHashBidiMap<URI, URI> renamingMap = new DualHashBidiMap<>();
Workpiece workpiece = null;
try {
workpiece = ServiceManager.getMetsService().loadWorkpiece(metaXmlUri);
int numberOfRenamedFiles = ServiceManager.getFileService().renameMediaFiles(process, workpiece,
renamingMap);
try (OutputStream out = ServiceManager.getFileService().write(metaXmlUri)) {
ServiceManager.getMetsService().save(workpiece, out);
logger.info("Renamed " + numberOfRenamedFiles + " media files for process " + process.getId());
}
} catch (IOException | URISyntaxException e) {
logger.error(e.getMessage());
String nameDetailMessage = processes.size()
+ " " + Helper.getString(LocaleHelper.getCurrentLocale(), PROCESSES)
+ " (" + Helper.getString(LocaleHelper.getCurrentLocale(), ERRORS_OCCURRED_KEY) + ")";
this.setNameDetail(nameDetailMessage);
if (Objects.nonNull(workpiece)) {
ServiceManager.getFileService().revertRenaming(renamingMap.inverseBidiMap(), workpiece);
}
}
MetadataLock.setFree(processId);
setProgress((100 / processes.size()) * (processes.indexOf(process) + 1));
}
setProgress(100);
}
}
4 changes: 4 additions & 0 deletions Kitodo/src/main/resources/kitodo_config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,7 @@ security.secret.ldapManagerPassword=
# largest data tables of tasks by processingBegin and process by creation date are considered.
# The dates can be defined & separated in the format YYYY, YYYY-MM or YYYY-MM-DD e.g. 2017-05-10,2018-06,2022
# database.subset.dates=

# This optional parameter can be used to limit the number of processes for which media renaming can be conducted as a
# list function. Values different from positive integers are interpreted as "unlimited".
#maxNumberOfProcessesForMediaRenaming=10000
2 changes: 2 additions & 0 deletions Kitodo/src/main/resources/messages/errors_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ noUserInStep=Der Aufgabe {0} wurden keine Nutzer zugeordnet.

# O
errorOccurred=Es ist ein Fehler aufgetreten:
errorsOccurredCheckLog=Es sind Fehler aufgetreten. Bitte \u00FCberprf\u00FCfen Sie kitodo.log f\u00FCr zus\u00E4tzliche Details.

# P
errorParsingFile=Parsingfehler: verschiedene {0} in der Datei (''{1}'' & ''{2}'').
Expand Down Expand Up @@ -167,6 +168,7 @@ templateAssignedError=Der Workflow kann nicht gel\u00F6scht werden, da diesem Pr
templateTitleAlreadyInUse=Der Produktionsvorlagentitel wird bereits verwendet.
templateTitleEmpty=Kein Produktionsvorlagentitel angegeben.
tooManyBatchesSelected=Es sind mehrere Batches ausgew\u00E4hlt. W\u00E4hlen Sie genau einen Batch aus, um diese Funktion zu nutzen.
tooManyProcessesSelectedForMediaRenaming=Die maximal erlaubte Anzahl an Vorg\u00E4ngen ({0}) f\u00FCr die Medienumbenennung wurde \u00FCberschritten ({1}).

# U
errorUploading=Fehler beim Hochladen von ''{0}''.
Expand Down
2 changes: 2 additions & 0 deletions Kitodo/src/main/resources/messages/errors_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ noUserInStep=No user assigned to step {0}.

# O
errorOccurred=An error has occurred:
errorsOccurredCheckLog=Errors occurred. Please check kitodo.log for Details.

# P
errorParsingFile=Error parsing: various {0} in the file (''{1}'' & ''{2}'').
Expand Down Expand Up @@ -166,6 +167,7 @@ templateAssignedError=The workflow could not be deleted because there are alread
templateTitleAlreadyInUse=The template title is already in use.
templateTitleEmpty=No template title stated.
tooManyBatchesSelected=Multiple batches are selected. To use this function, please select one batch only.
tooManyProcessesSelectedForMediaRenaming=Maximum number of allowed processes for media renaming ({0}) exceeded ({1}).

# U
errorUploading=Error uploading ''{0}''.
Expand Down
5 changes: 4 additions & 1 deletion Kitodo/src/main/resources/messages/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ dataEditor.removeElement.noConsecutivePagesSelected=Strukturelemente k\u00F6nnen
dataEditor.selectMetadataTask=Aufgabe w\u00E4hlen
dataEditor.layoutSavedSuccessfullyTitle=Aktuelle Spaltenaufteilung erfolgreich gespeichert
dataEditor.layoutSavedSuccessfullyText=Ihre aktuellen Metadaten-Editor-Einstellungen wurden erfolgreich gespeichert! Sie werden f\u00FCr alle zuk\u00FCnftigen Aufgaben dieses Typs wiederverwendet.
dataEditor.renameMedia=Medien umbenennen
dataEditor.renamingMediaComplete=Das Umbenennen der Medien ist abgeschlossen
dataEditor.renamingMediaError=Beim Umbenennen der Medien ist ein Fehler aufgetreten
dataEditor.renamingMediaText={0} Mediendateien in {1} Ordnern wurden umbenannt. Bitte Speichern Sie den Vorgang. Andernfalls werden die Dateiumbennungen beim Schlie\u00DFen des Metadateneditors verworfen.
Expand Down Expand Up @@ -961,6 +960,8 @@ removePhysicalDivision=Physisches Strukturelement entfernen
removeRole=Rolle entfernen
removeUserFromGroup=Benutzer aus der Benutzergruppe l\u00F6schen
renameBatch=Batch umbenennen
renameMediaFiles=Medien umbenennen
renamingMediaFilesOfSelectedProcessesStarted=Das Umbenennen der Medien f\u00FCr die ausgew\u00E4hlten Vorg\u00E4nge wurde erfolgreich gestartet.
requiredField=Mit * gekennzeichnete Felder sind Pflichtfelder
reset=Zur\u00FCcksetzen
resultPDF=Ergebnis-PDF
Expand Down Expand Up @@ -1281,6 +1282,8 @@ assignTask=Aufgabe zuweisen
overrideTask=Aufgabe \u00FCbernehmen
superviseTask=Aufgabe beobachten
renameMedia=Medien umbenennen
renameMediaThread=Medien umbenennen
renameMediaForProcessesConfirmMessage=Die Mediendateien von {0} Vorg\u00E4ngen werden gem\u00E4ss ihrer Reihenfolge in den jeweiligen Vorg\u00E4ngen umbenannt. Diese Aktion kann nicht r\u00FCckg\u00E4ngig gemacht werden. M\u00F6chten Sie fortfahren?
resetWorkflow=Workflow zur\u00FCcksetzen
runKitodoScript=KitodoScript ausf\u00FChren

Expand Down
5 changes: 4 additions & 1 deletion Kitodo/src/main/resources/messages/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ dataEditor.removeElement.noConsecutivePagesSelected=Select consecutive pages to
dataEditor.selectMetadataTask=Select task
dataEditor.layoutSavedSuccessfullyTitle=Current layout successfully saved
dataEditor.layoutSavedSuccessfullyText=Your current editor settings have been saved successfully and will be applied to all future tasks of the same type.
dataEditor.renameMedia=Rename media
dataEditor.renamingMediaComplete=Finished renaming media
dataEditor.renamingMediaError=An error occurred while renaming media files
dataEditor.renamingMediaText={0} media files in {1} folders have been renamed. Please click the 'Save' button to persist changes to the filenames. Otherwise the renaming will be reverted upon closing the editor.
Expand Down Expand Up @@ -962,6 +961,8 @@ removePhysicalDivision=Remove physical structure element
removeRole=Remove role
removeUserFromGroup=Delete user from group
renameBatch=Rename batch
renameMediaFiles=Rename media
renamingMediaFilesOfSelectedProcessesStarted=Renaming media files of selected processes started successfully.
requiredField=Fields marked with * are required
reset=Reset
resultPDF=Result PDF
Expand Down Expand Up @@ -1283,6 +1284,8 @@ overrideTask=Take on task
superviseTask=Watch task
resetWorkflow=Reset workflow
renameMedia=Rename media
renameMediaThread=Rename media
renameMediaForProcessesConfirmMessage=The media files of {0} processes will be renamed according to their order in the individual processes. This change cannot be reverted. To you want to continue?
runKitodoScript=Execute KitodoScript

viewAllAuthorities=View all authorities
Expand Down
Loading

0 comments on commit c516746

Please sign in to comment.