From cf4a2cbe73630a88f29a98baf602a66461fc081c Mon Sep 17 00:00:00 2001
From: Navneet Agarwal
Date: Thu, 20 Jun 2024 20:40:19 +0530
Subject: [PATCH 1/3] FORMS-14468 | Updating Captcha interface and it's
implementation
---
.../internal/form/FormConstants.java | 8 +-
.../internal/models/v1/form/HCaptchaImpl.java | 30 ++--
.../models/v1/form/RecaptchaImpl.java | 33 ++--
.../models/v2/form/HCaptchaImplV2.java | 113 ++++++++++++
.../models/v2/form/RecaptchaImplV2.java | 127 ++++++++++++++
.../core/components/models/form/Captcha.java | 49 +++++-
.../components/models/form/package-info.java | 2 +-
.../components/util/AbstractCaptchaImpl.java | 9 +-
.../models/v2/form/HCaptchaImplV2Test.java | 160 +++++++++++++++++
.../models/v2/form/RecaptchaImplV2Test.java | 163 ++++++++++++++++++
.../form/hcaptchav2/exporter-hcaptcha.json | 38 ++++
.../form/hcaptchav2/test-content.json | 22 +++
.../form/recaptchav2/exporter-recaptcha.json | 37 ++++
.../form/recaptchav2/test-content.json | 27 +++
14 files changed, 778 insertions(+), 40 deletions(-)
create mode 100644 bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2.java
create mode 100644 bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
create mode 100644 bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
create mode 100644 bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
create mode 100644 bundles/af-core/src/test/resources/form/hcaptchav2/exporter-hcaptcha.json
create mode 100644 bundles/af-core/src/test/resources/form/hcaptchav2/test-content.json
create mode 100644 bundles/af-core/src/test/resources/form/recaptchav2/exporter-recaptcha.json
create mode 100644 bundles/af-core/src/test/resources/form/recaptchav2/test-content.json
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
index d370d5ee42..60f3acdef7 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
@@ -71,12 +71,18 @@ 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 */
+ /** The resource type for hCaptcha v1 */
public static final String RT_FD_FORM_HCAPTCHA_V1 = RT_FD_FORM_PREFIX + "hcaptcha/v1/hcaptcha";
+ /** The resource type for hCaptcha v2 */
+ public static final String RT_FD_FORM_HCAPTCHA_V2 = RT_FD_FORM_PREFIX + "hcaptcha/v2/hcaptcha";
+
/** The resource type for reCaptcha v1 */
public static final String RT_FD_FORM_RECAPTCHA_V1 = RT_FD_FORM_PREFIX + "recaptcha/v1/recaptcha";
+ /** The resource type for reCaptcha v2 */
+ public static final String RT_FD_FORM_RECAPTCHA_V2 = RT_FD_FORM_PREFIX + "recaptcha/v2/recaptcha";
+
/** The resource type for radio button v1 */
public static final String RT_FD_FORM_RADIO_BUTTON_V1 = RT_FD_FORM_PREFIX + "radiobutton/v1/radiobutton";
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImpl.java
index ab71bb7d9e..528dc19bac 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImpl.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImpl.java
@@ -52,19 +52,20 @@
public class HCaptchaImpl extends AbstractCaptchaImpl implements HCaptcha {
private static final Logger LOGGER = LoggerFactory.getLogger(HCaptchaImpl.class);
+ protected static final String HCAPTCHA_CONFIG_FETCH_ERROR = "[AF] [CAPTCHA] [HCAPTCHA] Error while fetching cloud configuration, upgrade to latest release to use hCaptcha.";
@Inject
- private ResourceResolver resourceResolver;
+ protected ResourceResolver resourceResolver;
- private Resource resource;
+ protected Resource resource;
@Reference
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
- private HCaptchaConfiguration hCaptchaConfiguration;
+ protected HCaptchaConfiguration hCaptchaConfiguration;
@OSGiService
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
- private CloudConfigurationProvider cloudConfigurationProvider;
+ protected CloudConfigurationProvider cloudConfigurationProvider;
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
@JsonIgnore
@@ -76,18 +77,13 @@ public class HCaptchaImpl extends AbstractCaptchaImpl implements HCaptcha {
@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
+ @JsonIgnore
public String getProvider() {
return "hcaptcha";
}
@@ -99,7 +95,7 @@ public Map getCaptchaProperties() throws GuideException {
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.");
+ LOGGER.info(HCAPTCHA_CONFIG_FETCH_ERROR);
}
try {
if (resource != null && cloudConfigurationProvider != null) {
@@ -110,13 +106,13 @@ public Map getCaptchaProperties() throws GuideException {
}
}
} catch (GuideException e) {
- LOGGER.error("[AF] [Captcha] [HCAPTCHA] Error while fetching cloud configuration, upgrade to latest release to use hCaptcha.");
+ LOGGER.error(HCAPTCHA_CONFIG_FETCH_ERROR, e);
}
- customCaptchaProperties.put(SITE_KEY, siteKey);
- customCaptchaProperties.put(URI, uri);
- customCaptchaProperties.put(SIZE, this.size);
- customCaptchaProperties.put(THEME, "light");
- customCaptchaProperties.put(TYPE, "image");
+ customCaptchaProperties.put(CAPTCHA_SITE_KEY, siteKey);
+ customCaptchaProperties.put(CAPTCHA_URI, uri);
+ customCaptchaProperties.put(CAPTCHA_SIZE, this.size);
+ customCaptchaProperties.put(CAPTCHA_THEME, CAPTCHA_THEME_LIGHT);
+ customCaptchaProperties.put(CAPTCHA_TYPE, CAPTCHA_TYPE_IMAGE);
return customCaptchaProperties;
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImpl.java
index 3161772904..e28bb41d98 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImpl.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImpl.java
@@ -35,6 +35,7 @@
import com.adobe.aemds.guide.model.ReCaptchaConfigurationModel;
import com.adobe.aemds.guide.service.CloudConfigurationProvider;
import com.adobe.aemds.guide.service.GuideException;
+import com.adobe.aemds.guide.utils.GuideConstants;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
@@ -51,17 +52,17 @@
public class RecaptchaImpl extends AbstractCaptchaImpl implements Captcha {
@Inject
- private ResourceResolver resourceResolver;
+ protected ResourceResolver resourceResolver;
- private Resource resource;
+ protected Resource resource;
@Reference
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
- private ReCaptchaConfigurationModel reCaptchaConfiguration;
+ protected ReCaptchaConfigurationModel reCaptchaConfiguration;
@OSGiService
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
- private CloudConfigurationProvider cloudConfigurationProvider;
+ protected CloudConfigurationProvider cloudConfigurationProvider;
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
@JsonIgnore
@@ -77,13 +78,8 @@ public class RecaptchaImpl extends AbstractCaptchaImpl implements Captcha {
public static final String RECAPTCHA_DEFAULT_URL = RECAPTCHA_DEFAULT_DOMAIN + "recaptcha/api.js";
public static final String RECAPTCHA_ENTERPRISE_DEFAULT_URL = RECAPTCHA_DEFAULT_DOMAIN + "recaptcha/enterprise.js";
- private static final String RECAPTCHA_SITE_KEY = "siteKey";
- private static final String RECAPTCHA_URI = "uri";
- private static final String RECAPTCHA_SIZE = "size";
- private static final String RECAPTCHA_THEME = "theme";
- private static final String RECAPTCHA_TYPE = "type";
- private static final String RECAPTCHA_VERSION = "version";
- private static final String RECAPTCHA_KEYTYPE = "keyType";
+ public static final String RECAPTCHA_VERSION = "version";
+ public static final String RECAPTCHA_KEYTYPE = "keyType";
@Override
@JsonIgnore
@@ -97,6 +93,7 @@ public String getSize() {
}
@Override
+ @JsonIgnore
public String getProvider() {
return "recaptcha";
}
@@ -118,15 +115,15 @@ public Map getCaptchaProperties() throws GuideException {
keyType = reCaptchaConfiguration.keyType();
}
}
- customCaptchaProperties.put(RECAPTCHA_SITE_KEY, siteKey);
- if (StringUtils.isNotEmpty(version) && version.equals("enterprise")) {
- customCaptchaProperties.put(RECAPTCHA_URI, RECAPTCHA_ENTERPRISE_DEFAULT_URL);
+ customCaptchaProperties.put(CAPTCHA_SITE_KEY, siteKey);
+ if (StringUtils.isNotEmpty(version) && version.equals(GuideConstants.RECAPTCHA_ENTERPRISE_VERSION)) {
+ customCaptchaProperties.put(CAPTCHA_URI, RECAPTCHA_ENTERPRISE_DEFAULT_URL);
} else {
- customCaptchaProperties.put(RECAPTCHA_URI, RECAPTCHA_DEFAULT_URL);
+ customCaptchaProperties.put(CAPTCHA_URI, RECAPTCHA_DEFAULT_URL);
}
- customCaptchaProperties.put(RECAPTCHA_SIZE, getSize());
- customCaptchaProperties.put(RECAPTCHA_THEME, "light");
- customCaptchaProperties.put(RECAPTCHA_TYPE, "image");
+ customCaptchaProperties.put(CAPTCHA_SIZE, getSize());
+ customCaptchaProperties.put(CAPTCHA_THEME, CAPTCHA_THEME_LIGHT);
+ customCaptchaProperties.put(CAPTCHA_TYPE, CAPTCHA_TYPE_IMAGE);
customCaptchaProperties.put(RECAPTCHA_VERSION, version);
customCaptchaProperties.put(RECAPTCHA_KEYTYPE, keyType);
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2.java
new file mode 100644
index 0000000000..c222fe2fcb
--- /dev/null
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2.java
@@ -0,0 +1,113 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.v2.form;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Exporter;
+import org.apache.sling.models.annotations.Model;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.internal.models.v1.form.HCaptchaImpl;
+import com.adobe.cq.forms.core.components.models.form.HCaptcha;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+@Model(
+ adaptables = { SlingHttpServletRequest.class, Resource.class },
+ adapters = { HCaptcha.class,
+ ComponentExporter.class },
+ resourceType = { FormConstants.RT_FD_FORM_HCAPTCHA_V2 })
+@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
+public class HCaptchaImplV2 extends HCaptchaImpl {
+ private static final Logger LOGGER = LoggerFactory.getLogger(HCaptchaImplV2.class);
+
+ private String captchaSiteKey;
+
+ @Override
+ @JsonIgnore(false)
+ public String getProvider() {
+ return super.getProvider();
+ }
+
+ /**
+ * Set the hCaptchaConfiguration, by fetching it from the cloud configurations.
+ * Also sets the captchaSiteKey.
+ */
+ private void setHCaptchaConfiguration() {
+ if (cloudConfigurationProvider != null) {
+ try {
+ resource = resourceResolver.getResource(this.getPath());
+ hCaptchaConfiguration = cloudConfigurationProvider.getHCaptchaCloudConfiguration(resource);
+ if (hCaptchaConfiguration != null) {
+ captchaSiteKey = hCaptchaConfiguration.getSiteKey();
+ }
+ } catch (GuideException e) {
+ LOGGER.error(HCAPTCHA_CONFIG_FETCH_ERROR, e);
+ }
+ } else {
+ LOGGER.error(HCAPTCHA_CONFIG_FETCH_ERROR);
+ }
+ }
+
+ @PostConstruct
+ @Override
+ public Map getCaptchaProperties() throws GuideException {
+
+ Map customCaptchaProperties = new LinkedHashMap<>();
+ String uri = null;
+ if (hCaptchaConfiguration == null) {
+ setHCaptchaConfiguration();
+ }
+ if (hCaptchaConfiguration != null) {
+ uri = hCaptchaConfiguration.getClientSideJsUrl();
+ }
+ customCaptchaProperties.put(CAPTCHA_URI, uri);
+ customCaptchaProperties.put(CAPTCHA_SIZE, this.size);
+ customCaptchaProperties.put(CAPTCHA_THEME, CAPTCHA_THEME_LIGHT);
+ customCaptchaProperties.put(CAPTCHA_TYPE, CAPTCHA_TYPE_IMAGE);
+ return customCaptchaProperties;
+ }
+
+ @PostConstruct
+ @Override
+ public String getCaptchaDisplayMode() {
+ CaptchaDisplayMode captchaDisplayMode = CaptchaDisplayMode.VISIBLE;
+ if (CaptchaDisplayMode.INVISIBLE.getValue().equals(this.size)) {
+ captchaDisplayMode = CaptchaDisplayMode.INVISIBLE;
+ }
+ return captchaDisplayMode.getValue();
+ }
+
+ @PostConstruct
+ @Override
+ public String getCaptchaSiteKey() {
+ if (hCaptchaConfiguration == null) {
+ setHCaptchaConfiguration();
+ }
+ return this.captchaSiteKey;
+ }
+}
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
new file mode 100644
index 0000000000..d257af452e
--- /dev/null
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
@@ -0,0 +1,127 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.v2.form;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Exporter;
+import org.apache.sling.models.annotations.Model;
+
+import com.adobe.aemds.guide.service.GuideException;
+import com.adobe.aemds.guide.utils.GuideConstants;
+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.internal.models.v1.form.RecaptchaImpl;
+import com.adobe.cq.forms.core.components.models.form.Captcha;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+@Model(
+ adaptables = { SlingHttpServletRequest.class, Resource.class },
+ adapters = { Captcha.class,
+ ComponentExporter.class },
+ resourceType = { FormConstants.RT_FD_FORM_RECAPTCHA_V2 })
+@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
+public class RecaptchaImplV2 extends RecaptchaImpl {
+ public static final String RECAPTCHA_ENT_PROVIDER = "recaptchaEnterprise";
+ public static final String RECAPTCHA_V2_PROVIDER = "recaptchaV2";
+
+ private String captchaProvider;
+ private CaptchaDisplayMode captchaDisplayMode;
+ private String captchaSiteKey;
+
+ @PostConstruct
+ @Override
+ @JsonIgnore(false)
+ public String getProvider() {
+ if (reCaptchaConfiguration == null) {
+ setReCaptchaConfiguration();
+ }
+ return this.captchaProvider;
+ }
+
+ /**
+ * Set the reCaptchaConfiguration, by fetching it from the cloud configurations.
+ * Also sets the captchaSiteKey, version, keyType, captchaProvider and captchaDisplayMode.
+ */
+ private void setReCaptchaConfiguration() {
+ resource = resourceResolver.getResource(this.getPath());
+ if (resource != null && cloudConfigurationProvider != null) {
+ reCaptchaConfiguration = cloudConfigurationProvider.getRecaptchaCloudConfiguration(resource);
+ if (reCaptchaConfiguration != null) {
+ captchaSiteKey = reCaptchaConfiguration.siteKey();
+ String version = reCaptchaConfiguration.version();
+ String keyType = reCaptchaConfiguration.keyType();
+ if (GuideConstants.RECAPTCHA_ENTERPRISE_VERSION.equals(version)) {
+ captchaDisplayMode = GuideConstants.RECAPTCHA_SCORE_KEY.equals(keyType) ? CaptchaDisplayMode.INVISIBLE
+ : CaptchaDisplayMode.VISIBLE;
+ captchaProvider = RECAPTCHA_ENT_PROVIDER;
+ } else {
+ captchaDisplayMode = CaptchaDisplayMode.INVISIBLE.getValue().equals(getSize()) ? CaptchaDisplayMode.INVISIBLE
+ : CaptchaDisplayMode.VISIBLE;
+ captchaProvider = RECAPTCHA_V2_PROVIDER;
+ }
+ }
+ }
+ }
+
+ @PostConstruct
+ @JsonIgnore
+ @Override
+ public Map getCaptchaProperties() throws GuideException {
+
+ Map customCaptchaProperties = new LinkedHashMap<>();
+ if (reCaptchaConfiguration == null) {
+ setReCaptchaConfiguration();
+ }
+ if (StringUtils.isNotEmpty(captchaProvider) && RECAPTCHA_ENT_PROVIDER.equals(captchaProvider)) {
+ customCaptchaProperties.put(CAPTCHA_URI, RECAPTCHA_ENTERPRISE_DEFAULT_URL);
+ } else {
+ customCaptchaProperties.put(CAPTCHA_URI, RECAPTCHA_DEFAULT_URL);
+ }
+ customCaptchaProperties.put(CAPTCHA_SIZE, this.getSize());
+ customCaptchaProperties.put(CAPTCHA_THEME, CAPTCHA_THEME_LIGHT);
+ customCaptchaProperties.put(CAPTCHA_TYPE, CAPTCHA_TYPE_IMAGE);
+
+ return customCaptchaProperties;
+
+ }
+
+ @PostConstruct
+ @Override
+ public String getCaptchaDisplayMode() {
+ if (reCaptchaConfiguration == null) {
+ setReCaptchaConfiguration();
+ }
+ return this.captchaDisplayMode.getValue();
+ }
+
+ @PostConstruct
+ @Override
+ public String getCaptchaSiteKey() {
+ if (reCaptchaConfiguration == null) {
+ setReCaptchaConfiguration();
+ }
+ return this.captchaSiteKey;
+ }
+}
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Captcha.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Captcha.java
index 3fcc130f5a..e75471df34 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Captcha.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Captcha.java
@@ -21,6 +21,7 @@
import com.adobe.aemds.guide.service.GuideException;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Defines a base interface to be extended by all the different types of captcha.
@@ -30,15 +31,61 @@
@ConsumerType
public interface Captcha extends Field {
+ /**
+ * Defines the display mode for captcha.
+ * Possible values: {@code visible}, {@code invisible}
+ *
+ * @since com.adobe.cq.forms.core.components.models.form 5.4.4
+ */
+ enum CaptchaDisplayMode {
+ VISIBLE("visible"),
+ INVISIBLE("invisible");
+
+ private String displayMode;
+
+ CaptchaDisplayMode(String displayMode) {
+ this.displayMode = displayMode;
+ }
+
+ /**
+ * Returns the string value of this enum constant.
+ *
+ * @return the string value of this enum constant
+ * @since com.adobe.cq.forms.core.components.models.form 5.4.4
+ */
+ public String getValue() {
+ return displayMode;
+ }
+ }
+
@JsonIgnore
default String getCloudServicePath() {
return null;
}
- @JsonIgnore
+ @JsonProperty("captchaProvider")
String getProvider();
@JsonIgnore
Map getCaptchaProperties() throws GuideException;
+ /**
+ * Returns the display mode of the captcha component.
+ *
+ * @return the string value of the one of the {@link CaptchaDisplayMode} enum
+ * @since com.adobe.cq.forms.core.components.models.form 5.4.4
+ */
+ default String getCaptchaDisplayMode() {
+ return null;
+ }
+
+ /**
+ * Returns the site key of the captcha component.
+ *
+ * @return the site key
+ * @since com.adobe.cq.forms.core.components.models.form 5.4.4
+ */
+ default String getCaptchaSiteKey() {
+ return null;
+ }
}
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java
index ba286aa482..af4c9dd8d5 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java
@@ -35,7 +35,7 @@
*
*/
-@Version("5.4.3") // aligning this with release/650 since af2-rest-api is compiled with 5.2.0 in release/650
+@Version("5.4.4") // 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;
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/util/AbstractCaptchaImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/util/AbstractCaptchaImpl.java
index f3b9011bd1..3ad67a6727 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/util/AbstractCaptchaImpl.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/util/AbstractCaptchaImpl.java
@@ -20,15 +20,20 @@
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.cq.forms.core.components.models.form.Captcha;
-import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Abstract class which can be used as base class for {@link Captcha} implementations.
*/
public abstract class AbstractCaptchaImpl extends AbstractFieldImpl implements Captcha {
public static final String CUSTOM_RECAPTCHA_PROPERTY_WRAPPER = "fd:captcha";
+ public static final String CAPTCHA_SITE_KEY = "siteKey";
+ public static final String CAPTCHA_URI = "uri";
+ public static final String CAPTCHA_SIZE = "size";
+ public static final String CAPTCHA_THEME = "theme";
+ public static final String CAPTCHA_THEME_LIGHT = "light";
+ public static final String CAPTCHA_TYPE = "type";
+ public static final String CAPTCHA_TYPE_IMAGE = "image";
- @JsonIgnore
public abstract String getProvider();
public abstract Map getCaptchaProperties();
diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
new file mode 100644
index 0000000000..584eebc642
--- /dev/null
+++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
@@ -0,0 +1,160 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.v2.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;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AemContextExtension.class)
+public class HCaptchaImplV2Test {
+ private static final String BASE = "/form/hcaptchav2";
+ 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);
+ Mockito.when(hCaptchaConfiguration.getSiteKey()).thenReturn("dummySiteKey");
+ Mockito.when(hCaptchaConfiguration.getClientSideJsUrl()).thenReturn("https://js.hcaptcha.com/1/api.js");
+ }
+
+ @Test
+ void testExportedType() {
+ Captcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals(FormConstants.RT_FD_FORM_HCAPTCHA_V2, 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());
+ }
+
+ @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.getCloudServicePath()).thenCallRealMethod();
+ assertEquals(null, hCaptchaMock.getCloudServicePath());
+ }
+
+ @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());
+ }
+
+ @Test
+ void testCaptchaDisplayMode() {
+ HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals("invisible", hCaptcha.getCaptchaDisplayMode());
+ Captcha hcaptchaMock = Mockito.mock(Captcha.class);
+ when(hcaptchaMock.getCaptchaDisplayMode()).thenCallRealMethod();
+ assertEquals(null, hcaptchaMock.getCaptchaDisplayMode());
+ }
+
+ @Test
+ void testCaptchaSiteKey() {
+ HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals("dummySiteKey", hCaptcha.getCaptchaSiteKey());
+ Captcha hcaptchaMock = Mockito.mock(Captcha.class);
+ when(hcaptchaMock.getCaptchaDisplayMode()).thenCallRealMethod();
+ assertEquals(null, hcaptchaMock.getCaptchaSiteKey());
+ }
+
+}
diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
new file mode 100644
index 0000000000..4474608a40
--- /dev/null
+++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
@@ -0,0 +1,163 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.v2.form;
+
+import java.util.Map;
+
+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.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.mockito.Mockito.when;
+
+@ExtendWith(AemContextExtension.class)
+
+public class RecaptchaImplV2Test {
+ private static final String BASE = "/form/recaptchav2";
+ private static final String CONTENT_ROOT = "/content";
+ private static final String PATH_RECAPTCHA = CONTENT_ROOT + "/recaptcha";
+
+ private final AemContext context = FormsCoreComponentTestContext.newAemContext();
+
+ ReCaptchaConfigurationModel reCaptchaConfiguration = Mockito.mock(ReCaptchaConfigurationModel.class);
+
+ CloudConfigurationProvider cloudConfigurationProvider = new CloudConfigurationProvider() {
+ @Override
+ public ReCaptchaConfigurationModel getRecaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return reCaptchaConfiguration;
+ }
+
+ @Override
+ public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return null;
+ }
+ };
+
+ @BeforeEach
+ void setUp() throws GuideException {
+ context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT);
+ context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
+ Mockito.when(reCaptchaConfiguration.siteKey()).thenReturn("dummySiteKey");
+ Mockito.when(reCaptchaConfiguration.version()).thenReturn("enterprise");
+ Mockito.when(reCaptchaConfiguration.keyType()).thenReturn("score");
+ }
+
+ @Test
+ void testExportedType() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals(FormConstants.RT_FD_FORM_RECAPTCHA_V2, recaptcha.getExportedType());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.getExportedType()).thenCallRealMethod();
+ assertEquals("", recaptchaMock.getExportedType());
+ }
+
+ @Test
+ void testFieldType() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals(FieldType.CAPTCHA.getValue(), recaptcha.getFieldType());
+ }
+
+ @Test
+ void testGetName() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals("test-recaptcha", recaptcha.getName());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.getName()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.getName());
+ }
+
+ @Test
+ void testGetRecaptchaProvider() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals("recaptchaEnterprise", recaptcha.getProvider());
+ }
+
+ @Test
+ void testGetConfigurationPath() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals("enterpriseScore", recaptcha.getCloudServicePath());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.getCloudServicePath()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.getCloudServicePath());
+ }
+
+ @Test
+ void testIsVisible() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals(true, recaptcha.isVisible());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.isVisible()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.isVisible());
+ }
+
+ @Test
+ void testIsEnabled() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals(true, recaptcha.isEnabled());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.isEnabled()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.isEnabled());
+ }
+
+ @Test
+ void testJSONExport() throws Exception {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ Utils.testJSONExport(recaptcha, Utils.getTestExporterJSONPath(BASE, PATH_RECAPTCHA));
+ }
+
+ @Test
+ void testEnterpriseUrl() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ Map captchaProps = recaptcha.getCaptchaProperties();
+ String enterpriseUrl = (String) captchaProps.get("uri");
+ assertEquals("https://www.recaptcha.net/recaptcha/enterprise.js", enterpriseUrl);
+ }
+
+ @Test
+ void testCaptchaDisplayMode() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals("invisible", recaptcha.getCaptchaDisplayMode());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.getCaptchaDisplayMode()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.getCaptchaDisplayMode());
+ }
+
+ @Test
+ void testCaptchaSiteKey() {
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals("dummySiteKey", recaptcha.getCaptchaSiteKey());
+ Captcha recaptchaMock = Mockito.mock(Captcha.class);
+ when(recaptchaMock.getCaptchaDisplayMode()).thenCallRealMethod();
+ assertEquals(null, recaptchaMock.getCaptchaSiteKey());
+ }
+
+}
diff --git a/bundles/af-core/src/test/resources/form/hcaptchav2/exporter-hcaptcha.json b/bundles/af-core/src/test/resources/form/hcaptchav2/exporter-hcaptcha.json
new file mode 100644
index 0000000000..12f31c7df5
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/hcaptchav2/exporter-hcaptcha.json
@@ -0,0 +1,38 @@
+{
+ "id": "hcaptcha-abc574167c",
+ "fieldType": "captcha",
+ "name": "test-hcaptcha",
+ "visible": true,
+ "type": "string",
+ "required": true,
+ "enabled": true,
+ "readOnly": false,
+ "captchaDisplayMode": "invisible",
+ "captchaProvider": "hcaptcha",
+ "captchaSiteKey": "dummySiteKey",
+ "label": {
+ "visible": true,
+ "value": "HCAPTCHA"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/hcaptcha",
+ "fd:captcha": {
+ "provider": "hcaptcha",
+ "config": {
+ "uri": "https://js.hcaptcha.com/1/api.js",
+ "size": "invisible",
+ "theme": "light",
+ "type": "image"
+ }
+ }
+ },
+ ":type": "core/fd/components/form/hcaptcha/v2/hcaptcha"
+}
diff --git a/bundles/af-core/src/test/resources/form/hcaptchav2/test-content.json b/bundles/af-core/src/test/resources/form/hcaptchav2/test-content.json
new file mode 100644
index 0000000000..9f4d3c57af
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/hcaptchav2/test-content.json
@@ -0,0 +1,22 @@
+{
+ "hcaptcha": {
+ "jcr:primaryType": "nt:unstructured",
+ "jcr:createdBy": "admin",
+ "jcr:title": "HCAPTCHA",
+ "enabled": true,
+ "jcr:lastModifiedBy": "admin",
+ "readOnly": false,
+ "required": true,
+ "jcr:created": "Thu Apr 11 2024 10:37:33 GMT+0530",
+ "name": "test-hcaptcha",
+ "size": "invisible",
+ "cloudServicePath": "always-challenge",
+ "visible": true,
+ "hideTitle": "false",
+ "jcr:lastModified": "Thu Apr 11 2024 10:37:39 GMT+0530",
+ "sling:resourceType": "core/fd/components/form/hcaptcha/v2/hcaptcha",
+ "fieldType": "captcha",
+ "textIsRich": "true",
+ "unboundFormElement": false
+ }
+}
diff --git a/bundles/af-core/src/test/resources/form/recaptchav2/exporter-recaptcha.json b/bundles/af-core/src/test/resources/form/recaptchav2/exporter-recaptcha.json
new file mode 100644
index 0000000000..8edaaa7bf2
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/recaptchav2/exporter-recaptcha.json
@@ -0,0 +1,37 @@
+{
+ "id": "recaptcha-4b672680a2",
+ "fieldType": "captcha",
+ "name": "test-recaptcha",
+ "visible": true,
+ "type": "string",
+ "enabled": true,
+ "readOnly": false,
+ "captchaDisplayMode": "invisible",
+ "captchaProvider": "recaptchaEnterprise",
+ "captchaSiteKey": "dummySiteKey",
+ "label": {
+ "visible": true,
+ "value": "CAPTCHA"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/recaptcha",
+ "fd:captcha": {
+ "provider": "recaptchaEnterprise",
+ "config": {
+ "uri": "https://www.recaptcha.net/recaptcha/enterprise.js",
+ "size": "compact",
+ "theme": "light",
+ "type": "image"
+ }
+ }
+ },
+ ":type": "core/fd/components/form/recaptcha/v2/recaptcha"
+}
diff --git a/bundles/af-core/src/test/resources/form/recaptchav2/test-content.json b/bundles/af-core/src/test/resources/form/recaptchav2/test-content.json
new file mode 100644
index 0000000000..ca5cc760c1
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/recaptchav2/test-content.json
@@ -0,0 +1,27 @@
+{
+ "recaptcha": {
+ "id": "recaptcha-4b672680a2",
+ "jcr:primaryType": "nt:unstructured",
+ "jcr:createdBy": "admin",
+ "jcr:title": "CAPTCHA",
+ "enabled": true,
+ "readOnly": false,
+ "mandatory": "true",
+ "name": "test-recaptcha",
+ "rcCloudServicePath": "enterpriseScore",
+ "visible": true,
+ "hideTitle": "false",
+ "sling:resourceType": "core/fd/components/form/recaptcha/v2/recaptcha",
+ "fieldType": "captcha",
+ "recaptchaSize": "compact",
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "fd:path": "/content/forms/af/af2runtime/jcr:content/guideContainer/recaptcha"
+ },
+ ":type": "forms-components-examples/components/form/recaptcha"
+ }
+}
From 563772546c6dc9106bb3bfeebae25669ed067b47 Mon Sep 17 00:00:00 2001
From: Navneet Agarwal
Date: Fri, 21 Jun 2024 00:10:13 +0530
Subject: [PATCH 2/3] FORMS-14468 | Improving coverage
---
.../models/v2/form/RecaptchaImplV2.java | 2 +-
.../models/v2/form/HCaptchaImplV2Test.java | 46 +++++++++++++---
.../models/v2/form/RecaptchaImplV2Test.java | 52 ++++++++++++++++---
3 files changed, 87 insertions(+), 13 deletions(-)
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
index d257af452e..d44715de81 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2.java
@@ -113,7 +113,7 @@ public String getCaptchaDisplayMode() {
if (reCaptchaConfiguration == null) {
setReCaptchaConfiguration();
}
- return this.captchaDisplayMode.getValue();
+ return captchaDisplayMode != null ? this.captchaDisplayMode.getValue() : CaptchaDisplayMode.VISIBLE.getValue();
}
@PostConstruct
diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
index 584eebc642..94de1525fb 100644
--- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
+++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/HCaptchaImplV2Test.java
@@ -16,9 +16,12 @@
package com.adobe.cq.forms.core.components.internal.models.v2.form;
+import java.util.Map;
+
import org.apache.sling.api.resource.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
@@ -36,7 +39,6 @@
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
@ExtendWith(AemContextExtension.class)
@@ -62,11 +64,14 @@ public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) th
};
@BeforeEach
- void setUp() throws GuideException {
+ void setUp(TestInfo testInfo) throws GuideException {
context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT);
- context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
- Mockito.when(hCaptchaConfiguration.getSiteKey()).thenReturn("dummySiteKey");
- Mockito.when(hCaptchaConfiguration.getClientSideJsUrl()).thenReturn("https://js.hcaptcha.com/1/api.js");
+
+ if (!testInfo.getTestMethod().get().getName().contains("testSetHCaptchaConfiguration")) {
+ context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
+ Mockito.when(hCaptchaConfiguration.getSiteKey()).thenReturn("dummySiteKey");
+ Mockito.when(hCaptchaConfiguration.getClientSideJsUrl()).thenReturn("https://js.hcaptcha.com/1/api.js");
+ }
}
@Test
@@ -136,7 +141,8 @@ void testJSONExport() throws Exception {
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());
+ HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals(null, hCaptcha.getCaptchaSiteKey());
}
@Test
@@ -157,4 +163,32 @@ void testCaptchaSiteKey() {
assertEquals(null, hcaptchaMock.getCaptchaSiteKey());
}
+ @Test
+ void testSetHCaptchaConfigurationWheHCaptchaConfigIsNull() {
+ CloudConfigurationProvider cloudConfigurationProvider = new CloudConfigurationProvider() {
+ @Override
+ public ReCaptchaConfigurationModel getRecaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return null;
+ }
+
+ @Override
+ public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return null;
+ }
+ };
+ context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
+ HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals(null, hCaptcha.getCaptchaSiteKey());
+ Map hCaptchaProperties = hCaptcha.getCaptchaProperties();
+ assertEquals(null, hCaptchaProperties.get("uri"));
+ }
+
+ @Test
+ void testSetHCaptchaConfigurationWheCloudConfigurationProviderIsNull() {
+ HCaptcha hCaptcha = Utils.getComponentUnderTest(PATH_HCAPTCHA, HCaptcha.class, context);
+ assertEquals(null, hCaptcha.getCaptchaSiteKey());
+ Map hCaptchaProperties = hCaptcha.getCaptchaProperties();
+ assertEquals(null, hCaptchaProperties.get("uri"));
+ }
+
}
diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
index 4474608a40..af71999e3e 100644
--- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
+++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/RecaptchaImplV2Test.java
@@ -21,6 +21,7 @@
import org.apache.sling.api.resource.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
@@ -63,12 +64,14 @@ public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) th
};
@BeforeEach
- void setUp() throws GuideException {
+ void setUp(TestInfo testInfo) throws GuideException {
context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT);
- context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
- Mockito.when(reCaptchaConfiguration.siteKey()).thenReturn("dummySiteKey");
- Mockito.when(reCaptchaConfiguration.version()).thenReturn("enterprise");
- Mockito.when(reCaptchaConfiguration.keyType()).thenReturn("score");
+ if (!testInfo.getTestMethod().get().getName().contains("testSetRecaptchaConfiguration")) {
+ context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
+ Mockito.when(reCaptchaConfiguration.siteKey()).thenReturn("dummySiteKey");
+ Mockito.when(reCaptchaConfiguration.version()).thenReturn("enterprise");
+ Mockito.when(reCaptchaConfiguration.keyType()).thenReturn("score");
+ }
}
@Test
@@ -135,11 +138,27 @@ void testJSONExport() throws Exception {
}
@Test
- void testEnterpriseUrl() {
+ void testEnterpriseCheckboxConfig() {
+ Mockito.when(reCaptchaConfiguration.version()).thenReturn("enterprise");
+ Mockito.when(reCaptchaConfiguration.keyType()).thenReturn("checkbox");
Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
Map captchaProps = recaptcha.getCaptchaProperties();
String enterpriseUrl = (String) captchaProps.get("uri");
assertEquals("https://www.recaptcha.net/recaptcha/enterprise.js", enterpriseUrl);
+ assertEquals("recaptchaEnterprise", recaptcha.getProvider());
+ assertEquals("visible", recaptcha.getCaptchaDisplayMode());
+ }
+
+ @Test
+ void testV2Config() {
+ Mockito.when(reCaptchaConfiguration.version()).thenReturn("v2");
+ Mockito.when(reCaptchaConfiguration.keyType()).thenReturn("checkbox");
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ Map captchaProps = recaptcha.getCaptchaProperties();
+ String enterpriseUrl = (String) captchaProps.get("uri");
+ assertEquals("https://www.recaptcha.net/recaptcha/api.js", enterpriseUrl);
+ assertEquals("recaptchaV2", recaptcha.getProvider());
+ assertEquals("visible", recaptcha.getCaptchaDisplayMode());
}
@Test
@@ -160,4 +179,25 @@ void testCaptchaSiteKey() {
assertEquals(null, recaptchaMock.getCaptchaSiteKey());
}
+ @Test
+ void testSetRecaptchaConfigurationWithRecaptchaConfigNull() {
+ CloudConfigurationProvider cloudConfigurationProvider = new CloudConfigurationProvider() {
+ @Override
+ public ReCaptchaConfigurationModel getRecaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return null;
+ }
+
+ @Override
+ public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException {
+ return null;
+ }
+ };
+ context.registerService(CloudConfigurationProvider.class, cloudConfigurationProvider);
+ Captcha recaptcha = Utils.getComponentUnderTest(PATH_RECAPTCHA, Captcha.class, context);
+ assertEquals(null, recaptcha.getCaptchaSiteKey());
+ assertEquals("visible", recaptcha.getCaptchaDisplayMode());
+ Map recaptchaProperties = recaptcha.getCaptchaProperties();
+ assertEquals("https://www.recaptcha.net/recaptcha/api.js", recaptchaProperties.get("uri"));
+ }
+
}
From be0e3bf3270879224bc2d8e7988710475ccb82b5 Mon Sep 17 00:00:00 2001
From: Navneet Agarwal
Date: Mon, 29 Jul 2024 10:40:56 +0530
Subject: [PATCH 3/3] FORMS-14468 | Incorporate spec update for captcha
---
.../.content.xml | 2 +-
.../form/recaptchav2/.content.xml | 7 +
.../form/recaptchav2/_cq_template.xml | 6 +
.../.content.xml | 2 +-
.../components/form/recaptcha/v2/.content.xml | 4 +
.../form/recaptcha/v2/recaptcha/.content.xml | 8 +
.../form/recaptcha/v2/recaptcha/README.md | 77 +++++++++
.../v2/recaptcha/_cq_dialog/.content.xml | 124 +++++++++++++++
.../v2/recaptcha/clientlibs/.content.xml | 3 +
.../v2/recaptcha/clientlibs/site/.content.xml | 6 +
.../v2/recaptcha/clientlibs/site/css.txt | 18 +++
.../clientlibs/site/css/recaptchaview.css | 21 +++
.../v2/recaptcha/clientlibs/site/js.txt | 19 +++
.../clientlibs/site/js/recaptchaview.js | 86 +++++++++++
.../clientlibs/site/js/recaptchawidget.js | 124 +++++++++++++++
.../recaptcha/v2/recaptcha/recaptcha.html | 43 ++++++
ui.frontend/package-lock.json | 146 ++++++++++++------
ui.frontend/package.json | 4 +-
18 files changed, 651 insertions(+), 49 deletions(-)
create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/.content.xml
create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/_cq_template.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/.content.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/.content.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/README.md
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/_cq_dialog/.content.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/.content.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/.content.xml
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css.txt
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css/recaptchaview.css
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js.txt
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchaview.js
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchawidget.js
create mode 100644 ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/recaptcha.html
diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/clientlibs/custom-forms-components-runtime-all/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/clientlibs/custom-forms-components-runtime-all/.content.xml
index 157dfad222..a4d7a79c76 100644
--- a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/clientlibs/custom-forms-components-runtime-all/.content.xml
+++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/clientlibs/custom-forms-components-runtime-all/.content.xml
@@ -5,4 +5,4 @@
cssProcessor="[default:none,min:none]"
jsProcessor="[default:none,min:none]"
categories="[core.forms.components.it.runtime.all]"
- embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v2.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.it.textinput.v1.runtime, core.forms.components.hcaptcha.v1.runtime]"/>
+ embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v2.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v2.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.it.textinput.v1.runtime, core.forms.components.hcaptcha.v1.runtime]"/>
diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/.content.xml
new file mode 100644
index 0000000000..f057f42aba
--- /dev/null
+++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/.content.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/_cq_template.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/_cq_template.xml
new file mode 100644
index 0000000000..467dd5aa50
--- /dev/null
+++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/form/recaptchav2/_cq_template.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
index 99d071211e..c60f42f548 100644
--- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
@@ -5,4 +5,4 @@
cssProcessor="[default:none,min:none]"
jsProcessor="[default:none,min:none]"
categories="[core.forms.components.runtime.all]"
- embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime]"/>
+ embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v2.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime]"/>
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/.content.xml
new file mode 100644
index 0000000000..5e25fbe65e
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/.content.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/.content.xml
new file mode 100644
index 0000000000..16fe44c69e
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/.content.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/README.md b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/README.md
new file mode 100644
index 0000000000..fe8defe31d
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/README.md
@@ -0,0 +1,77 @@
+
+Adaptive Form Recaptcha (v2)
+====
+Adaptive Form Recaptcha field component written in HTL.
+
+## Features
+
+* Provides the following type of input:
+ * Google reCAPTCHA
+* Supports the following recaptcha versions:
+ * v2
+ * Both visible and invisible mode are supported
+ * Enterprise
+ * Checkbox keys (Visible Behaviour)
+ * Score-based keys (Invisible behaviour)
+* Styles
+* Custom constraint messages for the above types
+
+### Use Object
+The Form Text component uses the `com.adobe.cq.forms.core.components.models.form.Recaptcha` Sling Model for its Use-object.
+
+### Edit Dialog Properties
+The following properties are written to JCR for this Form Recaptcha component and are expected to be available as `Resource` properties:
+
+1. `./jcr:title` - defines the label to use for this field
+2. `./hideTitle` - if set to `true`, the label of this field will be hidden
+3. `./name` - defines the name of the field, which will be submitted with the form data
+4. `./default` - defines the default value of the field
+5. `./description` - defines a help message that can be rendered in the field as a hint for the user
+6. `./required` - if set to `true`, this field will be marked as required, not allowing the form to be submitted until the field has a value
+7. `./requiredMessage` - defines the message displayed as tooltip when submitting the form if the value is left empty
+8. `./readOnly` - if set to `true`, the filed will be read only
+9. `./rcCloudServicePath` - defines the path of cloud configuration resource for reCAPTCHA
+10. `./recaptchaSize` - defines the size attribute of Google reCAPTCHA. This property is only valid for reCAPTCHA v2 and the checkbox keys of reCAPTCHA enterprise. This property will be disabled for reCAPTCHA Enteprise score-based keys.
+
+## Client Libraries
+The component provides a `core.forms.components.recaptcha.v1.runtime` client library category that contains the Javascript runtime for the component.
+It should be added to a relevant site client library using the `embed` property.
+
+
+## BEM Description
+```
+BLOCK cmp-adaptiveform-recaptcha
+ ELEMENT cmp-adaptiveform-recaptcha__label
+ ELEMENT cmp-adaptiveform-recaptcha__widget
+ ELEMENT cmp-adaptiveform-recaptcha__errormessage
+```
+
+## JavaScript Data Attribute Bindings
+
+The following attributes must be added for the initialization of the recaptcha component in the form view:
+1. `data-cmp-is="adaptiveFormRecaptcha"`
+2. `data-cmp-adaptiveformcontainer-path="${formstructparser.formContainerPath}"`
+
+
+
+The following are optional attributes that can be added to the component in the form view:
+1. `data-cmp-valid` having a boolean value to indicate whether the field is currently valid or not
+2. `data-cmp-required` having a boolean value to indicate whether the field is currently required or not
+3. `data-cmp-readonly` having a boolean value to indicate whether the field is currently readonly or not
+4. `data-cmp-active` having a boolean value to indicate whether the field is currently active or not
+5. `data-cmp-visible` having a boolean value to indicate whether the field is currently visible or not
+6. `data-cmp-enabled` having a boolean value to indicate whether the field is currently enabled or not
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/_cq_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/_cq_dialog/.content.xml
new file mode 100644
index 0000000000..7c682ffd9c
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/_cq_dialog/.content.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/.content.xml
new file mode 100644
index 0000000000..491392d539
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/.content.xml
new file mode 100644
index 0000000000..ea32edb75b
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/.content.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css.txt
new file mode 100644
index 0000000000..99d77ce030
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css.txt
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright 2023 Adobe
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+#base=css
+recaptchaview.css
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css/recaptchaview.css b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css/recaptchaview.css
new file mode 100644
index 0000000000..91bc9a102e
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/css/recaptchaview.css
@@ -0,0 +1,21 @@
+/**
+## BEM Description
+BLOCK cmp-adaptiveform-recaptcha
+ ELEMENT cmp-adaptiveform-recaptcha__label
+ ELEMENT cmp-adaptiveform-recaptcha__widget
+ ELEMENT cmp-adaptiveform-recaptcha__errormessage
+*/
+
+.cmp-adaptiveform-recaptcha {
+
+}
+
+.cmp-adaptiveform-recaptcha__widget {
+
+}
+
+.cmp-adaptiveform-recaptcha__label {
+
+}
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js.txt
new file mode 100644
index 0000000000..5af65e4558
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js.txt
@@ -0,0 +1,19 @@
+###############################################################################
+# Copyright 2023 Adobe
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+#base=js
+recaptchaview.js
+recaptchawidget.js
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchaview.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchaview.js
new file mode 100644
index 0000000000..43d33a1365
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchaview.js
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright 2023 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+(function() {
+
+ "use strict";
+ class Recaptcha extends FormView.FormFieldBase {
+
+ static NS = FormView.Constants.NS;
+ static IS = "adaptiveFormRecaptcha";
+ static bemBlock = 'cmp-adaptiveform-recaptcha';
+ static selectors = {
+ self: "[data-" + this.NS + '-is="' + this.IS + '"]',
+ widget: `.${Recaptcha.bemBlock}__widget`,
+ label: `.${Recaptcha.bemBlock}__label`,
+ errorDiv: `.${Recaptcha.bemBlock}__errormessage`
+ };
+
+ constructor(params) {
+ super(params);
+ }
+
+ getWidget() {
+ return this.element.querySelector(Recaptcha.selectors.widget);
+ }
+
+ getDescription() {
+ return null;
+ }
+
+ getLabel() {
+ return this.element.querySelector(Recaptcha.selectors.label);
+ }
+
+ getTooltipDiv() {
+ return null;
+ }
+
+ getErrorDiv() {
+ return this.element.querySelector(Recaptcha.selectors.errorDiv);
+ }
+
+ getQuestionMarkDiv() {
+ return null;
+ }
+
+ initializeWidget() {
+ this.widgetObject = new RecaptchaWidget(this, this._model, this.getWidget());
+ this.getWidget().addEventListener('blur', (e) => {
+ if(this.element) {
+ this.setInactive();
+ }
+ });
+
+ }
+
+ setModel(model) {
+ super.setModel(model);
+ if (this.widgetObject == null) {
+ this.initializeWidget();
+ } else {
+ if (this.widget.value !== '') {
+ this._model.value = this.widget.value;
+ }
+ }
+ }
+
+ }
+
+ FormView.Utils.setupField(({element, formContainer}) => {
+ return new Recaptcha({element, formContainer})
+ }, Recaptcha.selectors.self);
+
+})();
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchawidget.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchawidget.js
new file mode 100644
index 0000000000..9e7219f820
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/clientlibs/site/js/recaptchawidget.js
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright 2023 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * This class is responsible for interacting with the recaptcha widget. It displays Google reCAPTCHA challenge.
+ */
+
+if (typeof window.RecaptchaWidget === 'undefined') {
+ window.RecaptchaWidget = class {
+ #widget = null
+ #model = null // passed by reference
+ #options = null
+ #lang = 'en'
+ static FD_CAPTCHA = "fd:captcha";
+ static RECAPTCHA_ENTERPRISE = "recaptchaEnterprise";
+ constructor(view, model, widget) {
+ // initialize the widget and model
+ this.#widget = widget;
+ this.#model = model;
+ this.#widget = document.createElement("div");
+ this.#widget.classList.add("cmp-adaptiveform-recaptcha__widget");
+ this.#lang = view.formContainer.getModel().lang;
+
+ //Always inserting it in body
+ document.body.appendChild(this.#widget);
+ this.#options = Object.assign({}, this.#model._jsonModel);
+
+ this.#renderRecaptcha(widget);
+ }
+
+ #renderRecaptcha(element) {
+
+ var self = this;
+ var recaptchaConfigData = this.#options;
+ //check if captchaSiteKey property exist in model, if not use the default siteKey
+ element.innerHTML = '';
+ var gcontainer = document.getElementsByClassName("g-recaptcha")[0];
+ var widgetId;
+ var url = recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.uri;
+ if (recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.size == "invisible") {
+ gcontainer.classList.add('g-recaptcha-invisible');
+ recaptchaConfigData.required = false;
+ }
+
+ const getSiteKey = function () {
+ return self.#model.captchaSiteKey == null
+ ? recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.siteKey : self.#model.captchaSiteKey;
+ }
+
+ const isRecaptchaEnterprise = function () {
+ if (self.#model.captchaProvider != null) {
+ if (self.#model.captchaProvider === RecaptchaWidget.RECAPTCHA_ENTERPRISE) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.version === "enterprise";
+ }
+ }
+
+ const isScoreBasedKey = function () {
+ return isRecaptchaEnterprise() && ( (self.#model.captchaDisplayMode != null && self.#model.captchaDisplayMode === "invisible") ||
+ recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.keyType === "score");
+ }
+
+ var successCallback = function(response) {
+ self.setCaptchaModel(response);
+
+ };
+
+ var expiredCallback = function() {
+ if (isRecaptchaEnterprise()) {
+ grecaptcha.enterprise.reset(widgetId);
+ } else {
+ grecaptcha.reset(widgetId);
+ }
+ self.setCaptchaModel("");
+ };
+
+ var onloadCallbackInternal = function() {
+ widgetId = isRecaptchaEnterprise() ? grecaptcha.enterprise.render(gcontainer, gparameters)
+ : grecaptcha.render(gcontainer, gparameters);
+ return widgetId;
+ };
+ var gparameters = {
+ 'sitekey': getSiteKey(),
+ 'size': recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.size,
+ 'theme': recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.theme || 'light',
+ 'type': recaptchaConfigData.properties[RecaptchaWidget.FD_CAPTCHA].config.type || 'image',
+ 'callback': successCallback,
+ 'expired-callback': expiredCallback
+ };
+
+ window.onloadRecaptchaCallback = onloadCallbackInternal;
+
+ var runtimeLocale = this.#lang;
+
+ var scr = document.createElement('script');
+ let queryParams = isScoreBasedKey() ? "?render=" + getSiteKey() : "?onload=onloadRecaptchaCallback&render=explicit";
+ queryParams += "&hl=" + runtimeLocale;
+ scr.src = url + queryParams;
+ scr.async = true;
+ element.appendChild(scr);
+ }
+
+ setCaptchaModel = function(response) {
+ this.#model.value = (response);
+ }
+ }
+}
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/recaptcha.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/recaptcha.html
new file mode 100644
index 0000000000..8d95ef7984
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/recaptcha/v2/recaptcha/recaptcha.html
@@ -0,0 +1,43 @@
+
+
+
+
diff --git a/ui.frontend/package-lock.json b/ui.frontend/package-lock.json
index 15643eb923..520f2a4e5e 100644
--- a/ui.frontend/package-lock.json
+++ b/ui.frontend/package-lock.json
@@ -9,8 +9,8 @@
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
- "@aemforms/af-core": "^0.22.86",
- "@aemforms/af-custom-functions": "1.0.8",
+ "@aemforms/af-core": "file:///Users/navneeta/repos/af2-web-runtime/packages/forms-next-core",
+ "@aemforms/af-custom-functions": "file:///Users/navneeta/repos/af-custom-functions",
"@aemforms/af-formatters": "^0.22.84"
},
"devDependencies": {
@@ -26,6 +26,50 @@
"webpack-merge": "^5.8.0"
}
},
+ "../../../repos/af-custom-functions": {
+ "name": "@aemforms/af-custom-functions",
+ "version": "1.0.7",
+ "license": "MIT License, Copyright 2024 Adobe Systems Incorporated",
+ "devDependencies": {
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^29.7.0"
+ }
+ },
+ "../../../repos/af2-web-runtime/packages/forms-next-core": {
+ "name": "@aemforms/af-core",
+ "version": "0.22.90",
+ "license": "Adobe Proprietary",
+ "dependencies": {
+ "@adobe/json-formula": "0.1.50",
+ "@aemforms/af-formatters": "^0.22.90"
+ },
+ "devDependencies": {
+ "@babel/preset-env": "^7.20.2",
+ "@types/jest": "29.2.4",
+ "@types/lodash": "^4.14.171",
+ "@typescript-eslint/eslint-plugin": "^4.28.2",
+ "@typescript-eslint/parser": "^4.28.2",
+ "babel-jest": "^29.4.1",
+ "blob-polyfill": "^7.0.20220408",
+ "eslint": "^7.30.0",
+ "eslint-config-standard": "^16.0.3",
+ "eslint-plugin-import": "^2.23.4",
+ "eslint-plugin-jest": "^24.3.6",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^5.1.0",
+ "form-data": "^4.0.0",
+ "jest": "29.3",
+ "jest-environment-jsdom": "^29.3.1",
+ "jest-junit": "^12.2.0",
+ "nock": "^13.1.3",
+ "node-fetch": "^2.6.1",
+ "parse-multipart-data": "^1.5.0",
+ "ts-jest": "29.0",
+ "typedoc": "0.22.11",
+ "typedoc-plugin-markdown": "3.11.13",
+ "typescript": "^4.3.5"
+ }
+ },
"../../af2-web-runtime/packages/forms-next-formatters": {
"name": "@aemforms/af-formatters",
"version": "0.22.75",
@@ -52,32 +96,18 @@
"typedoc-plugin-markdown": "3.11.13"
}
},
- "node_modules/@adobe/json-formula": {
- "version": "0.1.50",
- "resolved": "https://registry.npmjs.org/@adobe/json-formula/-/json-formula-0.1.50.tgz",
- "integrity": "sha512-dmlLYfbty8NPVIdxvI9cJ+ZdXsrRCFrCdmL1+aR2auEzXJ86rD0bm1qu+S4NOpFiZLKIyx0zvUTykms40vNjsA==",
- "engines": {
- "node": ">=16.0.0"
- }
- },
"node_modules/@aemforms/af-core": {
- "version": "0.22.86",
- "resolved": "https://registry.npmjs.org/@aemforms/af-core/-/af-core-0.22.86.tgz",
- "integrity": "sha512-MCwUfRGjFmnB6l6UJbqyKiOw5ArIwRLg6vNg+bfHxGqxMeBIjQ1P6OlEp9JQfhBTALfeC6IiiAreJ1gNCePTSQ==",
- "dependencies": {
- "@adobe/json-formula": "0.1.50",
- "@aemforms/af-formatters": "^0.22.86"
- }
+ "resolved": "../../../repos/af2-web-runtime/packages/forms-next-core",
+ "link": true
},
"node_modules/@aemforms/af-custom-functions": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@aemforms/af-custom-functions/-/af-custom-functions-1.0.8.tgz",
- "integrity": "sha512-R7+fKX4A5DaNoHvukm9eM762En8XA/ZVE3F5a/2lUuDmgi4f5INWE+i5+PIDZtHD66R4ZGaNAI4LoLtaXxgOGA=="
+ "resolved": "../../../repos/af-custom-functions",
+ "link": true
},
"node_modules/@aemforms/af-formatters": {
- "version": "0.22.86",
- "resolved": "https://registry.npmjs.org/@aemforms/af-formatters/-/af-formatters-0.22.86.tgz",
- "integrity": "sha512-nKWSnqy+riJlglBdpW5GDIv+YXGXPQyR0w32Atz6VRDtR5VN1K+m4cIZDFruwfyKoAZxFDtkM4pNt1HGvKfKMw=="
+ "version": "0.22.94",
+ "resolved": "https://registry.npmjs.org/@aemforms/af-formatters/-/af-formatters-0.22.94.tgz",
+ "integrity": "sha512-DUse02KD4+YD+WwdYJQ1Ur4+NkAmze7AKubDYSGDpdOz3CzLkz36aWmTgukwy8Iz99wAO4hvZOnt7d5Ed+LCwg=="
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
@@ -11070,29 +11100,48 @@
}
},
"dependencies": {
- "@adobe/json-formula": {
- "version": "0.1.50",
- "resolved": "https://registry.npmjs.org/@adobe/json-formula/-/json-formula-0.1.50.tgz",
- "integrity": "sha512-dmlLYfbty8NPVIdxvI9cJ+ZdXsrRCFrCdmL1+aR2auEzXJ86rD0bm1qu+S4NOpFiZLKIyx0zvUTykms40vNjsA=="
- },
"@aemforms/af-core": {
- "version": "0.22.86",
- "resolved": "https://registry.npmjs.org/@aemforms/af-core/-/af-core-0.22.86.tgz",
- "integrity": "sha512-MCwUfRGjFmnB6l6UJbqyKiOw5ArIwRLg6vNg+bfHxGqxMeBIjQ1P6OlEp9JQfhBTALfeC6IiiAreJ1gNCePTSQ==",
+ "version": "file:../../../repos/af2-web-runtime/packages/forms-next-core",
"requires": {
"@adobe/json-formula": "0.1.50",
- "@aemforms/af-formatters": "^0.22.86"
+ "@aemforms/af-formatters": "^0.22.90",
+ "@babel/preset-env": "^7.20.2",
+ "@types/jest": "29.2.4",
+ "@types/lodash": "^4.14.171",
+ "@typescript-eslint/eslint-plugin": "^4.28.2",
+ "@typescript-eslint/parser": "^4.28.2",
+ "babel-jest": "^29.4.1",
+ "blob-polyfill": "^7.0.20220408",
+ "eslint": "^7.30.0",
+ "eslint-config-standard": "^16.0.3",
+ "eslint-plugin-import": "^2.23.4",
+ "eslint-plugin-jest": "^24.3.6",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^5.1.0",
+ "form-data": "^4.0.0",
+ "jest": "29.3",
+ "jest-environment-jsdom": "^29.3.1",
+ "jest-junit": "^12.2.0",
+ "nock": "^13.1.3",
+ "node-fetch": "^2.6.1",
+ "parse-multipart-data": "^1.5.0",
+ "ts-jest": "29.0",
+ "typedoc": "0.22.11",
+ "typedoc-plugin-markdown": "3.11.13",
+ "typescript": "^4.3.5"
}
},
"@aemforms/af-custom-functions": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@aemforms/af-custom-functions/-/af-custom-functions-1.0.8.tgz",
- "integrity": "sha512-R7+fKX4A5DaNoHvukm9eM762En8XA/ZVE3F5a/2lUuDmgi4f5INWE+i5+PIDZtHD66R4ZGaNAI4LoLtaXxgOGA=="
+ "version": "file:../../../repos/af-custom-functions",
+ "requires": {
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^29.7.0"
+ }
},
"@aemforms/af-formatters": {
- "version": "0.22.86",
- "resolved": "https://registry.npmjs.org/@aemforms/af-formatters/-/af-formatters-0.22.86.tgz",
- "integrity": "sha512-nKWSnqy+riJlglBdpW5GDIv+YXGXPQyR0w32Atz6VRDtR5VN1K+m4cIZDFruwfyKoAZxFDtkM4pNt1HGvKfKMw=="
+ "version": "0.22.94",
+ "resolved": "https://registry.npmjs.org/@aemforms/af-formatters/-/af-formatters-0.22.94.tgz",
+ "integrity": "sha512-DUse02KD4+YD+WwdYJQ1Ur4+NkAmze7AKubDYSGDpdOz3CzLkz36aWmTgukwy8Iz99wAO4hvZOnt7d5Ed+LCwg=="
},
"@ampproject/remapping": {
"version": "2.2.1",
@@ -11368,7 +11417,8 @@
},
"@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
@@ -13306,7 +13356,8 @@
},
"@webpack-cli/configtest": {
"version": "1.2.0",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@webpack-cli/info": {
"version": "1.5.0",
@@ -13317,7 +13368,8 @@
},
"@webpack-cli/serve": {
"version": "1.7.0",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@xtuc/ieee754": {
"version": "1.2.0",
@@ -13351,7 +13403,8 @@
},
"acorn-import-assertions": {
"version": "1.9.0",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-walk": {
"version": "7.2.0",
@@ -13387,7 +13440,8 @@
},
"ajv-keywords": {
"version": "3.5.2",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"ansi-escapes": {
"version": "4.3.2",
@@ -15753,7 +15807,8 @@
},
"jest-pnp-resolver": {
"version": "1.2.3",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"jest-regex-util": {
"version": "26.0.0",
@@ -18235,7 +18290,8 @@
},
"ws": {
"version": "8.16.0",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"xml-name-validator": {
"version": "4.0.0",
diff --git a/ui.frontend/package.json b/ui.frontend/package.json
index 46261b1870..192b35dd0d 100644
--- a/ui.frontend/package.json
+++ b/ui.frontend/package.json
@@ -23,8 +23,8 @@
"webpack-merge": "^5.8.0"
},
"dependencies": {
- "@aemforms/af-core": "^0.22.86",
+ "@aemforms/af-core": "file:///Users/navneeta/repos/af2-web-runtime/packages/forms-next-core",
"@aemforms/af-formatters": "^0.22.84",
- "@aemforms/af-custom-functions": "1.0.8"
+ "@aemforms/af-custom-functions": "file:///Users/navneeta/repos/af-custom-functions"
}
}