Skip to content

Commit b8a0c36

Browse files
[FORMS-16370] [FORMS-16201] Re-saving of draft creates new draft instead of updating existing draft (#1503)
* [Draft] Re-saving of draft creates new draft instead of updating existing draft * FORMS-16201 Register auto save in publish(disabled) mode only
1 parent 0d552d7 commit b8a0c36

File tree

13 files changed

+232
-32
lines changed

13 files changed

+232
-32
lines changed

bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/ReservedProperties.java

+2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ private ReservedProperties() {
162162
public static final String FD_ENABLE_AUTO_SAVE = "fd:enableAutoSave";
163163
public static final String FD_AUTO_SAVE_STRATEGY_TYPE = "fd:autoSaveStrategyType";
164164
public static final String FD_AUTO_SAVE_INTERVAL = "fd:autoSaveInterval";
165+
166+
public static final String FD_DRAFT_ID = "fd:draftId";
165167
private static final Set<String> reservedProperties = aggregateReservedProperties();
166168

167169
private static Set<String> aggregateReservedProperties() {

bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImpl.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public class FormContainerImpl extends AbstractContainerImpl implements FormCont
8383
@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
8484
private CoreComponentCustomPropertiesProvider coreComponentCustomPropertiesProvider;
8585

86+
private static final String DRAFT_PREFILL_SERVICE = "service://FP/draft/";
87+
8688
@SlingObject(injectionStrategy = InjectionStrategy.OPTIONAL)
8789
@Nullable
8890
private SlingHttpServletRequest request;
@@ -342,9 +344,19 @@ public String getLanguageDirection() {
342344
(request != null && StringUtils.isNotBlank(request.getParameter(GuideConstants.AF_DATA_REF)))) {
343345
formDataEnabled = true;
344346
}
347+
348+
// set draftId in properties in case of forms portal prefill
349+
if (request != null && StringUtils.isNotBlank(request.getParameter(GuideConstants.AF_DATA_REF))) {
350+
final String dataRef = request.getParameter(GuideConstants.AF_DATA_REF);
351+
if (dataRef.startsWith(DRAFT_PREFILL_SERVICE)) {
352+
properties.put(ReservedProperties.FD_DRAFT_ID, StringUtils.substringAfter(dataRef, DRAFT_PREFILL_SERVICE));
353+
}
354+
}
345355
properties.put(FD_ROLE_ATTRIBUTE, getRoleAttribute());
346356
properties.put(FD_FORM_DATA_ENABLED, formDataEnabled);
347-
properties.put(ReservedProperties.FD_AUTO_SAVE_PROPERTY_WRAPPER, this.autoSaveConfig);
357+
if (this.autoSaveConfig != null && this.autoSaveConfig.isEnableAutoSave()) {
358+
properties.put(ReservedProperties.FD_AUTO_SAVE_PROPERTY_WRAPPER, this.autoSaveConfig);
359+
}
348360
properties.put(FD_CUSTOM_FUNCTIONS_URL, getCustomFunctionUrl());
349361
properties.put(FD_DATA_URL, getDataUrl());
350362

@@ -406,4 +418,10 @@ public String getCustomFunctionUrl() {
406418
return getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/customfunctions/" + getId();
407419
}
408420

421+
@JsonIgnore
422+
@Override
423+
public AutoSaveConfiguration getAutoSaveConfig() {
424+
return autoSaveConfig;
425+
}
426+
409427
}

bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/FormContainer.java

+11
Original file line numberDiff line numberDiff line change
@@ -385,4 +385,15 @@ default String getCustomFunctionUrl() {
385385
return null;
386386
}
387387

388+
/**
389+
* Returns the auto save configuration
390+
*
391+
* @return auto save configuration
392+
* @since com.adobe.cq.forms.core.components.models.form 5.11.0
393+
*/
394+
@JsonIgnore
395+
default AutoSaveConfiguration getAutoSaveConfig() {
396+
return null;
397+
}
398+
388399
}

bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* </p>
3636
*/
3737

38-
@Version("5.10.0")
38+
@Version("5.11.0")
3939
package com.adobe.cq.forms.core.components.models.form;
4040

4141
import org.osgi.annotation.versioning.Version;

bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImplTest.java

+96-5
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,14 @@
4646
import com.adobe.cq.export.json.SlingModelFilter;
4747
import com.adobe.cq.forms.core.Utils;
4848
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
49-
import com.adobe.cq.forms.core.components.models.form.FieldType;
50-
import com.adobe.cq.forms.core.components.models.form.FormClientLibManager;
51-
import com.adobe.cq.forms.core.components.models.form.FormContainer;
52-
import com.adobe.cq.forms.core.components.models.form.TextInput;
53-
import com.adobe.cq.forms.core.components.models.form.ThankYouOption;
49+
import com.adobe.cq.forms.core.components.internal.form.ReservedProperties;
50+
import com.adobe.cq.forms.core.components.models.form.*;
5451
import com.adobe.cq.forms.core.context.FormsCoreComponentTestContext;
5552
import com.day.cq.i18n.I18n;
5653
import com.day.cq.wcm.api.NameConstants;
5754
import com.day.cq.wcm.api.Page;
5855
import com.day.cq.wcm.api.PageManager;
56+
import com.day.cq.wcm.foundation.model.export.AllowedComponentsExporter;
5957
import com.day.cq.wcm.msm.api.MSMNameConstants;
6058
import io.wcm.testing.mock.aem.junit5.AemContext;
6159
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
@@ -78,6 +76,8 @@ public class FormContainerImplTest {
7876
private static final String CONTENT_DAM_ROOT = "/content/dam/formsanddocuments/demo";
7977
private static final String PATH_FORM_1 = CONTENT_ROOT + "/formcontainerv2";
8078
private static final String PATH_FORM_WITHOUT_FIELDTYPE = CONTENT_ROOT + "/formcontainerv2-without-fieldtype";
79+
80+
private static final String PATH_FORM_WITH_AUTO_SAVE = CONTENT_ROOT + "/formcontainerv2WithAutoSave";
8181
private static final String PATH_FORM_1_WITHOUT_REDIRECT = CONTENT_ROOT + "/formcontainerv2WithoutRedirect";
8282
private static final String CONTENT_FORM_WITHOUT_PREFILL_ROOT = "/content/forms/af/formWithoutPrefill";
8383
private static final String PATH_FORM_WITHOUT_PREFILL = CONTENT_FORM_WITHOUT_PREFILL_ROOT + "/formcontainerv2WithoutPrefill";
@@ -243,6 +243,14 @@ void testJSONExport() throws Exception {
243243
Utils.testJSONExport(formContainer, Utils.getTestExporterJSONPath(BASE, PATH_FORM_1));
244244
}
245245

246+
@Test
247+
void testJSONExportWithAutoSaveEnable() throws Exception {
248+
context.load().json(BASE + "/test-content-auto-save.json", PATH_FORM_WITH_AUTO_SAVE);
249+
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_WITH_AUTO_SAVE,
250+
FormContainer.class, context);
251+
Utils.testJSONExport(formContainer, Utils.getTestExporterJSONPath(BASE, PATH_FORM_WITH_AUTO_SAVE));
252+
}
253+
246254
@Test
247255
void testGetThankYouMessage() throws Exception {
248256
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_1, FormContainer.class, context);
@@ -455,6 +463,30 @@ void testGetFormDataEnabledWhenDataRefIsSet() throws Exception {
455463
request.setParameterMap(new HashMap<>());
456464
}
457465

466+
@Test
467+
void testDraftIdPropertyWhenDataRefIsSet() throws Exception {
468+
MockSlingHttpServletRequest request = context.request();
469+
Map<String, Object> tempMap = new HashMap<>();
470+
tempMap.put(GuideConstants.AF_DATA_REF, "service://FP/draft/KH5DOFY2RMWVOOVREE324MRXIY");
471+
request.setParameterMap(tempMap);
472+
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_WITHOUT_PREFILL, FormContainer.class, context);
473+
assertEquals("KH5DOFY2RMWVOOVREE324MRXIY", formContainer.getProperties().get(ReservedProperties.FD_DRAFT_ID));
474+
// reset the parameter map
475+
request.setParameterMap(new HashMap<>());
476+
}
477+
478+
@Test
479+
void testDraftIdPropertyWhenDraftIdIsNotPresentInDataRef() throws Exception {
480+
MockSlingHttpServletRequest request = context.request();
481+
Map<String, Object> tempMap = new HashMap<>();
482+
tempMap.put(GuideConstants.AF_DATA_REF, "service://FP/draft");
483+
request.setParameterMap(tempMap);
484+
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_WITHOUT_PREFILL, FormContainer.class, context);
485+
assertNull(formContainer.getProperties().get(ReservedProperties.FD_DRAFT_ID));
486+
// reset the parameter map
487+
request.setParameterMap(new HashMap<>());
488+
}
489+
458490
@Test
459491
void testGetFormDataDisabled() throws Exception {
460492
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_WITHOUT_PREFILL, FormContainer.class, context);
@@ -530,4 +562,63 @@ void testCustomFunctionUrl() throws Exception {
530562
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_1, FormContainer.class, context);
531563
assertEquals("/adobe/forms/af/customfunctions/L2NvbnRlbnQvZm9ybXMvYWYvZGVtbw==", formContainer.getCustomFunctionUrl());
532564
}
565+
566+
@Test
567+
public void testGetAutoSaveProperties() throws Exception {
568+
context.load().json(BASE + "/test-content-auto-save.json", PATH_FORM_WITH_AUTO_SAVE);
569+
FormContainer formContainer = Utils.getComponentUnderTest(PATH_FORM_WITH_AUTO_SAVE,
570+
FormContainer.class, context);
571+
assertNotNull(formContainer.getAutoSaveConfig());
572+
assertTrue(formContainer.getAutoSaveConfig().isEnableAutoSave());
573+
assertEquals(AutoSaveConfiguration.AutoSaveStrategyType.TIME, formContainer.getAutoSaveConfig().getAutoSaveStrategyType());
574+
}
575+
576+
@Test
577+
public void testDefaultGetAutoSaveConfig() throws Exception {
578+
FormContainer formContainer1 = new FormContainer() {
579+
580+
@Override
581+
public FormMetaData getMetaData() {
582+
return null;
583+
}
584+
585+
@Override
586+
public String getEncodedCurrentPagePath() {
587+
return null;
588+
}
589+
590+
@Override
591+
public String getThankYouMessage() {
592+
return null;
593+
}
594+
595+
@Override
596+
public List<? extends ComponentExporter> getItems() {
597+
return null;
598+
}
599+
600+
@Override
601+
public String getGridClassNames() {
602+
return null;
603+
}
604+
605+
@Override
606+
public Map<String, String> getColumnClassNames() {
607+
return null;
608+
}
609+
610+
@Override
611+
public int getColumnCount() {
612+
return 0;
613+
}
614+
615+
@Override
616+
public AllowedComponentsExporter getExportedAllowedComponents() {
617+
return null;
618+
}
619+
};
620+
;
621+
assertNull(formContainer1.getAutoSaveConfig());
622+
}
623+
533624
}

