Wiki-Quellcode von InvitationCommon

Zuletzt geändert von base4it Admin am 2025/11/04 19:31

Zeige letzte Bearbeiter
1 {{velocity}}
2 #*
3 * Invitation Application
4 * This document contains common macros used by all documents in the Invitation Application.
5 *
6 * Macros in this script don't rely on any variables except those which are passed to them and the following:
7 *
8 * $doc the com.xpn.xwiki.api.Document object representing the document containing this code.
9 * $msg the internationalization message provider containing a get(String) and a get(String, List) function
10 * $xcontext the com.xpn.xwiki.Context object for this request
11 * $xwiki an object of the com.xpn.xwiki.api.XWiki class.
12 * $escapetool an object of class org.apache.velocity.tools.generic.EscapeTool
13 * $util used to get a newline character ($util.getNewLine())
14 *
15 * No macros in this script depend on any other macros.
16 *###
17 ##
18 #if($request.getParameter('test') == '1')
19 {{info}}testLoadInvitationConfig{{/info}}
20 #testLoadInvitationConfig()
21 #elseif($doc.documentReference.name == 'InvitationCommon')
22 #set ($linkTarget = "${doc.getSpace()}.WebHome")
23 #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
24 {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
25 #end
26 ##
27 #*
28 * Display a message for the sender (preview) or for the admin (review sent messages)
29 *
30 * $mail (XObject representing email message) the message to view
31 *
32 * $recipients (List<String>) (Optional) the list of email addresses to override the list provided by $mail
33 * used for preview because createMailFromTemplate will exclude addresses
34 * which are invalid and we want to show the invalid addresses to the
35 * user to tell them that they need to correct them.
36 *
37 * $invalidAddresses (List<String>) (Optional) List of invalid email addresses in recipients. Needed if you want to
38 * show the user that they made a mistake on some addresses.
39 * For each email in $invalidEmails, if it is also in $recipients, then it
40 * will be marked but left in the same order, emails in $invlaidEmails but
41 * not found in $recipients will end up at the end of the list.
42 *###
43 #macro(displayMessage, $mail, $recipients, $invalidAddresses)
44
45 {{html wiki=false clean=false}}
46 <div id="invitation-displaymessage" class="invitation">
47 <strong>$escapetool.xml($services.localization.render('xe.invitation.previewLabel'))</strong>
48 <div class="invitation invitation-preview">
49 #set($recips = [])
50 #set($invalid = [])
51 ## get the lists of valid and invalid email addresses.
52 #if("$!invalidAddresses" == '')
53 #set($invalid = [])
54 #if("$!recipients" == '')
55 #set($recips = [$mail.getProperty('recipient').getValue().trim()])
56 #else
57 #set($discard = $recips.addAll($recipients))
58 #end
59 #else
60 ## Set to local variables to prevent altering input values.
61 #set($discard = $recips.addAll($recipients))
62 #set($discard = $invalid.addAll($invalidAddresses))
63 #end
64 ## Print the email addresses to be sent to.
65 ## To:
66 <strong>$escapetool.xml($services.localization.render('xe.invitation.toLabel'))</strong>
67 <div id="preview-to-field" class="invitation-preview field">
68 #foreach($recip in $recips)
69 #if($invalid.contains($recip))
70 <span class="invalid-address">$!escapetool.xml($!recip)</span> ##
71 #set($discard = $invalid.remove($recip))
72 #else
73 <span class="valid-address">$!escapetool.xml($!recip)</span> ##
74 #end
75 #end
76 #foreach($recip in $invalid)
77 <span class="invalid-address">$!escapetool.xml($!recip)</span> ##
78 #end
79 &nbsp; ## used to make the field the correct size if it's empty.
80 </div>
81 ## Tell the user that some of the email addresses are invalid.
82 #if($invalidAddresses && $invalidAddresses.size() > 0)
83 <p class="invalid-address-message">
84 {{/html}}
85 {{error}}
86 #if($recips.size() == 1)
87 ## The email address given is invalid and will not be sent to.
88 $services.rendering.escape($services.localization.render('xe.invitation.displayMessage.theAddressIsInvalid'), 'xwiki/2.1')
89 #else
90 #if($invalid.size() > 1)
91 $services.rendering.escape($services.localization.render('xe.invitation.displayMessage.someAddressesAreInvalid', [$invalidAddresses.size()]), 'xwiki/2.1')
92 #else
93 $services.rendering.escape($services.localization.render('xe.invitation.displayMessage.anAddressesIsInvalid'), 'xwiki/2.1')
94 #end
95 #end
96 {{/error}}
97 {{html wiki=false clean=false}}
98 </p>
99 #end
100 ## Subject:
101 <strong>$escapetool.xml($services.localization.render('xe.invitation.subjectLabel'))</strong>
102 <div id="preview-subjectline-field" class="invitation-preview field">
103 $escapetool.xml($mail.getProperty('subjectLine').getValue())
104 </div>
105 ## Message:
106 <strong>$escapetool.xml($services.localization.render('xe.invitation.contentLabel'))</strong>
107 <div id="preview-messagebody-field" class="invitation-preview field">
108 $mail.getProperty('messageBody').getValue()
109 </div>
110 </div>
111 </div>
112 {{/html}}
113
114 #end
115 ##
116 #*
117 * Load the configuration.
118 * Only works if the script calling this macro has permission to view InvitationConfig
119 * (or create it if it doesn't exist)
120 *
121 * $config (Map<String, String>) will be populated with invitation configuration.
122 *
123 * $configDocName (String) (Optional) will load configuration from this document, if not specified will use
124 * 'InvitationConfig' in the same space as $doc.
125 *
126 * $configClassName (String) (Optional) will load configuration from object of this class, if not specified will use
127 * 'Invitation' in the same space as $doc.
128 *###
129 #macro(loadInvitationConfig, $config, $configDocName, $configClassName)
130 #define($discard)
131 #if("$!configDocName" == '')
132 #set($configDocNameInternal = "${doc.getSpace()}.InvitationConfig")
133 #else
134 #set($configDocNameInternal = $configDocName)
135 #end
136 #if("$!configClassName" == '')
137 #set($configClassNameInternal = "${doc.getSpace()}.WebHome")
138 #else
139 #set($configClassNameInternal = $configClassName)
140 #end
141 ##
142 ## Load some parameters from the configuration.
143 #set($configDoc = $xwiki.getDocumentAsAuthor($configDocNameInternal))
144 ##
145 ## If no configuration document exists, create one and save it.
146 #if($configDoc.isNew())
147 ##
148 ## load the default configuration from this document.
149 #set($thisDocument = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationCommon"))
150 #set($defaultConfigObj = $thisDocument.getObject($configClassNameInternal))
151 #foreach($element in $defaultConfigObj.getProperties())
152 $config.put($element.getName(), $defaultConfigObj.getProperty($element.getName()).getValue())
153 #end
154 ##
155 #set($configDocContent =
156 '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
157 + '[$services.rendering.escape("' + "$!config.get('mainPage')"
158 + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
159 $configDoc.setContent($configDocContent)
160 $configDoc.setParent($configClassNameInternal)
161 #set($configObj = $configDoc.newObject($configClassNameInternal))
162 #foreach($key in $config.keySet())
163 $configObj.set($key, $config.get($key))
164 #end
165 ## Now create the configurable objects.
166 #set($cfgable = $configDoc.newObject('XWiki.ConfigurableClass'))
167 $cfgable.set('displayInSection', 'Invitation')
168 $cfgable.set('configurationClass', $configClassNameInternal)
169 $cfgable.set('configureGlobally', 1)
170 #set($propsToShow = 'subjectLineTemplate|messageBodyTemplate|emailRegex|from_address|allowUsersOfOtherWikis'
171 + '|usersMayPersonalizeMessage|usersMaySendToMultiple|emailClass|emailContainer')
172 $cfgable.set('propertiesToShow', $propsToShow)
173 #set($cfgable = $configDoc.newObject('XWiki.ConfigurableClass'))
174 $cfgable.set('displayInSection', 'Invitation')
175 $cfgable.set('heading', '$services.localization.render(''xe.invitation.configuration.smtpHeading'')')
176 $cfgable.set('configurationClass', $configClassNameInternal)
177 $cfgable.set('configureGlobally', 1)
178 $cfgable.set('propertiesToShow',
179 'smtp_server_password|smtp_server_username|smtp_port|smtp_server|javamail_extra_props')
180 $configDoc.saveAsAuthor()
181 #else
182 ## load the configuration object...
183 #set($configObj = $configDoc.getObject($configClassNameInternal))
184 #foreach($element in $configObj.getProperties())
185 $config.put($element.getName(), $configObj.getProperty($element.getName()).getValue())
186 #end
187 #end
188 #end## define $discard
189 ## Now invoke the defined code...
190 #set($discard = $discard.toString())
191 #end
192 ##
193 #*
194 * Basic unit testing of the macro above.
195 *###
196 #macro(testLoadInvitationConfig)
197 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
198 #if(!$configDoc.isNew())
199 $configDoc.deleteAsAuthor()
200 #end
201 #set($configClass = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.WebHome"))
202 #if($configClass.isNew())
203 #set ($classDocumentLink = $services.rendering.escape("${doc.getSpace()}.WebHome", 'xwiki/2.1'))
204 {{error}}Class document [[$classDocumentLink]] not found. can't run test.{{/error}}
205 #else
206 #set($config = {})
207 #loadInvitationConfig($config, 'HopefullyNonexistantSpace')
208 #if($config.size() < 9)
209 {{error}}Config map too small{{/error}}
210 #end
211 #if($config.get('from_address') != 'no-reply@localhost.localdomain')
212 {{error}}form_address incorrect, expecting "no-reply@localhost.localdomain" got "$config.get('from_address')"{{/error}}
213 #end
214 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
215 #if($configDoc.isNew())
216 {{error}}Config document not created{{/error}}
217 #else
218 #set($configObj = $configDoc.getObject("${doc.getSpace()}.Invitation"))
219 $configObj.set('from_address', 'thisisatest@localhost.localdomain')
220 $configDoc.saveAsAuthor()
221 $config.clear()
222 #loadInvitationConfig($config, 'HopefullyNonexistantSpace')
223 #if($config.get('from_address') != 'thisisatest@localhost.localdomain')
224 {{error}}altering config parameter failed.{{/error}}
225 #end
226 #end
227 #end
228 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
229 #if(!$configDoc.isNew())
230 $configDoc.deleteAsAuthor()
231 #end
232 #end
233 ##
234 #**
235 * Load mail from mail containing document.
236 *
237 * $config (Map<String, String>) will be used to get the name of the email class.
238 *
239 * $emailContainer (Document) the document to get the email from.
240 *
241 * $mail (Map<String, XObject>) will be populated with email message XObjects by their messageID.
242 *###
243 #macro(loadInvitationMail, $config, $emailContainer, $mail)
244 ## If this doesn't already exist, it's created.
245 #if($emailContainer.isNew())
246 #set($emailContainerContent =
247 '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
248 + '[$services.rendering.escape("' + "$config.get('emailContainer')"
249 + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
250 #set($discard = $emailContainer.setContent($emailContainerContent))
251 #set($discard = $emailContainer.setHidden(true))
252 #set($discard = $emailContainer.saveAsAuthor())
253 #end
254 ##
255 ## Load messages into a Map by messageID.
256 #foreach($obj in $emailContainer.getObjects($config.get('emailClass')))
257 #set($discard = $mail.put($obj.getProperty('messageID').getValue(), $obj))
258 #end
259 #end
260 ##
261 #**
262 * Is a guest allowed to accept an invitation?
263 *
264 * $guestActionsDoc (Document) the document which guests will use to register.
265 *###
266 #macro(canGuestAcceptInvitation, $guestActionsDoc)
267 #set($out = 'true')
268 #if(!$xwiki.hasAccessLevel('register', 'XWiki.XWikiGuest', 'XWiki.XWikiPreferences')
269 && !$guestActionsDoc.hasProgrammingRights())
270 ##
271 #set($out = 'false')
272 #end
273 $out##
274 #end
275 ##
276 #**
277 * Get the action taken by the user.
278 * This will interpret actions taken using displayActionConfirmationForm
279 *
280 * $parameterMap (Map<String, String>) the parameter map gotten by calling getParameterMap on the servlet request.
281 *
282 * $actionOutList (List<String>) will be populated with a single value (the action)
283 *###
284 #macro(getUserAction, $parameterMap, $actionOutList)
285 #set($actionInternal = 0)
286 #foreach($param in $parameterMap.keySet())
287 #if($param.indexOf('doAction_') != -1)
288 ## Strip 'doAction_'
289 #set($actionInternal = $param.substring(9))
290 #end
291 #end
292 #if($actionInternal != 0)
293 #set($discard = $actionOutList.add($actionInternal))
294 #end
295 #end
296 ##
297 #*
298 * Display a form allowing a user to confirm doing an action.
299 *
300 * $messageIDs (List<String>) the unique IDs of the invitations to act upon.
301 *
302 * $action (String) the action to do.
303 *
304 * $memoLabel (String) what the memo field should be labeled.
305 *
306 * $confirmLabel (String) what the confirm button should say.
307 *
308 * $additionalParameters (Map<String, String>) these parameters will be xml escaped and placed in hidden input fields.
309 *###
310 #macro(displayActionConfirmationForm, $messageIDs, $action, $memoLabel, $confirmLabel, $additionalParameters)
311 {{html wiki=false clean=false}}
312 <div class="invitation action-confirm">
313 <form action="$doc.getURL()" method="POST">
314 ##
315 #foreach($id in $messageIDs)
316 <input type="hidden" name="messageID" value="$escapetool.xml($id)" />
317 #end
318 <input type="hidden" name="confirm" value="y" />
319 <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" />
320 #if($additionalParameters && $additionalParameters.size() > 0)
321 #foreach($param in $additionalParameters.keySet())
322 <input type="hidden" name="$escapetool.xml($param)" value="$escapetool.xml($additionalParameters.get($param))" />
323 #end
324 #end
325 ##
326 <dl>
327 <dt><label for="memo">$memoLabel</label></dt>
328 <dd><input id='memo' type="text" size="54" name="memo" /></dd>
329 </dl>
330 <div class="bottombuttons">
331 <div class="buttons">
332 <span class="buttonwrapper">
333 <input type="submit" class="button" name="doAction_$escapetool.xml($action)" value="$confirmLabel" />
334 </span>
335 </div>
336 </div>
337 </form>
338 </div>
339 {{/html}}
340 #end
341 ##
342 #*
343 * Set the status of a message and log the memo.
344 *
345 * $message (Xobject) the message to act on.
346 *
347 * $status (String) the status to set the message to.
348 *
349 * $memo (String) what to enter in the log.
350 *###
351 #macro(setMessageStatus, $message, $status, $memo)
352 $message.set('status', $status)##
353 #set($history = $message.getProperty('history').getValue())
354 #set($statusWord = "#messageStatusForCode($status)")
355 ## disallow injection of \n which starts a new line or { which may be used for macros.
356 #set($log = $memo.replaceAll('\n', ' ').replaceAll('\{', '~{'))
357 #set($entry = "|$statusWord|[[$xcontext.getUser()]]|$!log")
358 #if("$!history" != '')
359 $message.set('history', "$!history$util.getNewline()$entry")##
360 #else
361 $message.set('history', $entry)##
362 #end
363 #end
364 ##
365 #*
366 * Get the last memo from the message history.
367 *
368 * $message (Xobject) the message to act on.
369 *###
370 #macro(getLastMemo, $message)
371 #set($history = "$!message.getProperty('history').getValue()")
372 #set($indexAfterLastNewline = $mathtool.add($history.lastIndexOf($util.getNewline()), 1))
373 #if($indexAfterLastNewline < $history.length())
374 #set($entry = "$!history.substring($indexAfterLastNewline)")
375 #set($indexAfterLastPipe = $mathtool.add($entry.lastIndexOf('|'), 1))
376 #if($indexAfterLastPipe < $entry.length())
377 $entry.substring($indexAfterLastPipe)##
378 #end
379 #end
380 #end
381 ##
382 #*
383 * Get the status of the current message for it's code.
384 * unsent - not sent yet.
385 * pending - sent and awating a response
386 * accepted - sent and accepted by recipient
387 * declined - sent and declined by recipient
388 * canceled - sent then canceled by sender
389 * reported - as spam (by recipient)
390 * notSpam - reported as spam and investigated (by admin)
391 * sendingFailed - failed to send message
392 * else - unknown status
393 *
394 * $status (String) the status of the message.
395 *###
396 #macro(messageStatusForCode, $status)
397 #if($status == 'unsent')
398 $services.localization.render('xe.invitation.messageStatus.unsent')##
399 #elseif($status == 'pending')
400 $services.localization.render('xe.invitation.messageStatus.pending')##
401 #elseif($status == 'accepted')
402 $services.localization.render('xe.invitation.messageStatus.accepted')##
403 #elseif($status == 'declined')
404 $services.localization.render('xe.invitation.messageStatus.declined')##
405 #elseif($status == 'canceled')
406 $services.localization.render('xe.invitation.messageStatus.canceled')##
407 #elseif($status == 'reported')
408 $services.localization.render('xe.invitation.messageStatus.reported')##
409 #elseif($status == 'notSpam')
410 $services.localization.render('xe.invitation.messageStatus.investigated')##
411 #elseif($status == 'sendingFailed')
412 $services.localization.render('xe.invitation.messageStatus.sendingFailed')##
413 #else
414 $services.localization.render('xe.invitation.messageStatus.unknown', [$escapetool.xml($status)])##
415 #end
416 #end
417 {{/velocity}}