Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy Sites Publish URL #3481

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4ba8ef9
Copy Sites Publish URL
Nov 22, 2024
a1f57e5
Updating the changelog with the unreleased ticket number and fixing c…
Nov 26, 2024
f7f5233
Fixing more code climate errors.
Nov 27, 2024
62debdc
Styling improvements. Adding Separate label, input and copy button fo…
Nov 27, 2024
1729e70
Fixing Code Climate styling issues.
Nov 27, 2024
58c50c6
Update the copyright year and few code smells
Nov 27, 2024
037a70b
Adding CopySitesPublishUrlFeatureTest.java, dedicated modal message f…
Dec 2, 2024
2a21a7a
.gitgnore updated with Qlty plugin folder
Dec 3, 2024
3cad1f5
Fixing Qlty plugin issues - comments on the new unit test and decalar…
Dec 3, 2024
285625a
Remove the 'service.ranking' property for the CopySitesPublishUrlFeat…
Dec 6, 2024
f05279c
renaming the servlet extension from .txt to .json. Fixing the copy to…
Dec 9, 2024
41a35d1
prefixing the CSS with acs-aem-commons__ to avoid potential conflict
Dec 9, 2024
4ca9f96
Merge branch 'master' into feature/view-publish-url-sites
krassib Dec 9, 2024
485bc4c
added the wrapper for the clientlib
Dec 10, 2024
9a68624
Merge remote-tracking branch 'personal/feature/view-publish-url-sites…
Dec 10, 2024
6191d18
Make the servlet configurationPolicy = ConfigurationPolicy.REQUIRE s…
Dec 10, 2024
589dc67
Copy Publish URL changes
davidjgonzalez Dec 11, 2024
caa6e53
Minor cleanup
davidjgonzalez Dec 11, 2024
1951350
Clean up
davidjgonzalez Dec 11, 2024
0fe22f5
Minor cleanup
davidjgonzalez Dec 11, 2024
9c7ed52
Cleanup: Optimizing imports
Dec 11, 2024
2ccbd53
minor cleanup
Dec 12, 2024
8a8018a
Removed the render conditions 1 and 2 for rendering the clientlib whe…
Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ bundle/mockserver.log
.java-version

# Maven versions plugin
pom.xml.versionsBackup
pom.xml.versionsBackup

# Qlty plugin folder
/.qlty/
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
<!-- Keep this up to date! After a release, change the tag name to the latest release -->-

## Unreleased ([details][unreleased changes details])
- #3480 - Sites Copy Publish URLs

## 6.9.6 - 2024-11-20

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*-
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 - 2024 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.wcm.impl;

import org.apache.sling.featureflags.ExecutionContext;
import org.apache.sling.featureflags.Feature;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;


