From 5a60a6402328503df1c9e14881aace2f60353a85 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Wed, 6 Sep 2023 15:51:34 +0200 Subject: [PATCH 01/11] Issue 3177 - Automate creation of vanity URLs for each country & language --- .../redirectmaps/impl/AddEntryServlet.java | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java index aa8decc1e4..a8a8da8b6b 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java @@ -18,15 +18,19 @@ package com.adobe.acs.commons.redirectmaps.impl; import java.io.IOException; -import java.util.List; +import java.util.*; import javax.servlet.ServletException; +import org.apache.commons.collections.CollectionUtils; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.resource.Resource; import org.apache.sling.api.servlets.SlingAllMethodsServlet; +import org.graalvm.util.CollectionsUtil; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,31 +40,51 @@ * Servlet for adding a line into the redirect map text file */ @SlingServlet(methods = { "POST" }, resourceTypes = { - "acs-commons/components/utilities/redirectmappage" }, selectors = { - "addentry" }, extensions = { "json" }, metatype = false) + "acs-commons/components/utilities/redirectmappage" }, selectors = { + "addentry" }, extensions = { "json" }, metatype = false) public class AddEntryServlet extends SlingAllMethodsServlet { private static final long serialVersionUID = -1704915461516132101L; private static final Logger log = LoggerFactory.getLogger(AddEntryServlet.class); - + public static final String ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST = "/etc/acs-commons/lists/countries/jcr:content/list"; + // Disable this feature on AEM as a Cloud Service @Reference(target="(distribution=classic)") transient RequireAem requireAem; + Map countries; + @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { log.trace("doPost"); String source = request.getParameter("source"); String target = request.getParameter("target"); log.debug("Adding entry with {} {}", source, target); - + Resource resource = request.getResourceResolver().getResource(ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST); + if (Objects.nonNull(resource)) { + countries = new HashMap<>(); + @NotNull + Iterable children = resource.getChildren(); + for (Resource childResource : children) { + String title = childResource.getValueMap().get("jcr:title", String.class); + String nodeValue = childResource.getValueMap().get("value", String.class); + countries.put(nodeValue, title); + } + } List lines = RedirectEntriesUtils.readEntries(request); + if(CollectionUtils.isNotEmpty(lines)){ + for (Map.Entry country : countries.entrySet()) { + String genericSource = country.getKey()+":" +source; + String genericTarget= "/"+country.getKey()+"/"+country.getValue()+target; + lines.add(genericSource + " " + genericTarget); + } + }else{ + lines.add(source + " " + target); + } - lines.add(source + " " + target); log.debug("Added entry..."); - RedirectEntriesUtils.updateRedirectMap(request, lines); RedirectEntriesUtils.writeEntriesToResponse(request, response, "Added entry " + source + " " + target); } From 980d6f3d8d813a7b256688b2ddea553695788211 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Thu, 14 Sep 2023 16:31:12 +0200 Subject: [PATCH 02/11] Automate creation of vanity URLs for each country & language --- .../adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java index a8a8da8b6b..c845da4211 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java @@ -29,8 +29,6 @@ import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.servlets.SlingAllMethodsServlet; -import org.graalvm.util.CollectionsUtil; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +63,6 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse Resource resource = request.getResourceResolver().getResource(ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST); if (Objects.nonNull(resource)) { countries = new HashMap<>(); - @NotNull Iterable children = resource.getChildren(); for (Resource childResource : children) { String title = childResource.getValueMap().get("jcr:title", String.class); From d8e5cf3ab5658e27ee608f4ac757f13228077282 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Thu, 14 Sep 2023 17:44:34 +0200 Subject: [PATCH 03/11] Automate creation of vanity URLs for each country & language --- .../redirectmaps/impl/AddEntryServlet.java | 18 +++++++++++++----- .../redirectmaps/impl/TestServlets.java | 10 +++++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java index c845da4211..d4a1e4229a 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java @@ -22,12 +22,14 @@ import javax.servlet.ServletException; +import com.drew.lang.annotations.NotNull; import org.apache.commons.collections.CollectionUtils; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,15 +65,21 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse Resource resource = request.getResourceResolver().getResource(ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST); if (Objects.nonNull(resource)) { countries = new HashMap<>(); + @NotNull Iterable children = resource.getChildren(); - for (Resource childResource : children) { - String title = childResource.getValueMap().get("jcr:title", String.class); - String nodeValue = childResource.getValueMap().get("value", String.class); - countries.put(nodeValue, title); + if(children != null){ + for (Resource childResource : children) { + ValueMap valueMap = childResource.getValueMap(); + if (valueMap != null) { + String title = valueMap.get("jcr:title", String.class); + String nodeValue = valueMap.get("value", String.class); + countries.put(nodeValue, title); + } + } } } List lines = RedirectEntriesUtils.readEntries(request); - if(CollectionUtils.isNotEmpty(lines)){ + if(countries != null && !countries.isEmpty()){ for (Map.Entry country : countries.entrySet()) { String genericSource = country.getKey()+":" +source; String genericTarget= "/"+country.getKey()+"/"+country.getValue()+target; diff --git a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java index 26da7a5a2f..30d42008b8 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java +++ b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java @@ -20,8 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.*; import java.io.IOException; import java.io.InputStream; @@ -41,12 +40,14 @@ import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.commons.testing.sling.MockResourceResolver; import org.apache.tika.io.IOUtils; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,6 +77,10 @@ public class TestServlets { @Mock private Resource mockMapContentResource; + @Mock + private ResourceResolver resourceResolver; + + private Map value = new HashMap<>(); private ModifiableValueMap mvm = new ModifiableValueMap() { @@ -292,7 +297,6 @@ public void testAddEntryServlet() throws ServletException, IOException { log.info("testAddEntryServlet"); AddEntryServlet servlet = new AddEntryServlet(); servlet.doPost(mockSlingRequest, mockSlingResponse); - log.info("REDIRECT MAP:\n" + value.get(JcrConstants.JCR_DATA)); assertTrue(value.get(JcrConstants.JCR_DATA).contains("/source /target")); log.info("Test successful!"); From f95003d6296084da1c801d2176d7798e262c5d03 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Thu, 14 Sep 2023 17:46:07 +0200 Subject: [PATCH 04/11] Automate creation of vanity URLs for each country & language --- .../acs/commons/redirectmaps/impl/TestServlets.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java index 30d42008b8..7489bccec3 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java +++ b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java @@ -20,7 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.io.IOException; import java.io.InputStream; @@ -40,14 +41,12 @@ import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; -import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.commons.testing.sling.MockResourceResolver; import org.apache.tika.io.IOUtils; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,9 +76,6 @@ public class TestServlets { @Mock private Resource mockMapContentResource; - @Mock - private ResourceResolver resourceResolver; - private Map value = new HashMap<>(); @@ -297,6 +293,7 @@ public void testAddEntryServlet() throws ServletException, IOException { log.info("testAddEntryServlet"); AddEntryServlet servlet = new AddEntryServlet(); servlet.doPost(mockSlingRequest, mockSlingResponse); + log.info("REDIRECT MAP:\n" + value.get(JcrConstants.JCR_DATA)); assertTrue(value.get(JcrConstants.JCR_DATA).contains("/source /target")); log.info("Test successful!"); From effcce0b6de79c882d6e94da137e24bc4925b1e2 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Thu, 14 Sep 2023 18:17:47 +0200 Subject: [PATCH 05/11] Automate creation of vanity URLs for each country & language --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785f222695..a0bc28abdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com) ## Unreleased ([details][unreleased changes details]) +## 6.0.15 - 2023-09-14 + +## Changed + +- #3177 - Redirect Mapper: Automate creation of vanity URLs for each country + + ## Fixed - #3040 - Fixed bug where namespaced multi-fields would have the namespace 2 times From ff440b86ffb45b93b6a18e5914e24022797933ab Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Fri, 6 Oct 2023 14:20:22 +0200 Subject: [PATCH 06/11] 3177 - Automate creation of vanity URLs for each country & language --- .../redirectmaps/impl/AddEntryServlet.java | 6 ++-- .../redirectmaps/impl/TestServlets.java | 29 +++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java index d4a1e4229a..8cab6888d4 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/AddEntryServlet.java @@ -18,12 +18,14 @@ package com.adobe.acs.commons.redirectmaps.impl; import java.io.IOException; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import javax.servlet.ServletException; import com.drew.lang.annotations.NotNull; -import org.apache.commons.collections.CollectionUtils; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; diff --git a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java index 7489bccec3..97db546bbd 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java +++ b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java @@ -20,8 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import java.io.IOException; import java.io.InputStream; @@ -41,12 +41,15 @@ import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ValueMap; import org.apache.sling.commons.testing.sling.MockResourceResolver; import org.apache.tika.io.IOUtils; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,6 +79,14 @@ public class TestServlets { @Mock private Resource mockMapContentResource; + @Mock + private ResourceResolver resourceResolver; + + @Mock + private Iterable children; + + @Mock + private Iterator childrenIterator; private Map value = new HashMap<>(); @@ -292,10 +303,22 @@ public String getUserID() { public void testAddEntryServlet() throws ServletException, IOException { log.info("testAddEntryServlet"); AddEntryServlet servlet = new AddEntryServlet(); + when(mockSlingRequest.getResourceResolver()).thenReturn(resourceResolver); + when(mockResource.getResourceResolver()).thenReturn(resourceResolver); + when(resourceResolver.getResource(any())).thenReturn(mockResource); + when(mockResource.getChildren()).thenReturn(children); + when(children.iterator()).thenReturn(childrenIterator); + when(childrenIterator.hasNext()).thenReturn(true,false); + when(childrenIterator.next()).thenReturn(mockResource); + ValueMap valueMap = Mockito.mock(ValueMap.class); + when(mockResource.adaptTo(ValueMap.class)).thenReturn(valueMap); + when(mockResource.getValueMap()).thenReturn(valueMap); + when(valueMap.get("jcr:title", String.class)).thenReturn("test"); + when(valueMap.get("value", String.class)).thenReturn("test"); servlet.doPost(mockSlingRequest, mockSlingResponse); log.info("REDIRECT MAP:\n" + value.get(JcrConstants.JCR_DATA)); - assertTrue(value.get(JcrConstants.JCR_DATA).contains("/source /target")); + assertTrue(value.get(JcrConstants.JCR_DATA).contains("/source /test/test/target")); log.info("Test successful!"); } From 6309b0307360be5dcc38c2aa3acdf37dd0526f6f Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Fri, 6 Oct 2023 14:25:38 +0200 Subject: [PATCH 07/11] 3177 - Automate creation of vanity URLs for each country & language --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67055693df..dd71aa7de5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com) ## 6.2.0 - 2023-09-14 +## Changed + +- #3177 - Redirect Mapper: Automate creation of vanity URLs for each country + ## Added - #3151 - New ContentSync utility From 9b1da0b90914ff6966054cba7d28960c46df21e5 Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Fri, 6 Oct 2023 14:46:07 +0200 Subject: [PATCH 08/11] 3177 - Automate creation of vanity URLs for each country & language --- .../com/adobe/acs/commons/redirectmaps/impl/TestServlets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java index 97db546bbd..46a298de36 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java +++ b/bundle/src/test/java/com/adobe/acs/commons/redirectmaps/impl/TestServlets.java @@ -302,7 +302,7 @@ public String getUserID() { @Test public void testAddEntryServlet() throws ServletException, IOException { log.info("testAddEntryServlet"); - AddEntryServlet servlet = new AddEntryServlet(); + final AddEntryServlet servlet = new AddEntryServlet(); when(mockSlingRequest.getResourceResolver()).thenReturn(resourceResolver); when(mockResource.getResourceResolver()).thenReturn(resourceResolver); when(resourceResolver.getResource(any())).thenReturn(mockResource); From c2115c6bd4fae7e39a64c6e401c124d7ffc499ef Mon Sep 17 00:00:00 2001 From: Yassine EL OUARDI Date: Wed, 8 Nov 2023 13:54:24 +0100 Subject: [PATCH 09/11] Add Bulk Edit / Delete for Multi countries --- bundle-cloud/pom.xml | 124 --- .../CloudDispatcherFlushRulesExecutor.java | 115 --- .../impl/CloudDispatcherFlusher.java | 139 ---- .../redirectmaps/impl/RemoveEntryServlet.java | 37 +- .../redirectmaps/impl/UpdateEntryServlet.java | 115 ++- .../dispatcher/DispatcherFlushRules.java | 30 - .../redirectmappage/clientlibs/app.js | 758 ++++++++++-------- .../utilities/redirectmappage/content.jsp | 31 +- 8 files changed, 583 insertions(+), 766 deletions(-) delete mode 100644 bundle-cloud/pom.xml delete mode 100644 bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlushRulesExecutor.java delete mode 100644 bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlusher.java delete mode 100644 bundle/src/main/java/com/adobe/acs/commons/replication/dispatcher/DispatcherFlushRules.java diff --git a/bundle-cloud/pom.xml b/bundle-cloud/pom.xml deleted file mode 100644 index e19168eea1..0000000000 --- a/bundle-cloud/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - 4.0.0 - - - - - - com.adobe.acs - acs-aem-commons - 6.2.1-SNAPSHOT - - - - - - acs-aem-commons-bundle-cloud - ACS AEM Commons Bundle - Core Cloud Fragment - OSGi Core bundle fragment for ACS AEM Commons (only AEMaaCS) - - - - biz.aQute.bnd - bnd-maven-plugin - - - - - - biz.aQute.bnd - bnd-baseline-maven-plugin - - - org.apache.sling - sling-maven-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - - - - - - com.google.code.findbugs - jsr305 - provided - - - com.adobe.acs - acs-aem-commons-bundle - ${project.version} - provided - - - - com.adobe.acs - acs-aem-commons-bundle - ${project.version} - tests - test-jar - test - - - junit - junit - test - - - org.mockito - mockito-core - test - - - org.apache.sling - org.apache.sling.testing.osgi-mock.junit4 - test - - - org.apache.sling - org.apache.sling.testing.sling-mock.junit4 - test - - - io.wcm - io.wcm.testing.aem-mock.junit4 - test - - - - - com.adobe.aem - aem-sdk-api - provided - - - diff --git a/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlushRulesExecutor.java b/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlushRulesExecutor.java deleted file mode 100644 index 5f62f3a8e4..0000000000 --- a/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlushRulesExecutor.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * #%L - * ACS AEM Commons Bundle - * %% - * Copyright (C) 2016 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.replication.dispatcher.impl; - -import com.adobe.acs.commons.replication.dispatcher.DispatcherFlushRules; -import com.adobe.acs.commons.util.RequireAem; -import com.day.cq.replication.ReplicationAction; -import com.day.cq.replication.ReplicationActionType; -import com.day.cq.replication.ReplicationException; -import com.day.cq.replication.ReplicationOptions; -import org.apache.sling.discovery.DiscoveryService; -import org.apache.sling.distribution.DistributionRequestType; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.List; - -import static org.apache.sling.distribution.event.DistributionEventProperties.DISTRIBUTION_PATHS; -import static org.apache.sling.distribution.event.DistributionEventProperties.DISTRIBUTION_TYPE; -import static org.apache.sling.distribution.event.DistributionEventTopics.AGENT_PACKAGE_DISTRIBUTED; -import static org.osgi.service.event.EventConstants.EVENT_TOPIC; - -@Component( - immediate = true, - service = EventHandler.class, - property = { - EVENT_TOPIC + "=" + AGENT_PACKAGE_DISTRIBUTED - } -) -public class CloudDispatcherFlushRulesExecutor implements EventHandler { - - private static final Logger log = LoggerFactory.getLogger(CloudDispatcherFlushRulesExecutor.class); - - @Reference(target = "(distribution=cloud-ready)") - private RequireAem requireAem; - - @Reference - private DiscoveryService discoveryService; - - @Reference - private volatile List dispatcherFlushRules; - - @Override - public void handleEvent(Event event) { - String distributionType = (String) event.getProperty(DISTRIBUTION_TYPE); - - boolean isLeader = discoveryService.getTopology().getLocalInstance().isLeader(); - // process the OSGi event on the leader author instance - if (isLeader) { - String[] distributionPaths = (String[]) event.getProperty(DISTRIBUTION_PATHS); - if (distributionPaths == null || distributionPaths.length == 0) { - log.debug("Skipping processing because the distribution paths are empty"); - return; - } - ReplicationActionType actionType = getReplicationActionType(distributionType); - if (actionType != null) { - executeFlushRules(actionType, Arrays.asList(distributionPaths)); - } - } - } - - private void executeFlushRules(ReplicationActionType actionType, List distributionPaths) { - ReplicationAction action = new ReplicationAction(actionType, distributionPaths.toArray(new String[0]), 0L, "", null); - ReplicationOptions opts = new ReplicationOptions(); - log.debug("Executing dispatcher flush rules for distribution paths {}", distributionPaths); - for (DispatcherFlushRules dispatcherFlushRule : dispatcherFlushRules) { - try { - dispatcherFlushRule.preprocess(action, opts); - } catch (ReplicationException e) { - log.warn("Could not execute dispatcher flush rule for distribution paths [{}]", distributionPaths, e); - } - } - if (log.isInfoEnabled()) { - log.info("Executed flush rules for resources [{}]", distributionPaths); - } - } - - - private ReplicationActionType getReplicationActionType(String distributionType) { - DistributionRequestType requestType = DistributionRequestType.fromName(distributionType); - if (DistributionRequestType.ADD.equals(requestType)) { - return ReplicationActionType.ACTIVATE; - } else if (DistributionRequestType.DELETE.equals(requestType)) { - return ReplicationActionType.DEACTIVATE; - } else if (DistributionRequestType.TEST.equals(requestType)) { - return ReplicationActionType.TEST; - } - log.debug("Distribution request type {} not supported", requestType); - return null; - } - - -} diff --git a/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlusher.java b/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlusher.java deleted file mode 100644 index e494e510b8..0000000000 --- a/bundle-cloud/src/main/java/com/adobe/acs/commons/replication/dispatcher/impl/CloudDispatcherFlusher.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * #%L - * ACS AEM Commons Bundle - * %% - * Copyright (C) 2016 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.replication.dispatcher.impl; - -import com.adobe.acs.commons.replication.dispatcher.DispatcherFlushFilter; -import com.adobe.acs.commons.replication.dispatcher.DispatcherFlusher; -import com.day.cq.replication.Agent; -import com.day.cq.replication.AgentFilter; -import com.day.cq.replication.AgentManager; -import com.day.cq.replication.ReplicationActionType; -import com.day.cq.replication.ReplicationException; -import com.day.cq.replication.ReplicationResult; -import org.apache.sling.api.resource.ResourceResolver; -import org.apache.sling.distribution.DistributionRequest; -import org.apache.sling.distribution.DistributionRequestType; -import org.apache.sling.distribution.DistributionResponse; -import org.apache.sling.distribution.Distributor; -import org.apache.sling.distribution.SimpleDistributionRequest; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.propertytypes.ServiceRanking; -import org.osgi.service.metatype.annotations.AttributeDefinition; -import org.osgi.service.metatype.annotations.Designate; -import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -@ServiceRanking(-5000) -@Designate(ocd = CloudDispatcherFlusher.Config.class) -public class CloudDispatcherFlusher implements DispatcherFlusher { - - private static final Logger log = LoggerFactory.getLogger(CloudDispatcherFlusher.class); - - @ObjectClassDefinition - @interface Config { - @AttributeDefinition(description = "Agent names to trigger when executing a distribute invalidate (ex. publish, preview)") - String[] agent_names() default {"publish"}; - } - - @Reference - private Distributor distributor; - - @Reference - private AgentManager agentManager; - - private String[] agentNames; - - @Activate - protected void activate(Config config) { - this.agentNames = config.agent_names(); - } - - @Override - public Map flush(ResourceResolver resourceResolver, String... paths) { - Map result = new HashMap<>(); - DistributionRequest distributionRequest = new SimpleDistributionRequest(DistributionRequestType.INVALIDATE, false, paths); - for (String agentName : agentNames) { - DistributionResponse distributionResponse = distributor.distribute(agentName, resourceResolver, distributionRequest); - Agent agent = agentManager.getAgents().get(agentName); - if (agent != null) { - result.put(agent, toReplicationResult(distributionResponse)); - } - } - log.debug("Executed dispatcher flush for paths {}", Arrays.asList(paths)); - return result; - } - - @Override - public Map flush(ResourceResolver resourceResolver, ReplicationActionType actionType, boolean synchronous, String... paths) throws ReplicationException { - // see https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/implementing/content-delivery/caching.html?lang=en#sling-distribution - log.warn( - "Dispatcher flusher in cloud should use INVALIDATE distribution types from author, no custom action type and synchronous should be set, " - + "refactor your code to use the DispatcherFlushRules.flush(resourceResolver, paths) method" - ); - return flush(resourceResolver, paths); - } - - @Override - public Map flush(ResourceResolver resourceResolver, ReplicationActionType actionType, boolean synchronous, AgentFilter agentFilter, String... paths) throws ReplicationException { - // see https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/implementing/content-delivery/caching.html?lang=en#sling-distribution - log.warn( - "Dispatcher flusher in cloud should use INVALIDATE distribution types from author, no custom action type and synchronous should be set, " - + "refactor your code to use the DispatcherFlushRules.flush(resourceResolver, paths) method" - ); - return flush(resourceResolver, paths); - } - - @Override - public final Agent[] getFlushAgents() { - return this.getAgents(new DispatcherFlushFilter()); - } - - /** - * {@inheritDoc} - */ - @Override - public final Agent[] getAgents(final AgentFilter agentFilter) { - final List flushAgents = new ArrayList(); - - for (final Agent agent : agentManager.getAgents().values()) { - if (agentFilter.isIncluded(agent)) { - flushAgents.add(agent); - } - } - return flushAgents.toArray(new Agent[flushAgents.size()]); - } - - private ReplicationResult toReplicationResult(DistributionResponse distributionResponse) { - if (distributionResponse.isSuccessful()) { - return ReplicationResult.OK; - } - return new ReplicationResult(false, 500, distributionResponse.getMessage()); - } -} diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/RemoveEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/RemoveEntryServlet.java index eda76454bf..687f3f4b3a 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/RemoveEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/RemoveEntryServlet.java @@ -51,17 +51,30 @@ public class RemoveEntryServlet extends SlingAllMethodsServlet { protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { log.trace("doPost"); - - int idx = Integer.parseInt(request.getParameter("idx"), 10); - log.debug("Removing index {}", idx); - - List lines = RedirectEntriesUtils.readEntries(request); - - lines.remove(idx); - log.debug("Removed line..."); - - RedirectEntriesUtils.updateRedirectMap(request, lines); - - RedirectEntriesUtils.writeEntriesToResponse(request, response, "Removed entry "+idx); + boolean multi = Boolean.parseBoolean(request.getParameter("multi")); + if(multi){ + List lines = RedirectEntriesUtils.readEntries(request); + String[] outerArray=request.getParameterValues("idx"); + String[] innerArray=outerArray[0].split(","); + int count =0; + for ( String i : innerArray){ + int idx = Integer.parseInt(i); + log.debug("Removing index {}", idx); + lines.remove(idx-count); + log.debug("Removed line..."); + count++; + } + RedirectEntriesUtils.updateRedirectMap(request, lines); + RedirectEntriesUtils.writeEntriesToResponse(request, response, "Removed entries "+innerArray); + } + else { + int idx = Integer.parseInt(request.getParameter("idx"), 10); + log.debug("Removing index {}", idx); + List lines = RedirectEntriesUtils.readEntries(request); + lines.remove(idx); + log.debug("Removed line..."); + RedirectEntriesUtils.updateRedirectMap(request, lines); + RedirectEntriesUtils.writeEntriesToResponse(request, response, "Removed entry " + idx); + } } } diff --git a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/UpdateEntryServlet.java b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/UpdateEntryServlet.java index bc0b124a44..c2a2cfb4ee 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/UpdateEntryServlet.java +++ b/bundle/src/main/java/com/adobe/acs/commons/redirectmaps/impl/UpdateEntryServlet.java @@ -18,14 +18,23 @@ package com.adobe.acs.commons.redirectmaps.impl; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import javax.servlet.ServletException; +import com.drew.lang.annotations.NotNull; +import org.apache.commons.lang3.StringUtils; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +51,9 @@ public class UpdateEntryServlet extends SlingAllMethodsServlet { private static final long serialVersionUID = -1704915461516132101L; private static final Logger log = LoggerFactory.getLogger(UpdateEntryServlet.class); - + public static final String ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST = "/etc/acs-commons/lists/countries/jcr:content/list"; + Map countries; + // Disable this feature on AEM as a Cloud Service @Reference(target="(distribution=classic)") transient RequireAem requireAem; @@ -51,20 +62,106 @@ public class UpdateEntryServlet extends SlingAllMethodsServlet { protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { log.trace("doPost"); - + Resource resource = request.getResourceResolver().getResource(ETC_ACS_COMMONS_LISTS_COUNTRIES_JCR_CONTENT_LIST); + if (Objects.nonNull(resource)) { + countries = new HashMap<>(); + @NotNull + Iterable children = resource.getChildren(); + if(children != null){ + for (Resource childResource : children) { + ValueMap valueMap = childResource.getValueMap(); + if (valueMap != null) { + String title = valueMap.get("jcr:title", String.class); + String nodeValue = valueMap.get("value", String.class); + countries.put(nodeValue, title); + } + } + } + } + String bulkParam = request.getParameter("bulk-edit"); + List lines = RedirectEntriesUtils.readEntries(request); String source = request.getParameter("edit-source"); String target = request.getParameter("edit-target"); + String targetBase = request.getParameter("edit-target-base"); int idx = Integer.parseInt(request.getParameter("edit-id"), 10); - log.debug("Updating entry {} with {} {}", idx, source, target); - - List lines = RedirectEntriesUtils.readEntries(request); - - lines.set(idx, source + " " + target); - log.debug("Updated entry..."); + if(bulkParam!=null) { + boolean bulkEdit = bulkParam.equals("on") ? true : false; + String regex = "^/[a-z]+/[a-z-]+"; + URI uri = null; + try { + uri = new URI(targetBase); + } catch (URISyntaxException e) { + log.error("Updating entry Exception with {}", targetBase,e); + } + if (uri!=null && uri.getHost() != null) { + targetBase = uri.getPath(); + } + if (bulkEdit) { + log.debug("Updating entry {} with {} {}", idx, source, target); + int index = 0; + for (String line : lines) { + // Remove the language and country part using regex + String substring = targetBase.replaceFirst(regex, ""); + if (StringUtils.isNotBlank(line)) { + String[] splitSourceTarget = line.split(" "); + if (splitSourceTarget.length >= 2) { + String splitKey = splitSourceTarget[0]; + String splitKValue = splitSourceTarget[1]; + URI uriSource = null; + URI uriTarget = null; + try { + uriSource = new URI(splitKValue); + uriTarget = new URI(target); + } catch (URISyntaxException e) { + log.error("Updating entry Exception with {}", targetBase,e); + } + if (uriSource !=null && uriSource.getHost() != null) { + splitKValue = uriSource.getPath(); + } + if (uriTarget !=null && uriTarget.getHost() != null) { + target = uriTarget.getPath(); + target = target.replaceFirst(regex, ""); + } + String[] splitVanityKey = splitKey.split("/"); + String[] splitVanityValue = splitKValue.split("/"); + if (splitVanityKey.length > 1 && splitVanityValue.length > 2) { + String countrySource = splitKey.split(":")[0]; + String country = splitVanityValue[1].replace(":", ""); + String codeLanguage = splitVanityValue[2]; + String countryValue = countries.get(country); + String countrySourceValue = countries.get(countrySource); + if (line.contains(substring) && !StringUtils.isAnyBlank(country, codeLanguage, countryValue) && countryValue.equals(codeLanguage)) { + if(!isFound(countries,target)) { + if(StringUtils.isNotBlank(countrySourceValue)){ + line = line.replace(country+"/"+countryValue, countrySource+"/"+countrySourceValue); + } + lines.set(index, line.replace(substring, target)); + } + } + } + } + } + index++; + } + log.debug("Updated entry..."); + } + }else{ + lines.set(idx, source + " " + target); + } log.trace("Saving lines {}", lines); RedirectEntriesUtils.updateRedirectMap(request, lines); RedirectEntriesUtils.writeEntriesToResponse(request, response, "Updated entry " + idx + " to " + source + " " + target); } -} + private boolean isFound(Map countries, String searchString) { + boolean found = false; + for (String value : countries.values()) { + if (searchString.contains(value)) { + found = true; + break; + } + } + return found; + } +} \ No newline at end of file diff --git a/bundle/src/main/java/com/adobe/acs/commons/replication/dispatcher/DispatcherFlushRules.java b/bundle/src/main/java/com/adobe/acs/commons/replication/dispatcher/DispatcherFlushRules.java deleted file mode 100644 index 5acb2e406e..0000000000 --- a/bundle/src/main/java/com/adobe/acs/commons/replication/dispatcher/DispatcherFlushRules.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * #%L - * ACS AEM Commons Bundle - * %% - * Copyright (C) 2016 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.replication.dispatcher; - -import com.day.cq.replication.ReplicationAction; -import com.day.cq.replication.ReplicationException; -import com.day.cq.replication.ReplicationOptions; - -public interface DispatcherFlushRules { - - void preprocess(final ReplicationAction replicationAction, - final ReplicationOptions replicationOptions) throws ReplicationException; -} diff --git a/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/clientlibs/app.js b/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/clientlibs/app.js index 5c963e15b8..2dc27ceda4 100644 --- a/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/clientlibs/app.js +++ b/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/clientlibs/app.js @@ -1,346 +1,436 @@ -/* - * #%L - * ACS AEM Commons Bundle - * %% - * Copyright (C) 2015 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% - */ -/*global angular: false */ -angular - .module("acs-commons-redirectmappage-app", [ - "acsCoral", - "ACS.Commons.notifications" - ]) - .controller("MainCtrl", [ - "$scope", - "$http", - "$timeout", - "NotificationsService", - function ($scope, $http, $timeout, NotificationsService) { - $scope.app = { - uri: "" - }; - - $scope.entries = []; + /* + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2015 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% + */ + /*global angular: false */ + angular + .module("acs-commons-redirectmappage-app", [ + "acsCoral", + "ACS.Commons.notifications" + ]) + .controller("MainCtrl", [ + "$scope", + "$http", + "$timeout", + "NotificationsService", + function ($scope, $http, $timeout, NotificationsService) { + $scope.app = { + uri: "" + }; + + $scope.entries = []; + $scope.entriesToRemove = []; + $scope.filteredEntries = []; + $scope.invalidEntries = []; + $scope.redirectMap = ""; + $scope.currentEntry = null; + + $scope.addEntry = function () { + var start = new Date().getTime(); + NotificationsService.running(true); + $scope.entries = []; + $scope.invalidEntries = []; + $http({ + method: "POST", + url: + $scope.app.uri + ".addentry.json?" + $("#entry-form").serialize() + }).then( + function (response) { + var data = response.data; + var status = response.status; + var headers = response.headers; + var config = response.config; + + var time = new Date().getTime() - start; + data.time = time; + $scope.entries = data.entries || []; + $scope.invalidEntries = data.invalidEntries || []; + $scope.filterEntries(); + NotificationsService.running(false); + NotificationsService.add("success", "SUCCESS", "Entry added!"); + $scope.loadRedirectMap(); + }, + function (error) { + var data = error.data; + var status = error.status; + NotificationsService.running(false); + NotificationsService.add("error", "ERROR", "Unable to add entry!"); + } + ); + }; + + + + $scope.page = 1; // Current page + $scope.itemsPerPage = 100; // Number of items to load per page + $scope.hasMoreData = true; // Whether there's more data to load + + $scope.loadMoreData = function () { + if ($scope.hasMoreData && $scope.itemsPerPage < $scope.entries.length) { + $scope.itemsPerPage = $scope.itemsPerPage * 2; + $scope.filterEntries(); + } + }; + + $scope.filterEntries = function () { $scope.filteredEntries = []; - $scope.invalidEntries = []; - $scope.redirectMap = ""; - $scope.currentEntry = null; - - $scope.addEntry = function () { - var start = new Date().getTime(); - NotificationsService.running(true); - $scope.entries = []; - $scope.invalidEntries = []; - $http({ - method: "POST", - url: - $scope.app.uri + ".addentry.json?" + $("#entry-form").serialize() - }).then( - function (response) { - var data = response.data; - var status = response.status; - var headers = response.headers; - var config = response.config; - - var time = new Date().getTime() - start; - data.time = time; - $scope.entries = data.entries || []; - $scope.invalidEntries = data.invalidEntries || []; - $scope.filterEntries(); - NotificationsService.running(false); - NotificationsService.add("success", "SUCCESS", "Entry added!"); - $scope.loadRedirectMap(); - }, - function (error) { - var data = error.data; - var status = error.status; - NotificationsService.running(false); - NotificationsService.add("error", "ERROR", "Unable to add entry!"); - } + var term = $("#filter-form") + .find("input[name=filter]") + .val() + .toLowerCase(); + + if (term.trim() !== "" && term.trim() !== "*") { + $scope.page = 1; // Reset the page to 1 + $scope.hasMoreData = true; // Reset to allow loading more data + filterData(term); + } else { + $scope.filteredEntries = $scope.entries.slice( + 0, + $scope.page * $scope.itemsPerPage ); - }; - - $scope.filterEntries = function () { - $scope.filteredEntries = []; - - var term = $("#filter-form") - .find("input[name=filter]") - .val() - .toLowerCase(); - if (term.trim() !== "") { - var count = 0; - $scope.entries.forEach(function (el, idx) { - var found = term.trim() === "*"; - Object.values(el).forEach(function (val, idx2) { + $scope.hasMoreData = $scope.filteredEntries.length < $scope.entries.length; + } + }; + + + function filterData(term) { + $scope.filteredEntries = $scope.entries.filter(function (el) { + var found = term.trim() === "*"; + Object.values(el).forEach(function (val) { if (val.toString().toLowerCase().indexOf(term) !== -1) { found = true; } }); - if (found) { - $scope.filteredEntries.push(el); - count++; - } - }); - - NotificationsService.add( - "success", - "SUCCESS", - "Found " + - count + - " entries for " + - $("#filter-form").find("input[name=filter]").val() + - "!" - ); - } - return false; - }; - - $scope.init = function () { - $('.endor-Crumbs-item[href="/miscadmin"]') - .html("Redirects") - .attr("href", "/miscadmin#/etc/acs-commons/redirect-maps"); - $scope.load(); - }; - - $scope.load = function () { - var start = new Date().getTime(); - NotificationsService.running(true); - $scope.filteredEntries = []; - $scope.entries = []; - $scope.invalidEntries = []; - $http({ - method: "GET", - url: $scope.app.uri + ".redirectentries.json" - }).then( - function (response) { - var data = response.data; - var status = response.status; - var headers = response.headers; - var config = response.config; - var time = new Date().getTime() - start; - $scope.entries = data.entries || []; - $scope.invalidEntries = data.invalidEntries || []; - NotificationsService.running(false); - NotificationsService.add( - "success", - "SUCCESS", - "Found " + data.length + " entries in " + time + "ms!" - ); - $scope.loadRedirectMap(); - $scope.filterEntries(); - }, - function (error) { - var data = error.data; - var status = error.status; - NotificationsService.running(false); - NotificationsService.add( - "error", - "ERROR", - "Unable load redirect entries!" - ); - } + return found; + }); + + $scope.hasMoreData = $scope.filteredEntries.length < $scope.entries.length; + NotificationsService.add( + "success", + "SUCCESS", + "Found " + $scope.filteredEntries.length + " entries for " + term + "!" + ); + } + + function loadMoreData() { + if ($scope.hasMoreData) { + // Simulate a delay for the example + // In a real application, you would make an AJAX request to fetch data + // based on the current page and itemsPerPage + simulateDataLoading(); + } + } + + function simulateDataLoading() { + // Simulate fetching more data with a delay + setTimeout(function () { + var newData = $scope.entries.slice( + $scope.filteredEntries.length, + $scope.filteredEntries.length + $scope.itemsPerPage ); - }; - - $scope.loadRedirectMap = function () { - var start = new Date().getTime(); - NotificationsService.running(true); - $scope.redirectMap = ""; - $http({ - method: "GET", - url: $scope.app.uri + ".redirectmap.txt" - }).then( - function (response) { - var data = response.data; - var status = response.status; - var headers = response.headers; - var config = response.config; - var time = new Date().getTime() - start; - $scope.redirectMap = data || ""; - NotificationsService.running(false); - NotificationsService.add( - "success", - "SUCCESS", - "Loaded redirect map in " + time + "ms!" - ); - }, - function (error) { - var data = error.data; - var status = error.status; - NotificationsService.running(false); - NotificationsService.add( - "error", - "ERROR", - "Unable load redirect map!" - ); - } + + // Check if there's more data + $scope.hasMoreData = $scope.filteredEntries.length < $scope.entries.length; + + $scope.filteredEntries = $scope.filteredEntries.concat(newData); + + NotificationsService.add( + "success", + "SUCCESS", + "Loaded " + newData.length + " more entries!" ); - }; - - $scope.openEditor = function (path) { - if (path.indexOf("/content/dam") === -1) { - window.open("/editor.html" + path + ".html", "_blank"); - } else { - window.open( - "/mnt/overlay/dam/gui/content/assets/metadataeditor.external.html?_charset_=utf-8&item=" + - path, - "_blank" - ); - } - }; - - $scope.editItem = function (id) { - $scope.entries.forEach(function (el) { - if (el.id === id) { - console.log("Editing entry: " + id); - document.querySelector("input[name=edit-source]").value = el.source; - document.querySelector("input[name=edit-target]").value = el.target; - document.querySelector("input[name=edit-id]").value = id; - } - }); - - var dialog = document.querySelector("#edit-entry"); - dialog.show(); - }; - - $scope.postValues = function (e, id) { - e.preventDefault(); - - NotificationsService.running(true); - - var $form = $("#" + id); - - $.post($form.attr("action"), $form.serialize(), function () { - location.reload(true); - }); - return false; - }; - - $scope.removeAlert = function (id) { - $scope.currentEntry = id; - - var dialog = document.querySelector("#remove-confirm"); - dialog.show(); - }; - - $scope.removeLine = function () { - var idx = $scope.currentEntry; - var start = new Date().getTime(); - NotificationsService.running(true); - $scope.entries = []; - $scope.filteredEntries = []; - $scope.invalidEntries = []; - $http({ - method: "POST", - url: $scope.app.uri + ".removeentry.json?idx=" + idx - }).then( - function (response) { - var data = response.data; - var status = response.status; - var headers = response.headers; - var config = response.config; - var time = new Date().getTime() - start; - data.time = time; - $scope.entries = data.entries || []; - $scope.invalidEntries = data.invalidEntries || []; - NotificationsService.running(false); - NotificationsService.add( - "success", - "SUCCESS", - "Redirect map updated!" + + $scope.$apply(); // Notify AngularJS that the data has changed + }, 1000); // Simulated delay in milliseconds + } + + + + + + + // Example: Reset the filter and load the first page of data + $scope.resetFilter = function () { + $scope.page = 1; + $scope.filteredEntries = []; + $scope.hasMoreData = true; + $scope.filterEntries(); + }; + + + + $scope.init = function () { + $('.endor-Crumbs-item[href="/miscadmin"]') + .html("Redirects") + .attr("href", "/miscadmin#/etc/acs-commons/redirect-maps"); + $scope.load(); + }; + + $scope.load = function () { + var start = new Date().getTime(); + NotificationsService.running(true); + $scope.filteredEntries = []; + $scope.entries = []; + $scope.invalidEntries = []; + $http({ + method: "GET", + url: $scope.app.uri + ".redirectentries.json" + }).then( + function (response) { + var data = response.data; + var status = response.status; + var headers = response.headers; + var config = response.config; + var time = new Date().getTime() - start; + $scope.entries = data.entries || []; + $scope.invalidEntries = data.invalidEntries || []; + NotificationsService.running(false); + NotificationsService.add( + "success", + "SUCCESS", + "Found " + data.length + " entries in " + time + "ms!" + ); + $scope.loadRedirectMap(); + $scope.filterEntries(); + }, + function (error) { + var data = error.data; + var status = error.status; + NotificationsService.running(false); + NotificationsService.add( + "error", + "ERROR", + "Unable load redirect entries!" + ); + } ); - $scope.loadRedirectMap(); - $scope.filterEntries(); - }, - function (error) { - var data = error.data; - var status = error.status; - NotificationsService.running(false); - NotificationsService.add( - "error", - "ERROR", - "Unable remove entry " + idx + "!" + }; + + $scope.loadRedirectMap = function () { + var start = new Date().getTime(); + NotificationsService.running(true); + $scope.redirectMap = ""; + $http({ + method: "GET", + url: $scope.app.uri + ".redirectmap.txt" + }).then( + function (response) { + var data = response.data; + var status = response.status; + var headers = response.headers; + var config = response.config; + var time = new Date().getTime() - start; + $scope.redirectMap = data || ""; + NotificationsService.running(false); + NotificationsService.add( + "success", + "SUCCESS", + "Loaded redirect map in " + time + "ms!" + ); + }, + function (error) { + var data = error.data; + var status = error.status; + NotificationsService.running(false); + NotificationsService.add( + "error", + "ERROR", + "Unable load redirect map!" + ); + } ); - } - ); - }; - - $scope.saveLine = function () { - var dialog = document.querySelector("#edit-entry"); - var start = new Date().getTime(); - NotificationsService.running(true); - $scope.entries = []; - $scope.invalidEntries = []; - $http({ - method: "POST", - url: - $scope.app.uri + - ".updateentry.json?" + - $("#update-form").serialize() - }).then( - function (response) { - var data = response.data; - var status = response.status; - var headers = response.headers; - var config = response.config; - - var time = new Date().getTime() - start; - data.time = time; - $scope.entries = data.entries || []; - $scope.invalidEntries = data.invalidEntries || []; - $scope.filterEntries(); - NotificationsService.running(false); - NotificationsService.add("success", "SUCCESS", "Entry updated!"); - $scope.loadRedirectMap(); - dialog.hide(); - }, - function (error) { - var data = error.data; - var status = error.status; - NotificationsService.running(false); - NotificationsService.add( - "error", - "ERROR", - "Unable to update entry!" + }; + + $scope.openEditor = function (path) { + if (path.indexOf("/content/dam") === -1) { + window.open("/editor.html" + path + ".html", "_blank"); + } else { + window.open( + "/mnt/overlay/dam/gui/content/assets/metadataeditor.external.html?_charset_=utf-8&item=" + + path, + "_blank" + ); + } + }; + + $scope.editItem = function (id) { + $scope.entries.forEach(function (el) { + if (el.id === id) { + console.log("Editing entry: " + id); + document.querySelector("input[name=edit-source]").value = el.source; + document.querySelector("input[name=edit-target]").value = el.target; + document.querySelector("input[name=edit-target-base]").value = el.target; + console.log("Target Base " +document.querySelector("input[name=edit-target-base]").value); + document.querySelector("input[name=edit-id]").value = id; + } + }); + + var dialog = document.querySelector("#edit-entry"); + dialog.show(); + }; + + $scope.postValues = function (e, id) { + e.preventDefault(); + + NotificationsService.running(true); + + var $form = $("#" + id); + + $.post($form.attr("action"), $form.serialize(), function () { + location.reload(true); + }); + return false; + }; + + $scope.removeAlert = function (id) { + $scope.currentEntry = id; + + var dialog = document.querySelector("#remove-confirm"); + dialog.show(); + }; + $scope.removeAlertMulti = function () { + var dialog = document.querySelector("#removemulti-confirm"); + dialog.show(); + }; + $scope.selectEntry = function (id) { + $scope.currentEntry = id; + if($scope.entriesToRemove.includes(id) === true ){ + //$scope.entriesToRemove = $scope.entriesToRemove.filter(item => item !== id); + }else{ + $scope.entriesToRemove.push(id); + } + console.log("entriesToRemove : "+ $scope.entriesToRemove.toString()); + }; + + $scope.removeLine = function () { + var idx = $scope.currentEntry; + var start = new Date().getTime(); + NotificationsService.running(true); + $scope.entries = []; + $scope.filteredEntries = []; + $scope.invalidEntries = []; + var multi = false; + if($scope.entriesToRemove.length > 0){ + multi = true; + idx = $scope.entriesToRemove; + } + $http({ + method: "POST", + url: $scope.app.uri + ".removeentry.json?idx=" + idx+"&multi="+multi + }).then( + function (response) { + var data = response.data; + var status = response.status; + var headers = response.headers; + var config = response.config; + var time = new Date().getTime() - start; + data.time = time; + $scope.entries = data.entries || []; + $scope.invalidEntries = data.invalidEntries || []; + NotificationsService.running(false); + NotificationsService.add( + "success", + "SUCCESS", + "Redirect map updated! BY REMOVING "+ $scope.entriesToRemove + ); + $scope.loadRedirectMap(); + $scope.filterEntries(); + $scope.entriesToRemove = []; + }, + function (error) { + var data = error.data; + var status = error.status; + NotificationsService.running(false); + NotificationsService.add( + "error", + "ERROR", + "Unable remove entry " + idx + "!" + ); + } ); - dialog.hide(); - } - ); - }; - - $scope.updateRedirectMap = function (e) { - e.preventDefault(); - - NotificationsService.running(true); - - var $form = $("#fn-acsCommons-update-redirect"); - - $.ajax({ - url: $form.attr("action"), - data: new FormData($form[0]), - cache: false, - contentType: false, - processData: false, - type: "POST", - success: function (data) { - location.reload(true); - } - }); - return false; - }; - } - ]); + }; + + $scope.saveLine = function () { + var dialog = document.querySelector("#edit-entry"); + var start = new Date().getTime(); + NotificationsService.running(true); + $scope.entries = []; + $scope.invalidEntries = []; + $http({ + method: "POST", + url: + $scope.app.uri + + ".updateentry.json?" + + $("#update-form").serialize() + }).then( + function (response) { + var data = response.data; + var status = response.status; + var headers = response.headers; + var config = response.config; + + var time = new Date().getTime() - start; + data.time = time; + $scope.entries = data.entries || []; + $scope.invalidEntries = data.invalidEntries || []; + $scope.filterEntries(); + NotificationsService.running(false); + NotificationsService.add("success", "SUCCESS", "Entry updated!"); + $scope.loadRedirectMap(); + dialog.hide(); + // Reload the current page after a successful update + // Reload the table data + location.reload(true); + }, + function (error) { + var data = error.data; + var status = error.status; + NotificationsService.running(false); + NotificationsService.add( + "error", + "ERROR", + "Unable to update entry!" + ); + dialog.hide(); + } + ); + }; + + $scope.updateRedirectMap = function (e) { + e.preventDefault(); + + NotificationsService.running(true); + + var $form = $("#fn-acsCommons-update-redirect"); + + $.ajax({ + url: $form.attr("action"), + data: new FormData($form[0]), + cache: false, + contentType: false, + processData: false, + type: "POST", + success: function (data) { + location.reload(true); + } + }); + return false; + }; + } + ]); diff --git a/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/content.jsp b/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/content.jsp index 67bef7658c..09b983753b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/content.jsp +++ b/ui.apps/src/main/content/jcr_root/apps/acs-commons/components/utilities/redirectmappage/content.jsp @@ -27,7 +27,7 @@ if (RequireAem.Distribution.CLOUD_READY.equals(requireAem.getDistribution())) {



- + @@ -46,7 +46,7 @@ if (RequireAem.Distribution.CLOUD_READY.equals(requireAem.getDistribution())) {

- +