bundles/af-core/src/test/resources/form/formcontainer/exporter-formcontainerv2.json

-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
"dorType": "generate",
99
"dorTemplateRef": "xyz"
1010
},
11-
"fd:autoSave": {
12-
"fd:enableAutoSave":false
13-
},
1411
"fd:path": "/content/forms/af/demo/jcr:content/formcontainerv2",
1512
"fd:isHamburgerMenuEnabled": false,
1613
"fd:schemaType": "BASIC",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"id": "L2NvbnRlbnQvZm9ybXMvYWYvZGVtbw==",
3+
"fieldType": "form",
4+
"lang": "en",
5+
"properties": {
6+
"thankyouPage": "/a/b/c",
7+
"fd:path": "/content/forms/af/demo/jcr:content/formcontainerv2WithAutoSave",
8+
"fd:schemaType": "BASIC",
9+
"fd:isHamburgerMenuEnabled": false,
10+
"fd:roleAttribute": null,
11+
"fd:formDataEnabled": true,
12+
"fd:autoSave": {
13+
"fd:enableAutoSave": true,
14+
"fd:autoSaveStrategyType": "time",
15+
"fd:autoSaveInterval": 2
16+
},
17+
"fd:customFunctionsUrl": "/adobe/forms/af/customfunctions/L2NvbnRlbnQvZm9ybXMvYWYvZGVtbw==",
18+
"fd:dataUrl": "/adobe/forms/af/data/L2NvbnRlbnQvZm9ybXMvYWYvZGVtbw=="
19+
},
20+
"action": "/adobe/forms/af/submit/L2NvbnRlbnQvZm9ybXMvYWYvZGVtbw==",
21+
"events": {
22+
"custom:setProperty": [
23+
"$event.payload"
24+
]
25+
},
26+
":itemsOrder": [
27+
"textinput"
28+
],
29+
"adaptiveform": "0.14.2",
30+
"metadata": {
31+
"grammar": "json-formula-1.0.0",
32+
"version": "1.0.0"
33+
},
34+
":type": "core/fd/components/form/container/v2/container",
35+
":items": {
36+
"textinput": {
37+
"id": "textinput-2ddda8d6f9",
38+
"fieldType": "text-input",
39+
"name": "abc",
40+
"visible": false,
41+
"description": "dummy",
42+
"type": "string",
43+
"label": {
44+
"value": "def",
45+
"visible": true
46+
},
47+
"properties": {
48+
"customProp": "customPropValue",
49+
"fd:dor": {
50+
"dorExclusion": false
51+
},
52+
"fd:path": "/content/forms/af/demo/jcr:content/formcontainerv2WithAutoSave/textinput"
53+
},
54+
"events": {
55+
"custom:setProperty": [
56+
"$event.payload"
57+
]
58+
},
59+
":type": "core/fd/components/form/textinput/v1/textinput"
60+
}
61+
}
62+
}

