diff --git a/CHANGELOG.md b/CHANGELOG.md index 785f222695..571a10cd0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com) ## Unreleased ([details][unreleased changes details]) +## 6.1.0 - 2023-09-08 + +## Added + +- #3159 - Add PageProperty annotation for Sling Models +- #3170 - Added a new MCP tool to bulk tag AEM content pages via an Excel file input. + ## Fixed +- #3147 - Fixed setting initial content-type when importing CFs from a spreadsheet - #3040 - Fixed bug where namespaced multi-fields would have the namespace 2 times - #3140 - Fixed issue where malformed MCP process nodes can cause a NPE that breaks the entire MPC reporting UI. Now displays more friendly values in UI to help remove the invalid nodes. - #3150 - Support for case-insensitive redirect rules ( [NC] flag equivalent of apache) diff --git a/all/pom.xml b/all/pom.xml index 316f7f5b33..098119bbd4 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT diff --git a/bundle/pom.xml b/bundle/pom.xml index 43f83c3c3e..c0d2b8c9ec 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java new file mode 100644 index 0000000000..e92f23dc46 --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java @@ -0,0 +1,254 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2023 Adobe + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.adobe.acs.commons.mcp.impl.processes; + +import com.adobe.acs.commons.fam.ActionManager; +import com.adobe.acs.commons.mcp.ProcessDefinition; +import com.adobe.acs.commons.mcp.ProcessInstance; +import com.adobe.acs.commons.mcp.form.FileUploadComponent; +import com.adobe.acs.commons.mcp.form.FormField; +import com.adobe.acs.commons.mcp.model.GenericBlobReport; +import com.adobe.acs.commons.mcp.util.StringUtil; +import com.day.cq.tagging.Tag; +import com.day.cq.wcm.api.Page; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.RepositoryException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Iterator; +import java.util.HashSet; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The type Bulk page tagger. + */ +public class BulkPageTagger extends ProcessDefinition implements Serializable { + private static final Logger log = LoggerFactory.getLogger(BulkPageTagger.class); + private static final long serialVersionUID = 798823856839772874L; + + /** + * The constant NAME. + */ + public static final String NAME = "Bulk Page Tagger"; + + /** + * The Excel file. + */ + @FormField( + name = "Excel File", + description = "Provide the .xlsx file that defines the content pages and the corresponding cq:tags to be added on the pages", + component = FileUploadComponent.class, + options = {"mimeTypes=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "required"} + ) + public transient InputStream excelFile = null; + + + @Override + public void init() throws RepositoryException { + // Nothing to be done here. + + } + + + @Override + public void buildProcess(ProcessInstance instance, ResourceResolver rr) throws LoginException { + report.setName(instance.getName()); + instance.getInfo().setDescription("Bulk Tag AEM content Pages"); + instance.defineCriticalAction("Parse Excel File", rr, this::parseExcel); + instance.defineCriticalAction("Add Tags to Content Pages", rr, this::tagPages); + + } + + + /** + * The Page tag mapping dataStructure. + */ + transient volatile HashMap pageTagMapping = new LinkedHashMap<>(); + + /** + * Parse input excel. + * + * @param manager the manager + * @throws Exception the exception + */ + @SuppressWarnings("squid:S112") + public void parseExcel(ActionManager manager) throws Exception { + manager.withResolver(rr -> { + final XSSFWorkbook workbook = new XSSFWorkbook(excelFile); + final XSSFSheet sheet = workbook.getSheetAt(0); + + final Iterator rows = sheet.rowIterator(); + final String tagsRootPath = new TagCreator.TagRootResolver(rr).getTagsLocationPath(); + + + if (tagsRootPath == null) { + recordAction(ReportRowSatus.FAILED_TO_PARSE, + "Abandoning Tag parsing. Unable to determine AEM Tags root (/content/cq:tags vs /etc/tags). Please ensure the path exists and is accessible by the user running Tag Creator.", "N/A"); + return; + } + + while (rows.hasNext()) { + final Row row = rows.next(); + if (row.getCell(0) == null) { + break; + } + if (row.getRowNum() != 0 && row.getCell(0) != null) { + pageTagMapping.put(row.getCell(0).getStringCellValue(), row.getCell(1).getStringCellValue()); + } + } + + }); + + } + + + /** + * Tag pages from the excel file with cq:tags. + * + * @param manager the manager + * @throws Exception the exception + */ + @SuppressWarnings("squid:S112") + public void tagPages(ActionManager manager) throws Exception { + + manager.withResolver(rr -> { + + pageTagMapping.forEach((key, value) -> { + BulkPageTagger.ReportRowSatus status; + Resource resource = rr.getResource(key); + if (resource != null) { + Page page = resource.adaptTo(Page.class); + if (page != null) { + Tag[] existingPageTags = page.getTags(); + String[] tagIds = Stream.of(existingPageTags) + .map(Tag::getTagID) + .toArray(String[]::new); + Set updatedTags = Arrays.stream(value.split("[;\n]")) + .map(String::trim) + .collect(Collectors.toSet()); + updatedTags.addAll(Arrays.asList(tagIds)); + String[] updatedTagsArray = updatedTags.stream().toArray(String[]::new); + + ModifiableValueMap properties = page.getContentResource().adaptTo(ModifiableValueMap.class); + properties.put(com.day.cq.tagging.TagConstants.PN_TAGS, updatedTagsArray); + try { + rr.commit(); + status = ReportRowSatus.UPDATED_EXISTING; + recordAction(status, page.getPath(), Arrays.toString(updatedTagsArray)); + } catch (PersistenceException e) { + status = ReportRowSatus.FAILED_TO_UPDATE; + recordAction(status, page.getPath(), Arrays.toString(updatedTagsArray)); + log.error(String.format("Unable to add tags to page with page path - %s ", page.getPath())); + } + + + } + + } + + }); + }); + } + + + /** + * Reporting + **/ + + + private final transient GenericBlobReport report = new GenericBlobReport(); + + private final transient ArrayList> reportRows = new ArrayList<>(); + + private enum ReportColumns { + /** + * Status report columns. + */ + STATUS, + /** + * Page path report columns. + */ + PAGE_PATH, + /** + * Tags array report columns. + */ + TAGS_ARRAY + } + + /** + * The enum Report row satus. + */ + public enum ReportRowSatus { + /** + * Created report row satus. + */ + CREATED, + /** + * Updated existing report row satus. + */ + UPDATED_EXISTING, + /** + * Failed to parse report row satus. + */ + FAILED_TO_PARSE, + /** + * Failed to update report row satus. + */ + FAILED_TO_UPDATE + } + + + private void recordAction(BulkPageTagger.ReportRowSatus status, String pagePath, String tags) { + final EnumMap row = new EnumMap<>(BulkPageTagger.ReportColumns.class); + + row.put(BulkPageTagger.ReportColumns.STATUS, StringUtil.getFriendlyName(status.name())); + row.put(ReportColumns.PAGE_PATH, pagePath); + row.put(ReportColumns.TAGS_ARRAY, tags); + + reportRows.add(row); + } + + + @Override + public void storeReport(ProcessInstance instance, ResourceResolver rr) throws RepositoryException, PersistenceException { + report.setRows(reportRows, BulkPageTagger.ReportColumns.class); + report.persist(rr, instance.getPath() + "/jcr:content/report"); + } + + +} diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java new file mode 100644 index 0000000000..0c9ba7c79d --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java @@ -0,0 +1,39 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2023 Adobe + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.adobe.acs.commons.mcp.impl.processes; + +import com.adobe.acs.commons.mcp.ProcessDefinitionFactory; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +@Component +@Service(ProcessDefinitionFactory.class) +public class BulkPageTaggerFactory extends ProcessDefinitionFactory { + + @Override + public String getName() { + return BulkPageTagger.NAME; + } + + @Override + protected BulkPageTagger createProcessDefinitionInstance() { + return new BulkPageTagger(); + } +} diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java index 2510cf8a04..efe48f9ff5 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java +++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java @@ -33,7 +33,6 @@ import com.adobe.cq.dam.cfm.FragmentTemplate; import com.day.cq.commons.jcr.JcrConstants; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; @@ -48,22 +47,17 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.reflect.MethodUtils; import org.apache.sling.api.request.RequestParameter; import org.apache.sling.api.resource.LoginException; import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Import a series of content fragments from a spreadsheet */ public class ContentFragmentImport extends ProcessDefinition { - private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentImport.class); - public enum ReportColumns { ITEM, ACTION, DESCRIPTION, COUNT } @@ -313,8 +307,14 @@ private void setContentElements(ContentFragment cf, Map row, ContentElement conte protected ContentFragment getOrCreateFragment(Resource parent, Resource template, String name, String title) throws ContentFragmentException { Resource fragmentResource = parent.getChild(name); if (fragmentResource == null) { - try { - FragmentTemplate fragmentTemplate = template.adaptTo(FragmentTemplate.class); -// TODO: Replace this reflection hack with the proper method once ACS Commons doesn't support 6.2 anymore - return (ContentFragment) MethodUtils.invokeMethod(fragmentTemplate, "createFragment", parent, name, title); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { - LOG.error("Unable to call createFragment method -- Is this 6.3 or newer?", ex); - return null; - } + FragmentTemplate fragmentTemplate = template.adaptTo(FragmentTemplate.class); + return fragmentTemplate.createFragment(parent, name, title); } else { return fragmentResource.adaptTo(ContentFragment.class); } diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java index a0b5b24808..a99caf95ba 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java @@ -18,6 +18,7 @@ package com.adobe.acs.commons.models.injectors.annotation; +import com.adobe.acs.commons.models.injectors.impl.HierarchicalPagePropertyInjector; import org.apache.commons.lang3.StringUtils; import org.apache.sling.models.annotations.Source; import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; @@ -39,14 +40,9 @@ @Target({METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) @InjectAnnotation -@Source(HierarchicalPageProperty.SOURCE) +@Source(HierarchicalPagePropertyInjector.SOURCE) public @interface HierarchicalPageProperty { - /** - * Source value used for this annotation. - * @see Source - */ - String SOURCE = "hierarchical-page-property"; /** * Specifies the name of the value from the value map to take. @@ -54,6 +50,12 @@ */ String value() default StringUtils.EMPTY; + /** + * Specifies if it should use the hierarchy to search for the page property. + * If false, it will only look at the current page. + */ + boolean inherit() default true; + /** * if set to REQUIRED injection is mandatory, if set to OPTIONAL injection is optional, in case of DEFAULT * the standard annotations ({@link org.apache.sling.models.annotations.Optional}, {@link org.apache.sling.models.annotations.Required}) are used. diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java new file mode 100644 index 0000000000..4e2f73a20c --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java @@ -0,0 +1,61 @@ +/* + * ACS AEM Commons + * + * Copyright (C) 2013 - 2023 Adobe + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.adobe.acs.commons.models.injectors.annotation; + + +import com.adobe.acs.commons.models.injectors.impl.HierarchicalPagePropertyInjector; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.models.annotations.Source; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.spi.injectorspecific.InjectAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Injects a page property. + * Note: not supported by the javax.Inject annotation because of performance reasons. Only direct annotation is supported. + */ +@Target({METHOD, FIELD, PARAMETER}) +@Retention(RUNTIME) +@InjectAnnotation +@Source(HierarchicalPagePropertyInjector.SOURCE) +public @interface PageProperty { + + + /** + * Specifies the name of the value from the value map to take. + * If empty, then the name is derived from the method or field. + */ + String value() default StringUtils.EMPTY; + + + /** + * if set to REQUIRED injection is mandatory, if set to OPTIONAL injection is optional, in case of DEFAULT + * the standard annotations ({@link org.apache.sling.models.annotations.Optional}, {@link org.apache.sling.models.annotations.Required}) are used. + * If even those are not available the default injection strategy defined on the {@link org.apache.sling.models.annotations.Model} applies. + * Default value = DEFAULT. + */ + InjectionStrategy injectionStrategy() default InjectionStrategy.DEFAULT; + +} diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java index 37ef6c49ff..706784875c 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java @@ -18,11 +18,13 @@ package com.adobe.acs.commons.models.injectors.impl; import com.adobe.acs.commons.models.injectors.annotation.HierarchicalPageProperty; +import com.adobe.acs.commons.models.injectors.annotation.PageProperty; import com.adobe.acs.commons.util.impl.ReflectionUtil; import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap; import com.day.cq.commons.inherit.InheritanceValueMap; import com.day.cq.wcm.api.Page; import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Source; import org.apache.sling.models.spi.DisposalCallbackRegistry; import org.apache.sling.models.spi.Injector; import org.osgi.framework.Constants; @@ -42,15 +44,22 @@ ) public class HierarchicalPagePropertyInjector implements Injector { + /** + * Source value used for injector + * + * @see Source + */ + public static final String SOURCE = "hierarchical-page-property"; + @Override public String getName() { - return HierarchicalPageProperty.SOURCE; + return SOURCE; } public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) { - if (!element.isAnnotationPresent(HierarchicalPageProperty.class)) { + if (!(element.isAnnotationPresent(HierarchicalPageProperty.class) || element.isAnnotationPresent(PageProperty.class))) { //skipping javax.Inject for performance reasons. Only supports direct injection. return null; } @@ -59,8 +68,12 @@ public Object getValue(Object adaptable, String name, Type declaredType, Annotat if (currentResource != null) { Resource adaptableRes = lookUpFromPage(currentResource); if (adaptableRes != null) { - InheritanceValueMap inheritanceValueMap = new HierarchyNodeInheritanceValueMap(adaptableRes); - return ReflectionUtil.convertValueMapValue(inheritanceValueMap, name, declaredType); + if (element.isAnnotationPresent(PageProperty.class) || !element.getAnnotation(HierarchicalPageProperty.class).inherit()) { + return ReflectionUtil.convertValueMapValue(adaptableRes.getValueMap(), name, declaredType); + } else { + InheritanceValueMap inheritanceValueMap = new HierarchyNodeInheritanceValueMap(adaptableRes); + return ReflectionUtil.convertValueMapValue(inheritanceValueMap, name, declaredType); + } } } diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java new file mode 100644 index 0000000000..3e08035a41 --- /dev/null +++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java @@ -0,0 +1,90 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2023 Adobe + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.adobe.acs.commons.mcp.impl.processes; + +import com.adobe.acs.commons.fam.ActionManager; +import com.adobe.acs.commons.functions.CheckedConsumer; +import io.wcm.testing.mock.aem.junit.AemContext; +import org.apache.jackrabbit.JcrConstants; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.testing.mock.sling.ResourceResolverType; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class BulkPageTaggerTest { + + @Rule + public final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK); + + private BulkPageTagger bulkPageTagger; + + @Mock + private ActionManager actionManager; + + @Before + public void setUp() throws Exception { + bulkPageTagger = new BulkPageTagger(); + bulkPageTagger.excelFile = getClass().getResourceAsStream("/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx"); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + CheckedConsumer method = (CheckedConsumer) invocation.getArguments()[0]; + method.accept(context.resourceResolver()); + return null; + } + }).when(actionManager).withResolver(any(CheckedConsumer.class)); + + } + + @Test + public void testParseExcel() throws Exception { + + final String tagsRootPath = com.day.cq.tagging.TagConstants.TAG_ROOT_PATH; + context.create().resource(tagsRootPath, JcrConstants.JCR_PRIMARYTYPE, "sling:Folder"); + context.resourceResolver().commit(); + bulkPageTagger.parseExcel(actionManager); + + final int expected = 9; + assertEquals(expected,bulkPageTagger.pageTagMapping.size() ); + } + + @Test + public void testTagPages() throws Exception { + + bulkPageTagger.parseExcel(actionManager); + context.create().page("/content/wknd/language-masters/en/about-us"); + context.create().resource("/content/wknd/language-masters/en/about-us/jcr:content", + JcrConstants.JCR_PRIMARYTYPE, + "cq:pagecontent","cq:tags","wknd-shared:activity/bulktagtest3;wknd-shared:activity/bulktagtest10"); + bulkPageTagger.tagPages(actionManager); + + } +} diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java index 07a1e4c13b..038ded4657 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java +++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java @@ -28,8 +28,6 @@ import java.util.Date; import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.TemporalAccessor; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java index 8c7698bf3e..82cc8676e9 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java +++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java @@ -37,6 +37,10 @@ import org.apache.sling.api.resource.Resource; import org.jetbrains.annotations.NotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + /** * Incomplete mock that provides just enough for basic testing */ @@ -47,6 +51,14 @@ public class MockContentFragment implements ContentFragment { String path; HashMap elements = new HashMap<>(); HashMap metadata = new HashMap<>(); + FragmentTemplate template; + + public MockContentFragment(){ + template = mock(FragmentTemplate.class); + ElementTemplate elementTemplate = mock(ElementTemplate.class); + doReturn("text/html").when(elementTemplate).getInitialContentType(); + doReturn(elementTemplate).when(template).getForElement(any(ContentElement.class)); + } @Override public Iterator getElements() { @@ -114,7 +126,7 @@ public Iterator listAllVariations() { @Override public FragmentTemplate getTemplate() { - return null; + return template; } @Override diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java index fc0e57ecc9..2ad5625cc3 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java @@ -17,10 +17,11 @@ */ package com.adobe.acs.commons.models.injectors.impl; -import com.adobe.acs.commons.models.injectors.annotation.HierarchicalPageProperty; import com.adobe.acs.commons.models.injectors.annotation.impl.HierarchicalPagePropertyAnnotationProcessorFactory; import com.adobe.acs.commons.models.injectors.impl.model.TestHierarchicalPagePropertiesModel; +import com.adobe.acs.commons.models.injectors.impl.model.TestPagePropertiesModel; import com.adobe.acs.commons.models.injectors.impl.model.impl.TestHierarchicalPagePropertiesModelModelImpl; +import com.adobe.acs.commons.models.injectors.impl.model.impl.TestPagePropertiesModelModelImpl; import io.wcm.testing.mock.aem.junit.AemContext; import org.apache.sling.api.resource.Resource; import org.apache.sling.models.spi.Injector; @@ -32,8 +33,7 @@ import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; @RunWith(MockitoJUnitRunner.class) public class HierarchicalPagePropertyInjectorTest { @@ -43,7 +43,8 @@ public class HierarchicalPagePropertyInjectorTest { @InjectMocks private HierarchicalPagePropertyInjector injector; - private TestHierarchicalPagePropertiesModel adapted; + private TestHierarchicalPagePropertiesModel hierarchicalModel; + private TestPagePropertiesModel pageModel; @Before public void setUp() throws Exception { @@ -53,19 +54,24 @@ public void setUp() throws Exception { context.registerService(Injector.class, injector); context.registerService(StaticInjectAnnotationProcessorFactory.class, new HierarchicalPagePropertyAnnotationProcessorFactory()); context.addModelsForClasses(TestHierarchicalPagePropertiesModelModelImpl.class); + context.addModelsForClasses(TestPagePropertiesModelModelImpl.class); Resource adaptable = context.request().getResource(); - adapted = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class); + hierarchicalModel = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class); + pageModel = adaptable.adaptTo(TestPagePropertiesModel.class); } @Test public void test_name() { - assertEquals(HierarchicalPageProperty.SOURCE, injector.getName()); + assertEquals(HierarchicalPagePropertyInjector.SOURCE, injector.getName()); } @Test public void test() { - assertNotNull(adapted); + assertNotNull(hierarchicalModel); + assertEquals("inherited!", hierarchicalModel.getHierarchicalPagePropertyString()); + assertNull(pageModel.getHierarchicalPagePropertyString()); + assertEquals("not inherited", hierarchicalModel.getPagePropertyString()); } diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java index 4365350c2b..b38acaebb2 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java @@ -23,7 +23,9 @@ public interface TestHierarchicalPagePropertiesModel { - String getPropertyString(); + String getPagePropertyString(); + + String getHierarchicalPagePropertyString(); String getUndefinedProperty(); diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java new file mode 100644 index 0000000000..757d52cfc2 --- /dev/null +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java @@ -0,0 +1,27 @@ +/* + * ACS AEM Commons + * + * Copyright (C) 2013 - 2023 Adobe + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.adobe.acs.commons.models.injectors.impl.model; + + +public interface TestPagePropertiesModel { + + String getPagePropertyString(); + + String getHierarchicalPagePropertyString(); + +} diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java index b786963cdb..ae255f5284 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java @@ -34,10 +34,13 @@ ) public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarchicalPagePropertiesModel { + @HierarchicalPageProperty + private String pagePropertyString; + @HierarchicalPageProperty private String hierarchicalPagePropertyString; - @HierarchicalPageProperty("hierarchicalPagePropertyBoolean") + @HierarchicalPageProperty(value = "hierarchicalPagePropertyBoolean", inherit = false) private boolean hierarchicalPagePropertyBoolean; @HierarchicalPageProperty @@ -63,7 +66,12 @@ public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarc @Override - public String getPropertyString() { + public String getPagePropertyString() { + return pagePropertyString; + } + + @Override + public String getHierarchicalPagePropertyString() { return hierarchicalPagePropertyString; } diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java new file mode 100644 index 0000000000..7faa5d76c4 --- /dev/null +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java @@ -0,0 +1,49 @@ +/* + * ACS AEM Commons + * + * Copyright (C) 2013 - 2023 Adobe + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.adobe.acs.commons.models.injectors.impl.model.impl; + +import com.adobe.acs.commons.models.injectors.annotation.PageProperty; +import com.adobe.acs.commons.models.injectors.impl.model.TestPagePropertiesModel; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.DefaultInjectionStrategy; +import org.apache.sling.models.annotations.Model; + +@Model( + adapters = TestPagePropertiesModel.class, + adaptables = {SlingHttpServletRequest.class, Resource.class}, + defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL +) +public class TestPagePropertiesModelModelImpl implements TestPagePropertiesModel { + + @PageProperty + private String hierarchicalPagePropertyString; + @PageProperty + private String pagePropertyString; + + @Override + public String getPagePropertyString() { + return pagePropertyString; + } + + @Override + public String getHierarchicalPagePropertyString() { + return hierarchicalPagePropertyString; + } + +} diff --git a/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx b/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx new file mode 100644 index 0000000000..e62257641d Binary files /dev/null and b/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx differ diff --git a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json index 6a80e34a7d..6baabc8f61 100644 --- a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json +++ b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json @@ -7,6 +7,7 @@ "cq:template": "/conf/we-retail/settings/wcm/templates/hero-page", "cq:designPath": "/etc/designs/acs-commons", "hierarchicalPagePropertyString": "inherited!", + "pagePropertyString": "inherited!", "hierarchicalPagePropertyBoolean": true, "hierarchicalPagePropertyInteger": 11, "hierarchicalPagePropertyMultiValueInteger": [ @@ -168,6 +169,8 @@ "cq:lastModified": "Tue Nov 06 2018 11:00:39 GMT+0100", "sling:resourceType": "weretail/components/structure/page", "cq:lastModifiedBy": "admin", + "pagePropertyString": "not inherited", + "hierarchicalPagePropertyBoolean": false, "root": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wcm/foundation/components/responsivegrid", diff --git a/oakpal-checks/pom.xml b/oakpal-checks/pom.xml index 0259a6bdfe..75c32575f5 100644 --- a/oakpal-checks/pom.xml +++ b/oakpal-checks/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index df76f9f47d..167e1cbffd 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT pom ACS AEM Commons - Reactor Project @@ -88,7 +88,7 @@ 1.8 1.8 - 1689084806 + 1694204679 diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index 09a79d924d..5a036d06cb 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT diff --git a/ui.content/pom.xml b/ui.content/pom.xml index 861c9c86b1..45ff9b0550 100644 --- a/ui.content/pom.xml +++ b/ui.content/pom.xml @@ -25,7 +25,7 @@ com.adobe.acs acs-aem-commons - 6.0.15-SNAPSHOT + 6.1.1-SNAPSHOT