755febc4 by acetousk

Implement variable injection for global variables in the mjml editor for loading…

… and saving, handle parsing regex in groovy, ftl, and mjml, find the correct variables to update, replace non updated variables with a ftl version of the variables that won't error but return the variable expression for saving, and handle other problems
1 parent 768cad19
...@@ -181,11 +181,13 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -181,11 +181,13 @@ along with this software (see the LICENSE.md file). If not, see
181 // console.log('response ', response) 181 // console.log('response ', response)
182 window.htmlLocation = response.htmlLocation; 182 window.htmlLocation = response.htmlLocation;
183 window.grapesLocation = response.grapesLocation; 183 window.grapesLocation = response.grapesLocation;
184 const url = new URL(window.location.href) 184 // const url = new URL(window.location.href)
185 url.searchParams.set('htmlLocation', response.htmlLocation); 185 // url.searchParams.set('htmlLocation', response.htmlLocation);
186 url.searchParams.set('grapesLocation', response.grapesLocation); 186 // url.searchParams.set('grapesLocation', response.grapesLocation);
187 window.history.pushState({}, '', url) 187 // window.history.pushState({}, '', url)
188 188
189 window.moquiVars = response.moquiVars;
190 // console.log('init window.moquiVars ', window.moquiVars)
189 const projectData = JSON.parse(response.data); 191 const projectData = JSON.parse(response.data);
190 // console.log('window.projectData ', window.projectData) 192 // console.log('window.projectData ', window.projectData)
191 193
...@@ -215,18 +217,20 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -215,18 +217,20 @@ along with this software (see the LICENSE.md file). If not, see
215 // we have to properly update the body before the store and extract the 217 // we have to properly update the body before the store and extract the
216 // project data from the response result. 218 // project data from the response result.
217 onStore: data => { 219 onStore: data => {
218 return { id: window.grapesLocation, data, html:window.editor.runCommand('mjml-code-to-html')?.html } 220 return { id: window.grapesLocation, data, moquiVars:window.moquiVars, html:window.editor.runCommand('mjml-code-to-html')?.html }
219 }, 221 },
220 onLoad: result => { 222 onLoad: result => {
221 if (result.resourceId !== null) { 223 if (result.resourceId !== null) {
222 const url = new URL(window.location.href) 224 const url = new URL(window.location.href)
223 url.searchParams.set('grapesLocation', result.grapesLocation); 225 url.searchParams.set('grapesLocation', result.grapesLocation);
224 url.searchParams.set('htmlLocation', result.htmlLocation); 226 // url.searchParams.set('htmlLocation', result.htmlLocation);
225 url.searchParams.set('emailTemplateId', result.emailTemplateId); 227 // url.searchParams.set('emailTemplateId', result.emailTemplateId);
226 window.history.pushState({}, '', url) 228 window.history.pushState({}, '', url)
227 window.grapesLocation = result.grapesLocation; 229 window.grapesLocation = result.grapesLocation;
228 window.htmlLocation = result.htmlLocation; 230 window.htmlLocation = result.htmlLocation;
229 window.emailTemplateId = result.emailTemplateId; 231 window.emailTemplateId = result.emailTemplateId;
232 window.moquiVars = result.moquiVars;
233 // console.log('onLoad window.moquiVars ', window.moquiVars)
230 } 234 }
231 // console.log('onLoad ', result) 235 // console.log('onLoad ', result)
232 return result.data 236 return result.data
......
...@@ -14,6 +14,17 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -14,6 +14,17 @@ along with this software (see the LICENSE.md file). If not, see
14 --> 14 -->
15 <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd"> 15 <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd">
16 16
17 <service verb="get" noun="GlobalGrapeVarList">
18 <out-parameters>
19 <parameter name="baseLinkUrl"/>
20 <parameter name="currentYear"/>
21 </out-parameters>
22 <actions>
23 <set field="baseLinkUrl" from="!'production'.equals(System.getProperty('instance_purpose')) ? 'http://localhost:8080' : ec.web.getWebappRootUrl(true,true)" />
24 <set field="currentYear" from="ec.user.nowTimestamp.format('yyyy')"/>
25 </actions>
26 </service>
27
17 <service verb="load" noun="GrapeJs"> 28 <service verb="load" noun="GrapeJs">
18 <description>Load GrapesJs resource. Can be adapted to entity other than EmailTemplate, but must have data for the grapesLocation and htmlLocation to ensure safety of read and write of resources.</description> 29 <description>Load GrapesJs resource. Can be adapted to entity other than EmailTemplate, but must have data for the grapesLocation and htmlLocation to ensure safety of read and write of resources.</description>
19 <in-parameters> 30 <in-parameters>
...@@ -25,12 +36,12 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -25,12 +36,12 @@ along with this software (see the LICENSE.md file). If not, see
25 <parameter name="grapesLocation"/> 36 <parameter name="grapesLocation"/>
26 <parameter name="htmlLocation"/> 37 <parameter name="htmlLocation"/>
27 <parameter name="data"/> 38 <parameter name="data"/>
39 <parameter name="emailTemplateId"/>
40 <parameter name="moquiVars"/>
28 </out-parameters> 41 </out-parameters>
29 <actions> 42 <actions>
30 <if condition="grapesLocation == 'null'"><set field="grapesLocation" from="null"/></if> 43 <if condition="grapesLocation == 'null'"><set field="grapesLocation" from="null"/></if>
31 <if condition="htmlLocation == 'null'"><set field="htmlLocation" from="null"/></if> 44 <if condition="htmlLocation == 'null'"><set field="htmlLocation" from="null"/></if>
32 <!-- <log level="warn" message="resourceId is ${resourceId} resourceId.getClass().getName() ${resourceId.getClass().getName()} resourceId == 'null' ${resourceId == 'null'} resourceId == null ${resourceId == null}"/>-->
33 <!-- <log level="warn" message="load context.toString() ${context.toString()}"/>-->
34 <entity-find-one entity-name="moqui.basic.email.EmailTemplate" value-field="emailTemplate" auto-field-map="[emailTemplateId:emailTemplateId]"/> 45 <entity-find-one entity-name="moqui.basic.email.EmailTemplate" value-field="emailTemplate" auto-field-map="[emailTemplateId:emailTemplateId]"/>
35 <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if> 46 <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if>
36 <set field="grapesLocation" from="emailTemplate?.grapesLocation"/> 47 <set field="grapesLocation" from="emailTemplate?.grapesLocation"/>
...@@ -42,25 +53,84 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -42,25 +53,84 @@ along with this software (see the LICENSE.md file). If not, see
42 <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/> 53 <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/>
43 <set field="grapesFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.json')"/> 54 <set field="grapesFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.json')"/>
44 55
45 <set field="data" from="ec.resource.getLocationReference('dbresource://grapesjs/template/default.json').getText()"/> 56 <service-call name="mjml.MjmlServices.get#GlobalGrapeVarList" out-map="context"/>
57 <set field="dataRaw" from="ec.resource.getLocationReference('dbresource://grapesjs/template/default.json').getText()"/>
46 <set field="htmlLocation" from="grapesJsResource.location + '/' + htmlFile?.dbResourceId + '.html'"/> 58 <set field="htmlLocation" from="grapesJsResource.location + '/' + htmlFile?.dbResourceId + '.html'"/>
47 <set field="grapesLocation" from="grapesJsResource.location + '/' + grapesFile?.dbResourceId + '.json'"/> 59 <set field="grapesLocation" from="grapesJsResource.location + '/' + grapesFile?.dbResourceId + '.json'"/>
48 <script><![CDATA[ 60 <script><![CDATA[
49 htmlFile.move(htmlLocation) 61 htmlFile.move(htmlLocation)
50 grapesFile.putText(data) 62 grapesFile.putText(dataRaw)
51 grapesFile.move(grapesLocation) 63 grapesFile.move(grapesLocation)
52 ]]></script> 64 ]]></script>
53
54 <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,grapesLocation:grapesLocation,htmlLocation:htmlLocation]"/> 65 <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,grapesLocation:grapesLocation,htmlLocation:htmlLocation]"/>
66
67 <service-call name="mjml.MjmlServices.get#GlobalGrapeVarList" out-map="globalGrapeVarList"/>
68 <script><![CDATA[
69 context.putAll(globalGrapeVarList)
70
71 context.varList = globalGrapeVarList*.key.collect { '\\\$\\{'+it+'\\}' }
72 context.replaceVarRegexPattern = context.varList.join('|')
73 if (context.replaceVarRegexPattern) {
74 context.dataPre = context.dataRaw.replaceAll(context.replaceVarRegexPattern) { match ->
75 return "${match}"
76 }
77 }
78
79 context.allVarsRegexPattern = /\$\{[a-zA-Z_]\w*\}/
80 context.errorVarList = context.dataRaw.findAll(context.allVarsRegexPattern).unique().collect { it - '${' - '}' } - globalGrapeVarList*.key
81 context.errorTemplateRegexPattern = errorVarList.collect { '\\\$\\{'+it+'\\}' }.join('|')
82 if (context.errorTemplateRegexPattern) {
83 context.dataPre = context.dataPre.replaceAll(context.errorTemplateRegexPattern) { match ->
84 def cleanMatch = match - '${' - '}'
85 return "\${" + cleanMatch + "!'\$\\{" + cleanMatch + "}'}"
86 }
87 }
88 ]]></script>
89 <!-- <log level="warn" message="dataPre is ${dataPre}"/>-->
90 <set field="grapesTempFile" from="grapesJsResource.makeFile(grapesFile?.dbResourceId + '.temp.json')"/>
91 <script>grapesTempFile.putText(dataPre)</script>
92 <set field="data" from="ec.resource.template(grapesTempFile.location, 'ftl')"/>
93 <script>grapesTempFile.delete()</script>
94 <!-- <log level="warn" message="data is ${data}"/>-->
95 <set field="moquiVars" from="globalGrapeVarList"/>
55 </then> 96 </then>
56 <else-if condition="grapesLocation &amp;&amp; htmlLocation"> 97 <else-if condition="grapesLocation &amp;&amp; htmlLocation">
57 <set field="putDbResource" from="ec.resource.getLocationReference(grapesLocation)"/> 98 <set field="grapesFile" from="ec.resource.getLocationReference(grapesLocation)"/>
58 <!-- TODO: Is this a strong enough check to prevent unauthorized access? --> 99 <!-- TODO: Is this a strong enough check to prevent unauthorized access? -->
59 <if condition="!putDbResource || putDbResource.parent?.location != grapesJsResource.location"> 100 <if condition="!grapesFile || grapesFile.parent?.location != grapesJsResource.location">
60 <return error="true" message="Resource not found"/> 101 <return error="true" message="Resource not found"/>
61 </if> 102 </if>
62 103
63 <set field="data" from="putDbResource.getText()"/> 104 <service-call name="mjml.MjmlServices.get#GlobalGrapeVarList" out-map="globalGrapeVarList"/>
105 <set field="dataRaw" from="grapesFile.getText()"/>
106 <script><![CDATA[
107 context.putAll(globalGrapeVarList)
108
109 context.varList = globalGrapeVarList*.key.collect { '\\\$\\{'+it+'\\}' }
110 context.replaceVarRegexPattern = context.varList.join('|')
111 if (context.replaceVarRegexPattern) {
112 context.dataPre = context.dataRaw.replaceAll(context.replaceVarRegexPattern) { match ->
113 return "${match}"
114 }
115 }
116
117 context.allVarsRegexPattern = /\$\{[a-zA-Z_]\w*\}/
118 context.errorVarList = context.dataRaw.findAll(context.allVarsRegexPattern).unique().collect { it - '${' - '}' } - globalGrapeVarList*.key
119 context.errorTemplateRegexPattern = errorVarList.collect { '\\\$\\{'+it+'\\}' }.join('|')
120 if (context.errorTemplateRegexPattern) {
121 context.dataPre = context.dataPre.replaceAll(context.errorTemplateRegexPattern) { match ->
122 def cleanMatch = match - '${' - '}'
123 return "\${" + cleanMatch + "!'\$\\{" + cleanMatch + "}'}"
124 }
125 }
126 ]]></script>
127 <!-- <log level="warn" message="dataPre is ${dataPre}"/>-->
128 <set field="grapesTempFile" from="grapesJsResource.makeFile(grapesFile?.dbResourceId + '.temp.json')"/>
129 <script>grapesTempFile.putText(dataPre)</script>
130 <set field="data" from="ec.resource.template(grapesTempFile.location, 'ftl')"/>
131 <script>grapesTempFile.delete()</script>
132 <!-- <log level="warn" message="data is ${data}"/>-->
133 <set field="moquiVars" from="globalGrapeVarList"/>
64 </else-if> 134 </else-if>
65 <else> 135 <else>
66 <return error="true" message="Resource not found"/> 136 <return error="true" message="Resource not found"/>
...@@ -75,6 +145,7 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -75,6 +145,7 @@ along with this software (see the LICENSE.md file). If not, see
75 <parameter name="grapesLocation"/> 145 <parameter name="grapesLocation"/>
76 <parameter name="emailTemplateId"/> 146 <parameter name="emailTemplateId"/>
77 <parameter name="data"/> 147 <parameter name="data"/>
148 <parameter name="moquiVars"/>
78 <parameter name="html" allow-html="any"/> 149 <parameter name="html" allow-html="any"/>
79 </in-parameters> 150 </in-parameters>
80 <out-parameters> 151 <out-parameters>
...@@ -88,12 +159,15 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -88,12 +159,15 @@ along with this software (see the LICENSE.md file). If not, see
88 <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if> 159 <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if>
89 <set field="grapesLocation" from="emailTemplate?.grapesLocation"/> 160 <set field="grapesLocation" from="emailTemplate?.grapesLocation"/>
90 <set field="htmlLocation" from="emailTemplate?.htmlLocation"/> 161 <set field="htmlLocation" from="emailTemplate?.htmlLocation"/>
91 <set field="data" from="groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parseText(ec.web.secureRequestParameters._requestBodyText).data)"/> 162 <set field="dataMap" from="new groovy.json.JsonSlurper().parseText(ec.web.secureRequestParameters._requestBodyText).data"/>
163 <!-- <log level="warn" message="dataMap is ${dataMap}"/>-->
164 <set field="moquiVars" from="new groovy.json.JsonSlurper().parseText(ec.web.secureRequestParameters._requestBodyText).moquiVars"/>
165 <set field="data" from="groovy.json.JsonOutput.toJson(dataMap)"/>
92 166
93 <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> 167 <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/>
94 <if condition="!htmlLocation &amp;&amp; !grapesLocation"> 168 <if condition="!htmlLocation &amp;&amp; !grapesLocation">
95 <then> 169 <then>
96 <!-- TODO: This should work, but isn't used anywhere and is untested. 170 <!-- TODO: This should work as of 2024 May 14, but isn't used anywhere and is untested. There will need to be work done based on the dataMap code
97 <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/> 171 <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/>
98 <set field="grapesFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.json')"/> 172 <set field="grapesFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.json')"/>
99 173
...@@ -118,7 +192,21 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -118,7 +192,21 @@ along with this software (see the LICENSE.md file). If not, see
118 <if condition="!grapesFile || grapesFile.parent?.location != grapesJsResource.location"> 192 <if condition="!grapesFile || grapesFile.parent?.location != grapesJsResource.location">
119 <return error="true" message="Resource not found"/> 193 <return error="true" message="Resource not found"/>
120 </if> 194 </if>
121 <script>grapesFile.putText(data)</script> 195 <script><![CDATA[
196 context.replaceMoquiVarRegexPattern = context.moquiVars*.value.join('|')
197
198 if (context.replaceMoquiVarRegexPattern) {
199 context.dataPre = data.replaceAll(context.replaceMoquiVarRegexPattern) { match ->
200 def output = moquiVars.find { it.value == match }?.key
201 return '${' + output + '}'
202 }
203 }
204 ]]></script>
205 <script>grapesFile.putText(dataPre)</script>
206
207 <!-- <set field="dataRaw" from="grapesFile.getText()"/>-->
208 <!-- <set field="dataRawMap" from="new groovy.json.JsonSlurper().parseText(dataRaw)"/>-->
209 <!-- <script>grapesFile.putText(data)</script>-->
122 210
123 <set field="htmlFile" from="null"/> 211 <set field="htmlFile" from="null"/>
124 <if condition="htmlLocation"><then> 212 <if condition="htmlLocation"><then>
...@@ -141,7 +229,7 @@ along with this software (see the LICENSE.md file). If not, see ...@@ -141,7 +229,7 @@ along with this software (see the LICENSE.md file). If not, see
141 <if condition="!htmlFile || htmlFile.parent?.location != grapesJsResource.location"> 229 <if condition="!htmlFile || htmlFile.parent?.location != grapesJsResource.location">
142 <return error="true" message="Resource not found"/> 230 <return error="true" message="Resource not found"/>
143 </if> 231 </if>
144 <script><![CDATA[htmlFile.putText(html)]]></script> 232 <!-- <script><![CDATA[htmlFile.putText(html)]]></script>-->
145 </else-if> 233 </else-if>
146 <else> 234 <else>
147 <return error="true" message="Resource not found"/> 235 <return error="true" message="Resource not found"/>
......