Skip to content

Commit

Permalink
FORMS-13811 | Adding rendition for hCaptcha (#1174)
Browse files Browse the repository at this point in the history
* embedding forms-sdk api

* adding hcaptcha and recaptcha models

* :fix hcaptcha model SlingException

* :fix deleting recaptcha model

* FORMS-13811 | Adding rendition for hCaptcha

* FORMS-13811 | Renamed public API

* FORMS-13811 | Embedding hcaptcha js

* FORMS-13811 | Adding unit test for sling model

* FORMS-13811 | Adding cypress test

* FORMS-13811 | Adressing review comments

* Adding e2e test

* FORMS-13811 | fix import statements

* Update pom.xml

* Adding FT for running Tests

* FORMS-13811 | Removing java-8 build for master

* Adding FT in test

* FORMS-13811 | Tests should run only with latest addon

* FORMS-13811 | Tests should run only with latest addon

* increasing coverage

* addressing review comments

---------

Co-authored-by: Navneet Agarwal <navneeta@adobe.com>
  • Loading branch information
2 people authored and ci-build committed May 3, 2024
1 parent 96f18e8 commit aa543a3
Show file tree
Hide file tree
Showing 44 changed files with 1,573 additions and 37 deletions.
22 changes: 0 additions & 22 deletions .circleci/config.yml
Expand Up @@ -175,21 +175,6 @@ jobs:
conf: .circleci/codecov.yml
flags: unittests

build-java-8:
executor: forms_executor_java8
working_directory: /home/circleci/build
steps:
- checkout
- *restore_cache
- run:
name: Update permissions
command: sudo chown -R circleci /usr/local/lib/node_modules
- run:
name: Build
command: node .circleci/ci/build.js
- store_artifacts:
path: test-results/junit

cypress-chrome-cloudready-with-addon:
executor: test_executor_cloudready
environment:
Expand Down Expand Up @@ -431,31 +416,24 @@ workflows:
filters:
tags:
only: /.*/
- build-java-8:
filters:
tags:
only: /.*/
- cypress-chrome-cloudready-with-addon:
filters:
tags:
only: /.*/
requires:
- build-java-11
- build-java-8
- cypress-chrome-cloudready-with-latest-addon:
filters:
tags:
only: /.*/
requires:
- build-java-11
- build-java-8
- cypress-chrome-cloudready-with-latest-addon-without-ft:
filters:
tags:
only: /.*/
requires:
- build-java-11
- build-java-8
- jsdocs-deploy:
requires:
- build-java-11
Expand Down
Expand Up @@ -71,6 +71,9 @@ private FormConstants() {
/** The resource type for check box group v1 */
public static final String RT_FD_FORM_CHECKBOX_GROUP_V1 = RT_FD_FORM_PREFIX + "checkboxgroup/v1/checkboxgroup";

/** The resource type for reCaptcha v1 */
public static final String RT_FD_FORM_HCAPTCHA_V1 = RT_FD_FORM_PREFIX + "hcaptcha/v1/hcaptcha";

/** The resource type for reCaptcha v1 */
public static final String RT_FD_FORM_RECAPTCHA_V1 = RT_FD_FORM_PREFIX + "recaptcha/v1/recaptcha";

Expand Down
@@ -0,0 +1,125 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 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.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.forms.core.components.internal.models.v1.form;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.aemds.guide.model.HCaptchaConfiguration;
import com.adobe.aemds.guide.service.CloudConfigurationProvider;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
import com.adobe.cq.forms.core.components.models.form.HCaptcha;
import com.adobe.cq.forms.core.components.util.AbstractCaptchaImpl;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Model(
adaptables = { SlingHttpServletRequest.class, Resource.class },
adapters = { HCaptcha.class,
ComponentExporter.class },
resourceType = { FormConstants.RT_FD_FORM_HCAPTCHA_V1 })
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class HCaptchaImpl extends AbstractCaptchaImpl implements HCaptcha {

private static final Logger LOGGER = LoggerFactory.getLogger(HCaptchaImpl.class);

@Inject
private ResourceResolver resourceResolver;

private Resource resource;

@Reference
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
private HCaptchaConfiguration hCaptchaConfiguration;

@OSGiService
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
private CloudConfigurationProvider cloudConfigurationProvider;

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
@JsonIgnore
@Named("cloudServicePath")
protected String cloudServicePath;

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
@JsonIgnore
@Named("size")
protected String size;

private static final String SITE_KEY = "siteKey";
private static final String URI = "uri";
private static final String SIZE = "size";
private static final String THEME = "theme";
private static final String TYPE = "type";

@Override
public String getCloudServicePath() {
return cloudServicePath;
}

@Override
public String getProvider() {
return "hcaptcha";
}

@Override
public Map<String, Object> getCaptchaProperties() throws GuideException {

Map<String, Object> customCaptchaProperties = new LinkedHashMap<>();
String siteKey = null, uri = null;
resource = resourceResolver.getResource(this.getPath());
if (cloudConfigurationProvider == null) {
LOGGER.info("[AF] [Captcha] [HCAPTCHA] Error while fetching cloud configuration, upgrade to latest release to use hCaptcha.");
}
try {
if (resource != null && cloudConfigurationProvider != null) {
hCaptchaConfiguration = cloudConfigurationProvider.getHCaptchaCloudConfiguration(resource);
if (hCaptchaConfiguration != null) {
siteKey = hCaptchaConfiguration.getSiteKey();
uri = hCaptchaConfiguration.getClientSideJsUrl();
}
}
} catch (GuideException e) {
LOGGER.error("[AF] [Captcha] [HCAPTCHA] Error while fetching cloud configuration, upgrade to latest release to use hCaptcha.");
}
customCaptchaProperties.put(SITE_KEY, siteKey);
customCaptchaProperties.put(URI, uri);
customCaptchaProperties.put(SIZE, this.size);
customCaptchaProperties.put(THEME, "light");
customCaptchaProperties.put(TYPE, "image");

return customCaptchaProperties;

}

}
Expand Up @@ -23,8 +23,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;

/**
* Defines the form {@code Captcha} Sling Model used for the {@code /apps/core/fd/components/form/recaptcha/v1/recaptcha}
* component.
* Defines a base interface to be extended by all the different types of captcha.
*
* @since com.adobe.cq.forms.core.components.models.form 2.0.0
*/
Expand Down
@@ -0,0 +1,27 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 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.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.forms.core.components.models.form;

import org.osgi.annotation.versioning.ConsumerType;

/**
* Defines the form {@code HCaptcha} Sling Model used for the {@code /apps/core/fd/components/form/hcaptcha/v1/hcaptcha}
* component.
*
* @since com.adobe.cq.forms.core.components.models.form 5.4.0
*/
@ConsumerType
public interface HCaptcha extends Captcha {}
Expand Up @@ -34,7 +34,7 @@
* version, is bound to this proxy component resource type.
* </p>
*/
@Version("5.3.1") // aligning this with release/650 since af2-rest-api is compiled with 5.2.0 in release/650
@Version("5.4.0") // aligning this with release/650 since af2-rest-api is compiled with 5.2.0 in release/650
package com.adobe.cq.forms.core.components.models.form;

import org.osgi.annotation.versioning.Version;
@@ -0,0 +1,140 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 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.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.forms.core.components.internal.models.v1.form;

import org.apache.sling.api.resource.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;

import com.adobe.aemds.guide.model.HCaptchaConfiguration;
import com.adobe.aemds.guide.model.ReCaptchaConfigurationModel;
import com.adobe.aemds.guide.service.CloudConfigurationProvider;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.cq.forms.core.Utils;
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
import com.adobe.cq.forms.core.components.models.form.Captcha;
import com.adobe.cq.forms.core.components.models.form.FieldType;
import com.adobe.cq.forms.core.components.models.form.HCaptcha;
import com.adobe.cq.forms.core.context.FormsCoreComponentTestContext;
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@ExtendWith(AemContextExtension.class)
public class HCaptchaImplTest {
private static final String BASE = "/form/hcaptcha";
private static final String CONTENT_ROOT = "/content";
private static final String PATH_HCAPTCHA = CONTENT_ROOT + "/hcaptcha";

private final AemContext context = FormsCoreComponentTestContext.newAemContext();

HCaptchaConfiguration hCaptchaConfiguration = Mockito.mock(HCaptchaConfiguration.class);

CloudConfigurationProvider cloudConfigurationProvider = new CloudConfigurationProvider() {
@Override
public ReCaptchaConfigurationModel getRecaptchaCloudConfiguration(Resource resource) throws GuideException {
return null;
}

@Override
public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException {
return hCaptchaConfiguration;
}
};

@BeforeEach
void setUp() throws GuideException {
context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT);
context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
}

@Test
void testExportedType() {
Captcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals(FormConstants.RT_FD_FORM_HCAPTCHA_V1, hCaptcha.getExportedType());
HCaptcha hcaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hcaptchaMock.getExportedType()).thenCallRealMethod();
assertEquals("", hcaptchaMock.getExportedType());
}

@Test
void testFieldType() {
HCaptcha hcaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals(FieldType.CAPTCHA.getValue(), hcaptcha.getFieldType());
}

@Test
void testGetName() {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals("test-hcaptcha", hCaptcha.getName());
HCaptcha hcaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hcaptchaMock.getName()).thenCallRealMethod();
assertEquals(null, hcaptchaMock.getName());
}

