diff --git a/app/aem/core/src/main/java/com/cognifide/apm/core/endpoints/ScriptMoveServlet.java b/app/aem/core/src/main/java/com/cognifide/apm/core/endpoints/ScriptMoveServlet.java index 3890a70f..671bc0d0 100644 --- a/app/aem/core/src/main/java/com/cognifide/apm/core/endpoints/ScriptMoveServlet.java +++ b/app/aem/core/src/main/java/com/cognifide/apm/core/endpoints/ScriptMoveServlet.java @@ -23,9 +23,14 @@ import com.cognifide.apm.core.Property; import com.cognifide.apm.core.endpoints.response.ResponseEntity; import com.cognifide.apm.core.endpoints.utils.RequestProcessor; +import com.cognifide.apm.core.scripts.ScriptStorageImpl; import com.day.cq.commons.jcr.JcrConstants; import com.day.cq.commons.jcr.JcrUtil; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.jcr.Session; import javax.servlet.Servlet; import org.apache.commons.lang3.StringUtils; @@ -38,6 +43,8 @@ import org.apache.sling.models.factory.ModelFactory; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Component( service = Servlet.class, @@ -50,6 +57,14 @@ ) public class ScriptMoveServlet extends SlingAllMethodsServlet { + private static final Logger LOGGER = LoggerFactory.getLogger(ScriptMoveServlet.class); + + private static final Pattern SCRIPT_PATTERN = Pattern.compile("[0-9a-zA-Z_\\-]+\\.apm"); + + private static final Pattern FOLDER_PATTERN = Pattern.compile("[0-9a-zA-Z_\\-]+"); + + private static final Pattern DESTINATION_PATTERN = Pattern.compile("(/[0-9a-zA-Z_\\-]+)+"); + @Reference private ModelFactory modelFactory; @@ -62,19 +77,24 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse String rename = containsExtension(form.getPath()) ? (form.getRename() + (containsExtension(form.getRename()) ? "" : Apm.FILE_EXT)) : JcrUtil.createValidName(form.getRename()); + validate(dest, rename); String destPath = String.format("%s/%s", dest, rename); if (!StringUtils.equals(form.getPath(), destPath)) { destPath = createUniquePath(destPath, resourceResolver); session.move(form.getPath(), destPath); session.save(); + LOGGER.info("Item successfully moved from {} to {}", form.getPath(), destPath); } if (!containsExtension(form.getPath())) { ValueMap valueMap = resourceResolver.getResource(destPath).adaptTo(ModifiableValueMap.class); + String prevTitle = valueMap.get(JcrConstants.JCR_TITLE, String.class); valueMap.put(JcrConstants.JCR_TITLE, form.getRename()); + resourceResolver.commit(); + LOGGER.info("Item successfully renamed from {} to {}", prevTitle, form.getRename()); } - resourceResolver.commit(); return ResponseEntity.ok("Item successfully moved"); } catch (Exception e) { + LOGGER.error("Errors while moving item", e); return ResponseEntity.badRequest(StringUtils.defaultString(e.getMessage(), "Errors while moving item")); } }); @@ -93,4 +113,16 @@ private String createUniquePath(String pathWithExtension, ResourceResolver resol } return path + (counter > 0 ? counter : "") + extension; } + + private void validate(String path, String name) { + List validationErrors = new ArrayList<>(); + ScriptStorageImpl.ensurePropertyMatchesPattern(validationErrors, "rename", name, + containsExtension(name) ? SCRIPT_PATTERN : FOLDER_PATTERN); + ScriptStorageImpl.ensurePropertyMatchesPattern(validationErrors, "destination", path, DESTINATION_PATTERN); + if (!validationErrors.isEmpty()) { + String message = validationErrors.stream() + .collect(Collectors.joining("\n", "Validation errors:\n", "")); + throw new RuntimeException(message); + } + } } diff --git a/app/aem/core/src/main/java/com/cognifide/apm/core/scripts/ScriptStorageImpl.java b/app/aem/core/src/main/java/com/cognifide/apm/core/scripts/ScriptStorageImpl.java index ebb10e84..c0fb506c 100644 --- a/app/aem/core/src/main/java/com/cognifide/apm/core/scripts/ScriptStorageImpl.java +++ b/app/aem/core/src/main/java/com/cognifide/apm/core/scripts/ScriptStorageImpl.java @@ -62,7 +62,7 @@ public class ScriptStorageImpl implements ScriptStorage { private static final Pattern FILE_NAME_PATTERN = Pattern.compile("[0-9a-zA-Z_\\-]+\\.apm"); - private static final Pattern PATH_PATTERN = Pattern.compile("/[0-9a-zA-Z_\\-/]+"); + private static final Pattern PATH_PATTERN = Pattern.compile("(/[0-9a-zA-Z_\\-]+)+"); private static final Charset SCRIPT_ENCODING = StandardCharsets.UTF_8; @@ -173,7 +173,7 @@ private List validate(FileDescriptor file) { return errors; } - private static void ensurePropertyMatchesPattern(List errors, String property, String value, + public static void ensurePropertyMatchesPattern(List errors, String property, String value, Pattern pattern) { if (!pattern.matcher(value).matches()) { errors.add(String.format("Invalid %s: \"%s\"", property, value)); diff --git a/app/aem/core/src/main/java/com/cognifide/apm/core/services/ScriptsResourceChangeListener.java b/app/aem/core/src/main/java/com/cognifide/apm/core/services/ScriptsResourceChangeListener.java index 705c384e..78a2f6e0 100644 --- a/app/aem/core/src/main/java/com/cognifide/apm/core/services/ScriptsResourceChangeListener.java +++ b/app/aem/core/src/main/java/com/cognifide/apm/core/services/ScriptsResourceChangeListener.java @@ -102,14 +102,17 @@ public void onChange(List changes) { SlingHelper.operateTraced(resolverProvider, resolver -> { // rename copy/paste folders - changes.stream() - .filter(change -> change.getType() == ResourceChange.ChangeType.ADDED) - .map(change -> resolver.getResource(change.getPath())) - .filter(ScriptsRowModel::isFolder) - .forEach(resource -> { - ValueMap valueMap = resource.adaptTo(ModifiableValueMap.class); - valueMap.put(JcrConstants.JCR_TITLE, resource.getName()); - }); + boolean onlyAdded = changes.stream() + .allMatch(change -> change.getType() == ResourceChange.ChangeType.ADDED); + if (onlyAdded) { + changes.stream() + .map(change -> resolver.getResource(change.getPath())) + .filter(ScriptsRowModel::isFolder) + .forEach(resource -> { + ValueMap valueMap = resource.adaptTo(ModifiableValueMap.class); + valueMap.put(JcrConstants.JCR_TITLE, resource.getName()); + }); + } //register schedule or cron expression scripts changes.stream() .filter(change -> StringUtils.endsWith(change.getPath(), Apm.FILE_EXT))