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 01bbc23604..6ecdd327c3 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 @@ -108,6 +108,9 @@ private FormConstants() { public static final String RT_FD_FRAGMENT_CONTAINER_V1 = RT_FD_FORM_PREFIX + "fragmentcontainer/v1/fragmentcontainer"; + /** The resource type for terms and conditions v1 */ + public static final String RT_FD_FORM_TERMS_AND_CONDITIONS_V1 = RT_FD_FORM_PREFIX + "termsandconditions/v1/termsandconditions"; + public static final String FORM_FIELD_TYPE = "form"; public static final String REQ_ATTR_FORMCONTAINER_PATH = "formContainerPath"; diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImpl.java new file mode 100644 index 0000000000..63a81cc98c --- /dev/null +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImpl.java @@ -0,0 +1,107 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ 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. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +package com.adobe.cq.forms.core.components.internal.models.v1.form; + +import java.util.List; +import java.util.Map; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Default; +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.ValueMapValue; +import org.jetbrains.annotations.NotNull; + +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.FieldType; +import com.adobe.cq.forms.core.components.models.form.TermsAndConditions; +import com.fasterxml.jackson.annotation.JsonIgnore; + +@Model( + adaptables = { SlingHttpServletRequest.class, Resource.class }, + adapters = { TermsAndConditions.class, + ComponentExporter.class }, + resourceType = { FormConstants.RT_FD_FORM_TERMS_AND_CONDITIONS_V1 }) + +@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) +public class TermsAndConditionsImpl extends PanelImpl implements TermsAndConditions { + + private static final String CUSTOM_TNC_PROPERTY = "fd:tnc"; + + private static final String FIELD_TYPE = "fieldType"; + + @JsonIgnore + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL) + @Default(booleanValues = true) + private boolean showApprovalOption; + + @JsonIgnore + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL) + @Default(booleanValues = false) + private boolean showLink; + + @JsonIgnore + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL) + @Default(booleanValues = false) + private boolean showAsPopup; + + @Override + public boolean isShowApprovalOption() { + return showApprovalOption; + } + + @Override + public boolean isShowLink() { + return showLink; + } + + @Override + public boolean isShowAsPopup() { + return showAsPopup; + } + + @Override + public @NotNull String getId() { + return super.getId(); + } + + @Override + public @NotNull Map getProperties() { + Map properties = super.getProperties(); + if (resource.getValueMap().containsKey(CUSTOM_TNC_PROPERTY)) { + properties.put(CUSTOM_TNC_PROPERTY, true); + } + return properties; + } + + @Override + protected List getFilteredChildrenResources() { + List childResources = getFilteredChildrenResources(resource); + // the tnc component will either have links or consent text based upon showLink value + if (showLink) { + childResources.removeIf(child -> FieldType.PLAIN_TEXT.getValue().equals(child.getValueMap().get(FIELD_TYPE))); + + } else { + childResources.removeIf(child -> FieldType.CHECKBOX_GROUP.getValue().equals(child.getValueMap().get(FIELD_TYPE))); + } + return childResources; + } +} diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/TermsAndConditions.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/TermsAndConditions.java new file mode 100644 index 0000000000..e724791843 --- /dev/null +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/TermsAndConditions.java @@ -0,0 +1,50 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ 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. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +package com.adobe.cq.forms.core.components.models.form; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Defines the form {@code TermsAndConditions} Sling Model used for the + * {@code /apps/core/fd/components/form/termsandconditions/v1/termsandconditions} component. + * + * @since com.adobe.cq.forms.core.components.models.form 4.5.0 + */ +@ConsumerType +public interface TermsAndConditions extends Container, ContainerConstraint { + + String FD_TERMS_AND_CONDITIONS = "fd:tnc"; + + /** + * + * @return {@code true} if approval checkbox should be shown, otherwise {@code false} + */ + boolean isShowApprovalOption(); + + /** + * + * @return {@code true} if links to external Terms & Conditions pages are to be shown, otherwise + * {@code false if consent text is to be shown} + */ + boolean isShowLink(); + + /** + * + * @return @return {@code true} if the content is to be shown as pop-up , otherwise {@code false} + */ + boolean isShowAsPopup(); +} diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImplTest.java new file mode 100644 index 0000000000..57c936958b --- /dev/null +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TermsAndConditionsImplTest.java @@ -0,0 +1,126 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ 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. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package com.adobe.cq.forms.core.components.internal.models.v1.form; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.apache.sling.api.resource.Resource; +import org.junit.Assert; +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.cq.export.json.SlingModelFilter; +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.TermsAndConditions; +import com.adobe.cq.forms.core.context.FormsCoreComponentTestContext; +import com.day.cq.wcm.api.NameConstants; +import com.day.cq.wcm.msm.api.MSMNameConstants; +import io.wcm.testing.mock.aem.junit5.AemContext; +import io.wcm.testing.mock.aem.junit5.AemContextExtension; + +import static org.junit.Assert.assertEquals; + +@ExtendWith(AemContextExtension.class) +public class TermsAndConditionsImplTest { + + private static final String BASE = "/form/termsandconditions"; + private static final String CONTENT_ROOT = "/content"; + + private static final String PATH_TNC = CONTENT_ROOT + "/termsandconditions"; + + private static final String PATH_NOWRAP_TNC = CONTENT_ROOT + "/termsandconditionsNoWrapData"; + + private final AemContext context = FormsCoreComponentTestContext.newAemContext(); + + @BeforeEach + public void setUp() { + context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT); + context.registerService(SlingModelFilter.class, new SlingModelFilter() { + + private final Set IGNORED_NODE_NAMES = new HashSet() { + { + add(NameConstants.NN_RESPONSIVE_CONFIG); + add(MSMNameConstants.NT_LIVE_SYNC_CONFIG); + add("cq:annotations"); + } + }; + + @Override + public Map filterProperties(Map map) { + return map; + } + + @Override + public Iterable filterChildResources(Iterable childResources) { + return StreamSupport + .stream(childResources.spliterator(), false) + .filter(r -> !IGNORED_NODE_NAMES.contains(r.getName())) + .collect(Collectors.toList()); + } + }); + } + + @Test + void testExportedType() throws Exception { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_TNC, TermsAndConditions.class, context); + assertEquals(FormConstants.RT_FD_FORM_TERMS_AND_CONDITIONS_V1, tnc.getExportedType()); + TermsAndConditions tncMock = Mockito.mock(TermsAndConditions.class); + Mockito.when(tncMock.getExportedType()).thenCallRealMethod(); + assertEquals("", tncMock.getExportedType()); + } + + @Test + public void testGetProperties() { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_TNC, TermsAndConditions.class, context); + Assert.assertTrue(tnc.isShowApprovalOption()); + Assert.assertTrue(tnc.isShowAsPopup()); + Assert.assertFalse(tnc.isShowLink()); + } + + @Test + public void testCustomFDProperty() { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_TNC, TermsAndConditions.class, context); + Map props = tnc.getProperties(); + Assert.assertTrue(props.containsKey("fd:tnc")); + Assert.assertTrue((Boolean) props.get("fd:tnc")); + + } + + @Test + void testJSONExport() throws Exception { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_TNC, TermsAndConditions.class, context); + Utils.testJSONExport(tnc, Utils.getTestExporterJSONPath(BASE, PATH_TNC)); + } + + @Test + void testJSONExport_showLink() throws Exception { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_NOWRAP_TNC, TermsAndConditions.class, context); + Utils.testJSONExport(tnc, Utils.getTestExporterJSONPath(BASE, PATH_NOWRAP_TNC)); + } + + @Test + void testNoWrap() { + TermsAndConditions tnc = Utils.getComponentUnderTest(PATH_NOWRAP_TNC, TermsAndConditions.class, context); + Assert.assertNull(tnc.getType()); + } +} diff --git a/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditions.json b/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditions.json new file mode 100644 index 0000000000..64ec40ecc3 --- /dev/null +++ b/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditions.json @@ -0,0 +1,75 @@ +{ + "id": "termsandconditions-dac51d5ed9", + "fieldType": "panel", + "name": "termsandconditions1694159302516", + "type": "object", + "properties": { + "fd:dor": { + "dorExclusion": false, + "dorExcludeTitle": false, + "dorExcludeDescription": false + }, + "fd:path": "/content/termsandconditions", + "fd:tnc": true + }, + "label": { + "value": "Terms And Conditions" + }, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + ":itemsOrder": [ + "text", + "approvalcheckbox" + ], + ":items": { + "text": { + "id": "text-37c101fc2b", + "fieldType": "plain-text", + "name": "consenttext", + "value": "Text related to the terms and conditions come here", + "richText": false, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + "properties": { + "fd:path": "/content/termsandconditions/text" + }, + ":type": "core/fd/components/form/text/v1/text" + }, + "approvalcheckbox": { + "id": "checkbox-150eb94d3e", + "fieldType": "checkbox", + "name": "approvalcheckbox", + "type": "string", + "enabled": false, + "enforceEnum": true, + "label": { + "value": "I agree to the terms & conditions" + }, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + "properties": { + "afs:layout": { + "orientation": "horizontal" + }, + "fd:dor": { + "dorExclusion": false + }, + "fd:path": "/content/termsandconditions/approvalcheckbox" + }, + "enum": [ + "true" + ], + ":type": "core/fd/components/form/checkbox/v1/checkbox" + } + }, + ":type": "core/fd/components/form/termsandconditions/v1/termsandconditions" +} diff --git a/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditionsNoWrapData.json b/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditionsNoWrapData.json new file mode 100644 index 0000000000..23f4a33d14 --- /dev/null +++ b/bundles/af-core/src/test/resources/form/termsandconditions/exporter-termsandconditionsNoWrapData.json @@ -0,0 +1,89 @@ +{ + "id": "termsandconditions-5e021cc31d", + "fieldType": "panel", + "name": "termsandconditions1694159302516", + "properties": { + "fd:dor": { + "dorExclusion": false, + "dorExcludeTitle": false, + "dorExcludeDescription": false + }, + "fd:path": "/content/termsandconditionsNoWrapData", + "fd:tnc": true + }, + "label": { + "value": "Terms And Conditions" + }, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + ":itemsOrder": [ + "approvalcheckbox", + "link" + ], + ":type": "core/fd/components/form/termsandconditions/v1/termsandconditions", + ":items": { + "approvalcheckbox": { + "id": "checkbox-9d01a4893a", + "fieldType": "checkbox", + "name": "approvalcheckbox", + "type": "string", + "enabled": false, + "enforceEnum": true, + "label": { + "value": "I agree to the terms & conditions" + }, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + "properties": { + "afs:layout": { + "orientation": "horizontal" + }, + "fd:dor": { + "dorExclusion": false + }, + "fd:path": "/content/termsandconditionsNoWrapData/approvalcheckbox" + }, + "enum": [ + "true" + ], + ":type": "core/fd/components/form/checkbox/v1/checkbox" + }, + "link": { + "id": "checkboxgroup-577c0892d3", + "fieldType": "checkbox-group", + "name": "link1694159323342", + "type": "string", + "enforceEnum": true, + "enumNames": [ + "label for the link" + ], + "label": { + "value": "" + }, + "events": { + "custom:setProperty": [ + "$event.payload" + ] + }, + "properties": { + "afs:layout": { + "orientation": "vertical" + }, + "fd:dor": { + "dorExclusion": false + }, + "fd:path": "/content/termsandconditionsNoWrapData/link" + }, + "enum": [ + "yourlink" + ], + ":type": "core/fd/components/form/checkboxgroup/v1/checkboxgroup" + } + } +} diff --git a/bundles/af-core/src/test/resources/form/termsandconditions/test-content.json b/bundles/af-core/src/test/resources/form/termsandconditions/test-content.json new file mode 100644 index 0000000000..b7ef1cf3c5 --- /dev/null +++ b/bundles/af-core/src/test/resources/form/termsandconditions/test-content.json @@ -0,0 +1,89 @@ +{ + "termsandconditions": { + "showApprovalOption": true, + "jcr:title": "Terms And Conditions", + "fd:tnc": true, + "showAsPopup": true, + "name": "termsandconditions1694159302516", + "sling:resourceType": "core/fd/components/form/termsandconditions/v1/termsandconditions", + "wrapData": true, + "fieldType": "panel", + "text": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "", + "name": "consenttext", + "value": "Text related to the terms and conditions come here", + "hideTitle": "true", + "sling:resourceType": "core/fd/components/form/text/v1/text", + "fieldType": "plain-text" + }, + "approvalcheckbox": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "I agree to the terms & conditions", + "enabled": "false", + "name": "approvalcheckbox", + "checkedValue": "true", + "sling:resourceType": "core/fd/components/form/checkbox/v1/checkbox", + "fieldType": "checkbox" + }, + "link": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "", + "orientation": "vertical", + "enum": [ + "yourlink" + ], + "name": "link1694159323342", + "title": "I agree to the terms & conditions", + "enumNames": [ + "label for the link" + ], + "sling:resourceType": "core/fd/components/form/checkboxgroup/v1/checkboxgroup", + "fieldType": "checkbox-group" + } + }, + "termsandconditionsNoWrapData": { + "showApprovalOption": true, + "jcr:title": "Terms And Conditions", + "fd:tnc": true, + "showAsPopup": true, + "showLink": true, + "name": "termsandconditions1694159302516", + "sling:resourceType": "core/fd/components/form/termsandconditions/v1/termsandconditions", + "wrapData": false, + "fieldType": "panel", + "text": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "", + "name": "consenttext", + "value": "Text related to the terms and conditions come here", + "hideTitle": "true", + "sling:resourceType": "core/fd/components/form/text/v1/text", + "fieldType": "plain-text" + }, + "approvalcheckbox": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "I agree to the terms & conditions", + "enabled": "false", + "name": "approvalcheckbox", + "checkedValue": "true", + "sling:resourceType": "core/fd/components/form/checkbox/v1/checkbox", + "fieldType": "checkbox" + }, + "link": { + "jcr:primaryType": "nt:unstructured", + "jcr:title": "", + "orientation": "vertical", + "enum": [ + "yourlink" + ], + "name": "link1694159323342", + "title": "I agree to the terms & conditions", + "enumNames": [ + "label for the link" + ], + "sling:resourceType": "core/fd/components/form/checkboxgroup/v1/checkboxgroup", + "fieldType": "checkbox-group" + } + } +} diff --git a/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/.content.xml b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/.content.xml new file mode 100644 index 0000000000..9390fcd533 --- /dev/null +++ b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/.content.xml @@ -0,0 +1,7 @@ + + diff --git a/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/_cq_template/.content.xml b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/_cq_template/.content.xml new file mode 100644 index 0000000000..95a10387e4 --- /dev/null +++ b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/termsandconditions/_cq_template/.content.xml @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/termsandconditions/.content.xml b/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/termsandconditions/.content.xml new file mode 100644 index 0000000000..824a08cbbb --- /dev/null +++ b/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/termsandconditions/.content.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/.content.xml b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/.content.xml new file mode 100755 index 0000000000..7256712059 --- /dev/null +++ b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/.content.xml @@ -0,0 +1,7 @@ + + diff --git a/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/basic/.content.xml b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/basic/.content.xml new file mode 100755 index 0000000000..109206d96b --- /dev/null +++ b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/termsandconditions/basic/.content.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/termsandconditions/.content.xml b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/termsandconditions/.content.xml new file mode 100644 index 0000000000..3edadd6c63 --- /dev/null +++ b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/termsandconditions/.content.xml @@ -0,0 +1,5 @@ + +