bundles/af-core/src/test/resources/form/formcontainer/test-content-auto-save.json

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,16 @@
77
"prefillService" : "abc",
88
"fd:enableAutoSave": "true",
99
"fd:autoSaveInterval": "2",
10-
"fd:autoSaveStrategyType": "time"
10+
"fd:autoSaveStrategyType": "time",
11+
"textinput" : {
12+
"jcr:primaryType": "nt:unstructured",
13+
"sling:resourceType" : "core/fd/components/form/textinput/v1/textinput",
14+
"name" : "abc",
15+
"jcr:title" : "def",
16+
"hideTitle" : false,
17+
"description" : "dummy",
18+
"fd:translationIds" : "{\"jcr:title\":\"guideContainer##textinput##jcr:title##5598\",\"placeholder\":\"guideContainer##textinput##description##5648\"}",
19+
"visible" : false,
20+
"customProp": "customPropValue"
21+
}
1122
}

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Adaptive Form container written in HTL.
2424
* Thank you page
2525
* Thank you message
2626
* Ability to drop other adaptive form components
27+
* Auto save feature for Drafts
2728

2829
### Use Object
2930
The Adaptive Form Container component uses the `com.adobe.cq.forms.core.components.models.form.FormContainer` Sling Model for its Use-object.
@@ -88,4 +89,6 @@ Apply a `data-cmp-is="adaptiveFormContainer"` attribute to the `cmp-adaptiveform
8889
Applying `data-cmp-adaptiveform-container-loader` attribute to the div specifically for applying the loader class on it, it is to ensure that the loading icon should not appear over components.
8990

9091
Applying `data-cmp-custom-functions-module-url` attribute to the div to point to the edge delivery URL of the custom functions file. Custom Functions exported from this file will be registered in Function Runtime.
91-
This Url should whitelist the AEM author/publish domain in the Cross Origin Resource Sharing (CORS) configuration.
92+
This Url should whitelist the AEM author/publish domain in the Cross Origin Resource Sharing (CORS) configuration.
93+
94+
Applying `data-cmp-auto-save` attribute to the `cmp-adaptiveform-container` block to control the auto-save functionality. If the attribute's value is set to true, auto-save will be enabled for the form; otherwise, it will not be triggered. This attribute will be set to true in published mode if enableAutoSave is enabled.

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/site/js/formcontainerview.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
*/
8989
#setupAutoSave(formModel) {
9090
const autoSaveProperties = formModel?.properties?.['fd:autoSave'];
91-
const enableAutoSave = autoSaveProperties?.['fd:enableAutoSave'];
91+
const enableAutoSave = this.#getAutoSaveAttribute();
9292
if (enableAutoSave) {
9393
const autoSaveStrategyType = autoSaveProperties['fd:autoSaveStrategyType'];
9494
const autoSaveInterval = autoSaveProperties['fd:autoSaveInterval'];
@@ -103,6 +103,10 @@
103103
}
104104
}
105105
}
106+
107+
#getAutoSaveAttribute() {
108+
return this.getFormElement()?.getAttribute('data-cmp-auto-save') === 'true';
109+
}
106110
}
107111

108112
async function onDocumentReady() {

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/container.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
data-sly-use.templates="core/wcm/components/commons/v1/templates.html"
3737
action="${container.metadata.action}"
3838
id="${container.id}"
39+
data-cmp-auto-save="${wcmmode.disabled && container.autoSaveConfig && container.autoSaveConfig.enableAutoSave ? 'true' : 'false'}"
3940
data-cmp-is="adaptiveFormContainer"
4041
data-cmp-context-path="${request.contextPath}"
4142
data-cmp-page-lang="${container.containingPageLang}"
@@ -76,4 +77,4 @@
7677
</div>
7778
</form>
7879
<div data-cmp-adaptiveform-container-loader="${container.id}"></div>
79-
</sly>
80+
</sly>

0 commit comments

Comments
 (0)