/**
* OSGi Feature flag to enable or disable the copy publish URLs dropdown field in the Sites Editor.
*/
@Component(
property = {
"service.ranking=200"
krassib marked this conversation as resolved.
Show resolved Hide resolved
},
service = Feature.class
)
@Designate(ocd = CopySitesPublishUrlFeature.Config.class)
public class CopySitesPublishUrlFeature implements Feature {
static final String FEATURE_FLAG_PID = "com.adobe.acs.commons.wcm.impl.copysitespublishurlfeature.feature.flag";

private Config config;

@ObjectClassDefinition(
name = "ACS AEM Commons - Copy Sites Publish URL Feature Flag",
description = "ACS Commons feature flag enables or disables the copy publish url dropdown field in the Sites Editor."
)
@interface Config {
@AttributeDefinition(
name = "Enable",
description = "Check to enable the AEM Sites Copy Publish URL feature."
)
boolean feature_flag_active_status() default false;
}

@SuppressWarnings("ClassEscapesDefinedScope")
@Activate
protected final void activate(Config config) {
this.config = config;
}

@Override
public String getName() {
return FEATURE_FLAG_PID;
}

@Override
public String getDescription() {
return "ACS AEM Commons feature flag enables or disables the copy publish URL dropdown field in the Sites Editor.";
}

@Override
public boolean isEnabled(ExecutionContext executionContext) {
return config.feature_flag_active_status();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*-
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 - 2024 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.wcm.impl;

import com.day.cq.commons.Externalizer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
import org.jetbrains.annotations.NotNull;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

import javax.servlet.Servlet;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;


/**
* This servlet generates a JSON response with the externalized URLs for the given path using configured keys in its
* configuration. They keys need to match the environment keys configured in the Externalizer configuration. The servlet
* uses Externalizer service to generate the externalized URLs via Externalizer.externalLink() method. The response is
* in format {"Author": "Author URL", "Publish": "Publish URL", ...}.
*/
@Component(service = Servlet.class)
krassib marked this conversation as resolved.
Show resolved Hide resolved
@SlingServletResourceTypes(
resourceTypes = PublishUrlServlet.RESOURCE_TYPE,
methods = HttpConstants.METHOD_GET,
extensions = PublishUrlServlet.TXT_EXTENSION
)
@Designate(ocd = PublishUrlServlet.PublishUrlServletConfig.class)
public class PublishUrlServlet extends SlingSafeMethodsServlet implements Serializable {
krassib marked this conversation as resolved.
Show resolved Hide resolved

private static final long serialVersionUID = 1L;
protected static final String RESOURCE_TYPE = "acs-commons/components/utilities/publish-url";
protected static final String TXT_EXTENSION = "txt";
krassib marked this conversation as resolved.
Show resolved Hide resolved
private static final String PATH = "path";
private static final String JSON_TYPE = "application/json";
private String[] externalizerKeys;

@Activate
protected void activate(final PublishUrlServletConfig config) {
this.externalizerKeys = config.externalizerKeys();
}

/**
* Gets the path parameter from the request and generates the externalized URLs for the given path using the
* Externalizer service. Writes the JSON response with the externalized URLs to the response.
* @param request SlingHttpServletRequest
* @param response SlingHttpServletResponse
* @throws IOException if response.getWriter() fails
*/
@Override
protected void doGet(SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response) throws IOException {
String path = request.getParameter(PATH);
ResourceResolver resolver = request.getResourceResolver();
Externalizer externalizer = resolver.adaptTo(Externalizer.class);
ObjectMapper mapper = new ObjectMapper();
ObjectNode jsonResponse = mapper.createObjectNode();

if (externalizer != null) {
Arrays.asList(externalizerKeys).forEach(key -> {
String capitalizedKey = StringUtils.capitalize(key);
String externalLink = externalizer.externalLink(resolver, key, request.getScheme(), path);
jsonResponse.put(capitalizedKey, externalLink);
});
}

response.setContentType(JSON_TYPE);
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.getWriter().write(jsonResponse.toString());
}

@ObjectClassDefinition(
name = "ACS AEM Commons - Publish URL Servlet Configuration",
description = "Configuration for the Publish URL Servlet"
)
public @interface PublishUrlServletConfig {

@AttributeDefinition(
name = "Externalizer Environment Keys",
description = "Externalizer Environment Keys. They need to match the environment keys configured in"
+ " the Externalizer configuration.",
type = AttributeType.STRING
)
String[] externalizerKeys() default {};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*-
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2024 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.wcm.impl;

import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@ExtendWith({MockitoExtension.class, AemContextExtension.class})
krassib marked this conversation as resolved.
Show resolved Hide resolved
class CopySitesPublishUrlFeatureTest {


@InjectMocks
CopySitesPublishUrlFeature copySitesPublishUrlFeature = new CopySitesPublishUrlFeature();
@Mock
CopySitesPublishUrlFeature.Config config;

@BeforeEach
void setUp() {
copySitesPublishUrlFeature.activate(config);
}

@Test
void testGetName() {
assertEquals("com.adobe.acs.commons.wcm.impl.copysitespublishurlfeature.feature.flag",
copySitesPublishUrlFeature.getName());
}

@Test
void testGetDescription() {
assertEquals("ACS AEM Commons feature flag enables or disables the copy publish URL dropdown field in the Sites Editor.",
copySitesPublishUrlFeature.getDescription());
}

@Test
void testIsEnabled() {
when(config.feature_flag_active_status()).thenReturn(true);
assertTrue(copySitesPublishUrlFeature.isEnabled(null));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*-
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2024 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.wcm.impl;

import com.day.cq.commons.Externalizer;
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith({MockitoExtension.class, AemContextExtension.class})
class PublishUrlServletTest {

private final AemContext context = new AemContext();

@InjectMocks
PublishUrlServlet publishUrlServlet = new PublishUrlServlet();
@Mock
Externalizer externalizer;
@Mock
PublishUrlServlet.PublishUrlServletConfig config;

@Test
void testDoGet() throws IOException {
context.registerAdapter(ResourceResolver.class, Externalizer.class, externalizer);
MockSlingHttpServletRequest request = context.request();
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("path", "/content/we-retail/us/en/experience");
request.setParameterMap(requestParams);
when(config.externalizerKeys()).thenReturn(new String[]{"local", "author", "publish", "dispatcher"});
when(externalizer.externalLink(any(ResourceResolver.class), any(String.class), any(String.class), any(String.class)))
.thenReturn("http://localhost:4502/content/we-retail/us/en/experience.html")
.thenReturn("https://aem.author.someorganization.com/content/we-retail/us/en/experience.html")
.thenReturn("https://aem.publish.someorganization.com/content/we-retail/us/en/experience.html")
.thenReturn("https://www.someorganization.com/experience");
publishUrlServlet.activate(config);
MockSlingHttpServletResponse response = context.response();
publishUrlServlet.doGet(request, response);
try(InputStream inputStream = getClass().getResourceAsStream("PublishUrlServletResponse.json")) {
assert inputStream != null;
String expectedJson = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
assertEquals(expectedJson, response.getOutputAsString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Local":"http://localhost:4502/content/we-retail/us/en/experience.html","Author":"https://aem.author.someorganization.com/content/we-retail/us/en/experience.html","Publish":"https://aem.publish.someorganization.com/content/we-retail/us/en/experience.html","Dispatcher":"https://www.someorganization.com/experience"}
Loading
Loading