@Test
void testGetHCaptchaProvider() {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals("hcaptcha", hCaptcha.getProvider());
HCaptcha hcaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hcaptchaMock.getName()).thenCallRealMethod();
assertEquals(null, hcaptchaMock.getName());
}

@Test
void testGetConfigurationPath() {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals("always-challenge", hCaptcha.getCloudServicePath());
HCaptcha hCaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hCaptchaMock.getName()).thenCallRealMethod();
assertEquals(null, hCaptchaMock.getName());
}

@Test
void testIsVisible() {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals(true, hCaptcha.isVisible());
HCaptcha hCaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hCaptchaMock.isVisible()).thenCallRealMethod();
assertEquals(null, hCaptchaMock.isVisible());
}

@Test
void testIsEnabled() {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertEquals(true, hCaptcha.isEnabled());
HCaptcha hCaptchaMock = Mockito.mock(HCaptcha.class);
Mockito.when(hCaptchaMock.isEnabled()).thenCallRealMethod();
assertEquals(null, hCaptchaMock.isEnabled());
}

@Test
void testJSONExport() throws Exception {
HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
Utils.testJSONExport(hCaptcha, Utils.getTestExporterJSONPath(BASE, PATH_HCAPTCHA));
}

@Test
void hCaptchaConfigExceptionTest() throws GuideException {
Mockito.when(hCaptchaConfiguration.getSiteKey()).thenThrow(new GuideException("Error while fetching site key"));
HCaptcha hcaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
assertNotNull(hcaptcha.getCaptchaProperties());
}
}
Expand Up @@ -21,6 +21,7 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;

import com.adobe.aemds.guide.model.HCaptchaConfiguration;
import com.adobe.aemds.guide.model.ReCaptchaConfigurationModel;
import com.adobe.aemds.guide.service.CloudConfigurationProvider;
import com.adobe.aemds.guide.service.GuideException;
Expand Down Expand Up @@ -49,6 +50,11 @@ public class RecaptchaImplTest {
public ReCaptchaConfigurationModel getRecaptchaCloudConfiguration(Resource resource) throws GuideException {
return reCaptchaConfiguration;
}

@Override
public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException {
return null;
}
};

@BeforeEach
Expand Down

0 comments on commit aa543a3

Please sign in to comment.