@@ -8,16 +8,14 @@ import org.orbeon.oxf.fr.FormRunnerCommon.frc
8
8
import org .orbeon .oxf .fr .email .EmailMetadata .HeaderName .Custom
9
9
import org .orbeon .oxf .fr .email .EmailMetadata .{TemplateMatch , TemplateValue }
10
10
import org .orbeon .oxf .fr .email .{Attachment , EmailContent , EmailMetadata , EmailMetadataParsing }
11
- import org .orbeon .oxf .fr .persistence .api .PersistenceApi
12
11
import org .orbeon .oxf .fr .process .RenderedFormat
13
12
import org .orbeon .oxf .fr .s3 .{S3 , S3Config }
14
- import org .orbeon .oxf .http .HttpMethod
15
13
import org .orbeon .oxf .util .StringUtils .*
16
14
import org .orbeon .oxf .util .{CoreCrossPlatformSupportTrait , IndentedLogger , TryUtils , XPathCache }
17
15
import org .orbeon .oxf .xforms .action .XFormsAPI .inScopeContainingDocument
18
16
import org .orbeon .oxf .xforms .function .XFormsFunction
19
17
import org .orbeon .saxon .om
20
- import org .orbeon .saxon .om .{NodeInfo , SequenceIterator }
18
+ import org .orbeon .saxon .om .{Item , NodeInfo , SequenceIterator }
21
19
import org .orbeon .saxon .value .{BooleanValue , StringValue }
22
20
import org .orbeon .scaxon .Implicits .*
23
21
import org .orbeon .scaxon .SimplePath .*
@@ -32,7 +30,7 @@ import scala.util.Try
32
30
33
31
trait FormRunnerEmailBackend {
34
32
35
- // Only used from `email-form.xsl` and not needed offline.
33
+ // Only used from `email-form.xsl`/EmailContent and not needed offline.
36
34
// @XPathFunction
37
35
def emailAttachmentFilename (
38
36
data : NodeInfo ,
@@ -81,7 +79,7 @@ trait FormRunnerEmailBackend {
81
79
val emailTemplateOpt = emailTemplateElemOpt.map(EmailMetadataParsing .parseCurrentTemplate(_, formDefinition))
82
80
val templateValues = emailTemplateOpt.toList.flatMap(_.headers.filter(_._1.entryName == headerName).map(_._2))
83
81
84
- values (formDefinition, formData, templateValues)
82
+ evaluatedTemplateValues (formDefinition, formData, templateValues)
85
83
}
86
84
87
85
// @XPathFunction
@@ -93,44 +91,65 @@ trait FormRunnerEmailBackend {
93
91
val emailTemplateOpt = emailTemplateElemOpt.map(EmailMetadataParsing .parseCurrentTemplate(_, formDefinition))
94
92
val templateValues = emailTemplateOpt.toList.flatMap(_.controlsToAttach)
95
93
96
- values (formDefinition, formData, templateValues)
94
+ evaluatedTemplateValues (formDefinition, formData, templateValues)
97
95
}
98
96
99
- def values (
100
- formDefinition : NodeInfo ,
101
- formData : NodeInfo ,
102
- templateValues : List [TemplateValue ]
103
- ): SequenceIterator = {
97
+ def evaluatedTemplateValues (
98
+ formDefinition : NodeInfo ,
99
+ formData : NodeInfo ,
100
+ templateValues : List [TemplateValue ]
101
+ ): SequenceIterator =
102
+ templateValues.flatMap(evaluatedTemplateValue(formDefinition, formData, _))
103
+
104
+ def evaluatedTemplateValue (
105
+ formDefinition : NodeInfo ,
106
+ formData : NodeInfo ,
107
+ templateValue : TemplateValue
108
+ ): List [Item ] =
109
+ templateValue match {
110
+ case TemplateValue .Control (controlName, sectionOpt) =>
111
+ controlValue(formDefinition, formData, controlName, sectionOpt)
112
+
113
+ case TemplateValue .Expression (expression) =>
114
+ expressionValue(formDefinition, expression)
115
+
116
+ case TemplateValue .Text (text) =>
117
+ List (StringValue .makeStringValue(text))
118
+ }
119
+
120
+ def controlValue (
121
+ formDefinition : NodeInfo ,
122
+ formData : NodeInfo ,
123
+ controlName : String ,
124
+ sectionOpt : Option [String ]
125
+ ): List [NodeInfo ] = {
104
126
105
127
val formDefinitionCtx = new InDocFormRunnerDocContext (formDefinition)
106
128
107
- templateValues.flatMap {
108
- // Control not in section template
109
- case TemplateValue . Control (controlName, None ) =>
129
+ sectionOpt match {
130
+ case None =>
131
+ // Control not in section template
110
132
frc.searchControlsTopLevelOnly(
111
133
data = Some (formData),
112
134
predicate = FormRunnerCommon .frc.getControlName(_) == controlName)(
113
135
ctx = formDefinitionCtx
114
- ).flatMap(_.holders).flatten
136
+ ).toList. flatMap(_.holders).flatten
115
137
116
- // Control in section template
117
- case TemplateValue . Control (controlName, Some (sectionTemplate)) =>
138
+ case Some ( section) =>
139
+ // Control in section template
118
140
frc.searchControlsUnderSectionTemplates(
119
141
head = formDefinition.rootElement.child(" *:head" ).head,
120
142
data = Some (formData),
121
143
controlPredicate = FormRunnerCommon .frc.getControlName(_) == controlName,
122
- sectionPredicate = frc.getControlNameOpt(_).contains(sectionTemplate ))(
144
+ sectionPredicate = frc.getControlNameOpt(_).contains(section ))(
123
145
ctx = formDefinitionCtx
124
- ).flatMap(_.holders).flatten
125
-
126
- case TemplateValue .Expression (expression) =>
127
- evaluatedExpressionAsStrings(formDefinition, expressionWithProcessedVarReferences(formDefinition, expression))
128
-
129
- case TemplateValue .Text (text) =>
130
- List (StringValue .makeStringValue(text))
146
+ ).toList.flatMap(_.holders).flatten
131
147
}
132
148
}
133
149
150
+ def expressionValue (formDefinition : NodeInfo , expression : String ): List [StringValue ] =
151
+ evaluatedExpressionAsStrings(formDefinition, expressionWithProcessedVarReferences(formDefinition, expression))
152
+
134
153
private def expressionWithProcessedVarReferences (formDefinition : NodeInfo , expression : String ): String = {
135
154
val formDefinitionCtx = new InDocFormRunnerDocContext (formDefinition)
136
155
@@ -205,6 +224,8 @@ trait FormRunnerEmailBackend {
205
224
language : String ,
206
225
templateNameOpt : Option [String ]
207
226
)(implicit
227
+ logger : IndentedLogger ,
228
+ coreCrossPlatformSupport : CoreCrossPlatformSupportTrait ,
208
229
formRunnerParams : FormRunnerParams
209
230
): List [EmailContent ] = {
210
231
@@ -243,42 +264,24 @@ trait FormRunnerEmailBackend {
243
264
emailContent : EmailContent ,
244
265
s3PathPrefix : String
245
266
)(implicit
246
- logger : IndentedLogger ,
247
- coreCrossPlatformSupport : CoreCrossPlatformSupportTrait ,
248
- formRunnerParams : FormRunnerParams ,
249
267
s3Config : S3Config ,
250
268
s3Client : S3Client
251
269
): Try [Unit ] = {
252
270
// TODO: store email body and headers as well
253
- TryUtils .sequenceLazily(emailContent.allAttachments )(storeAttachmentToS3(_, s3PathPrefix)).map(_ => ())
271
+ TryUtils .sequenceLazily(emailContent.attachments )(storeAttachmentToS3(_, s3PathPrefix)).map(_ => ())
254
272
}
255
273
256
274
private def storeAttachmentToS3 (
257
- attachment : Attachment ,
258
- s3PathPrefix : String
275
+ attachment : Attachment ,
276
+ s3PathPrefix : String
259
277
)(implicit
260
- logger : IndentedLogger ,
261
- coreCrossPlatformSupport : CoreCrossPlatformSupportTrait ,
262
- formRunnerParams : FormRunnerParams ,
263
- s3Config : S3Config ,
264
- s3Client : S3Client
278
+ s3Config : S3Config ,
279
+ s3Client : S3Client
265
280
): Try [PutObjectResponse ] = {
266
281
267
- val key = s3PathPrefix + attachment.filename
268
-
269
- attachment.data match {
270
- case Left (uri) =>
271
- // Attachment given as URI, stream/download it to S3
272
- val connectionResult = PersistenceApi .connectPersistence(
273
- method = HttpMethod .GET ,
274
- pathQuery = uri.toString,
275
- formVersionOpt = Left (FormDefinitionVersion .Specific (formRunnerParams.formVersion)).some
276
- )
277
-
278
- S3 .write(key, connectionResult.content.stream, connectionResult.content.contentLength, attachment.contentType.some)
279
- case Right (byteArray) =>
280
- // Attachment given as byte array, store it to S3 directly
281
- S3 .write(key, byteArray, attachment.contentType.some)
282
- }
282
+ val key = s3PathPrefix + attachment.filename
283
+ val content = attachment.data.content()
284
+
285
+ S3 .write(key, content.stream, content.contentLength, attachment.contentType.some)
283
286
}
284
287
}
0 commit comments