Wiki source code of InvitationCommon

Version 1.1 by superadmin on 2025/05/22 17:44

Show last authors
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 <span class="errormessage">
85 #if($recips.size() == 1)
86 ## The email address given is invalid and will not be sent to.
87 $escapetool.xml($services.localization.render('xe.invitation.displayMessage.theAddressIsInvalid'))
88 #else
89 #if($invalid.size() > 1)
90 $escapetool.xml($services.localization.render('xe.invitation.displayMessage.someAddressesAreInvalid', [$invalidAddresses.size()]))
91 #else
92 $escapetool.xml($services.localization.render('xe.invitation.displayMessage.anAddressesIsInvalid'))
93 #end
94 #end
95 </span>
96 </p>
97 #end
98 ## Subject:
99 <strong>$escapetool.xml($services.localization.render('xe.invitation.subjectLabel'))</strong>
100 <div id="preview-subjectline-field" class="invitation-preview field">
101 $escapetool.xml($mail.getProperty('subjectLine').getValue())
102 </div>
103 ## Message:
104 <strong>$escapetool.xml($services.localization.render('xe.invitation.contentLabel'))</strong>
105 <div id="preview-messagebody-field" class="invitation-preview field">
106 $mail.getProperty('messageBody').getValue()
107 </div>
108 </div>
109 </div>
110 {{/html}}
111
112 #end
113 ##
114 #*
115 * Load the configuration.
116 * Only works if the script calling this macro has permission to view InvitationConfig
117 * (or create it if it doesn't exist)
118 *
119 * $config (Map<String, String>) will be populated with invitation configuration.
120 *
121 * $configDocName (String) (Optional) will load configuration from this document, if not specified will use
122 * 'InvitationConfig' in the same space as $doc.
123 *
124 * $configClassName (String) (Optional) will load configuration from object of this class, if not specified will use
125 * 'Invitation' in the same space as $doc.
126 *###
127 #macro(loadInvitationConfig, $config, $configDocName, $configClassName)
128 #define($discard)
129 #if("$!configDocName" == '')
130 #set($configDocNameInternal = "${doc.getSpace()}.InvitationConfig")
131 #else
132 #set($configDocNameInternal = $configDocName)
133 #end
134 #if("$!configClassName" == '')
135 #set($configClassNameInternal = "${doc.getSpace()}.WebHome")
136 #else
137 #set($configClassNameInternal = $configClassName)
138 #end
139 ##
140 ## Load some parameters from the configuration.
141 #set($configDoc = $xwiki.getDocumentAsAuthor($configDocNameInternal))
142 ##
143 ## If no configuration document exists, create one and save it.
144 #if($configDoc.isNew())
145 ##
146 ## load the default configuration from this document.
147 #set($thisDocument = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationCommon"))
148 #set($defaultConfigObj = $thisDocument.getObject($configClassNameInternal))
149 #foreach($element in $defaultConfigObj.getProperties())
150 $config.put($element.getName(), $defaultConfigObj.getProperty($element.getName()).getValue())
151 #end
152 ##
153 #set($configDocContent =
154 '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
155 + '[$services.rendering.escape("' + "$!config.get('mainPage')"
156 + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
157 $configDoc.setContent($configDocContent)
158 $configDoc.setParent($configClassNameInternal)
159 #set($configObj = $configDoc.newObject($configClassNameInternal))
160 #foreach($key in $config.keySet())
161 $configObj.set($key, $config.get($key))
162 #end
163 ## Now create the configurable objects.
164 #set($cfgable = $configDoc.newObject('XWiki.ConfigurableClass'))
165 $cfgable.set('displayInSection', 'Invitation')
166 $cfgable.set('configurationClass', $configClassNameInternal)
167 $cfgable.set('configureGlobally', 1)
168 #set($propsToShow = 'subjectLineTemplate|messageBodyTemplate|emailRegex|from_address|allowUsersOfOtherWikis'
169 + '|usersMayPersonalizeMessage|usersMaySendToMultiple|emailClass|emailContainer')
170 $cfgable.set('propertiesToShow', $propsToShow)
171 #set($cfgable = $configDoc.newObject('XWiki.ConfigurableClass'))
172 $cfgable.set('displayInSection', 'Invitation')
173 $cfgable.set('heading', '$services.localization.render(''xe.invitation.configuration.smtpHeading'')')
174 $cfgable.set('configurationClass', $configClassNameInternal)
175 $cfgable.set('configureGlobally', 1)
176 $cfgable.set('propertiesToShow',
177 'smtp_server_password|smtp_server_username|smtp_port|smtp_server|javamail_extra_props')
178 $configDoc.saveAsAuthor()
179 #else
180 ## load the configuration object...
181 #set($configObj = $configDoc.getObject($configClassNameInternal))
182 #foreach($element in $configObj.getProperties())
183 $config.put($element.getName(), $configObj.getProperty($element.getName()).getValue())
184 #end
185 #end
186 #end## define $discard
187 ## Now invoke the defined code...
188 #set($discard = $discard.toString())
189 #end
190 ##
191 #*
192 * Basic unit testing of the macro above.
193 *###
194 #macro(testLoadInvitationConfig)
195 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
196 #if(!$configDoc.isNew())
197 $configDoc.deleteAsAuthor()
198 #end
199 #set($configClass = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.WebHome"))
200 #if($configClass.isNew())
201 #set ($classDocumentLink = $services.rendering.escape("${doc.getSpace()}.WebHome", 'xwiki/2.1'))
202 {{error}}Class document [[$classDocumentLink]] not found. can't run test.{{/error}}
203 #else
204 #set($config = {})
205 #loadInvitationConfig($config, 'HopefullyNonexistantSpace')
206 #if($config.size() < 9)
207 {{error}}Config map too small{{/error}}
208 #end
209 #if($config.get('from_address') != 'no-reply@localhost.localdomain')
210 {{error}}form_address incorrect, expecting "no-reply@localhost.localdomain" got "$config.get('from_address')"{{/error}}
211 #end
212 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
213 #if($configDoc.isNew())
214 {{error}}Config document not created{{/error}}
215 #else
216 #set($configObj = $configDoc.getObject("${doc.getSpace()}.Invitation"))
217 $configObj.set('from_address', 'thisisatest@localhost.localdomain')
218 $configDoc.saveAsAuthor()
219 $config.clear()
220 #loadInvitationConfig($config, 'HopefullyNonexistantSpace')
221 #if($config.get('from_address') != 'thisisatest@localhost.localdomain')
222 {{error}}altering config parameter failed.{{/error}}
223 #end
224 #end
225 #end
226 #set($configDoc = $xwiki.getDocumentAsAuthor("${doc.getSpace()}.InvitationConfig"))
227 #if(!$configDoc.isNew())
228 $configDoc.deleteAsAuthor()
229 #end
230 #end
231 ##
232 #**
233 * Load mail from mail containing document.
234 *
235 * $config (Map<String, String>) will be used to get the name of the email class.
236 *
237 * $emailContainer (Document) the document to get the email from.
238 *
239 * $mail (Map<String, XObject>) will be populated with email message XObjects by their messageID.
240 *###
241 #macro(loadInvitationMail, $config, $emailContainer, $mail)
242 ## If this doesn't already exist, it's created.
243 #if($emailContainer.isNew())
244 #set($emailContainerContent =
245 '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
246 + '[$services.rendering.escape("' + "$config.get('emailContainer')"
247 + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
248 #set($discard = $emailContainer.setContent($emailContainerContent))
249 #set($discard = $emailContainer.setHidden(true))
250 #set($discard = $emailContainer.saveAsAuthor())
251 #end
252 ##
253 ## Load messages into a Map by messageID.
254 #foreach($obj in $emailContainer.getObjects($config.get('emailClass')))
255 #set($discard = $mail.put($obj.getProperty('messageID').getValue(), $obj))
256 #end
257 #end
258 ##
259 #**
260 * Is a guest allowed to accept an invitation?
261 *
262 * $guestActionsDoc (Document) the document which guests will use to register.
263 *###
264 #macro(canGuestAcceptInvitation, $guestActionsDoc)
265 #set($out = 'true')
266 #if(!$xwiki.hasAccessLevel('register', 'XWiki.XWikiGuest', 'XWiki.XWikiPreferences')
267 && !$guestActionsDoc.hasProgrammingRights())
268 ##
269 #set($out = 'false')
270 #end
271 $out##
272 #end
273 ##
274 #**
275 * Get the action taken by the user.
276 * This will interpret actions taken using displayActionConfirmationForm
277 *
278 * $parameterMap (Map<String, String>) the parameter map gotten by calling getParameterMap on the servlet request.
279 *
280 * $actionOutList (List<String>) will be populated with a single value (the action)
281 *###
282 #macro(getUserAction, $parameterMap, $actionOutList)
283 #set($actionInternal = 0)
284 #foreach($param in $parameterMap.keySet())
285 #if($param.indexOf('doAction_') != -1)
286 ## Strip 'doAction_'
287 #set($actionInternal = $param.substring(9))
288 #end
289 #end
290 #if($actionInternal != 0)
291 #set($discard = $actionOutList.add($actionInternal))
292 #end
293 #end
294 ##
295 #*
296 * Display a form allowing a user to confirm doing an action.
297 *
298 * $messageIDs (List<String>) the unique IDs of the invitations to act upon.
299 *
300 * $action (String) the action to do.
301 *
302 * $memoLabel (String) what the memo field should be labeled.
303 *
304 * $confirmLabel (String) what the confirm button should say.
305 *
306 * $additionalParameters (Map<String, String>) these parameters will be xml escaped and placed in hidden input fields.
307 *###
308 #macro(displayActionConfirmationForm, $messageIDs, $action, $memoLabel, $confirmLabel, $additionalParameters)
309 {{html wiki=false clean=false}}
310 <div class="invitation action-confirm">
311 <form action="$doc.getURL()" method="POST">
312 ##
313 #foreach($id in $messageIDs)
314 <input type="hidden" name="messageID" value="$escapetool.xml($id)" />
315 #end
316 <input type="hidden" name="confirm" value="y" />
317 <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" />
318 #if($additionalParameters && $additionalParameters.size() > 0)
319 #foreach($param in $additionalParameters.keySet())
320 <input type="hidden" name="$escapetool.xml($param)" value="$escapetool.xml($additionalParameters.get($param))" />
321 #end
322 #end
323 ##
324 <dl>
325 <dt><label for="memo">$memoLabel</label></dt>
326 <dd><input id='memo' type="text" size="54" name="memo" /></dd>
327 </dl>
328 <div class="bottombuttons">
329 <div class="buttons">
330 <span class="buttonwrapper">
331 <input type="submit" class="button" name="doAction_$escapetool.xml($action)" value="$confirmLabel" />
332 </span>
333 </div>
334 </div>
335 </form>
336 </div>
337 {{/html}}
338 #end
339 ##
340 #*
341 * Set the status of a message and log the memo.
342 *
343 * $message (Xobject) the message to act on.
344 *
345 * $status (String) the status to set the message to.
346 *
347 * $memo (String) what to enter in the log.
348 *###
349 #macro(setMessageStatus, $message, $status, $memo)
350 $message.set('status', $status)##
351 #set($history = $message.getProperty('history').getValue())
352 #set($statusWord = "#messageStatusForCode($status)")
353 ## disallow injection of \n which starts a new line or { which may be used for macros.
354 #set($log = $memo.replaceAll('\n', ' ').replaceAll('\{', '~{'))
355 #set($entry = "|$statusWord|[[$xcontext.getUser()]]|$!log")
356 #if("$!history" != '')
357 $message.set('history', "$!history$util.getNewline()$entry")##
358 #else
359 $message.set('history', $entry)##
360 #end
361 #end
362 ##
363 #*
364 * Get the last memo from the message history.
365 *
366 * $message (Xobject) the message to act on.
367 *###
368 #macro(getLastMemo, $message)
369 #set($history = "$!message.getProperty('history').getValue()")
370 #set($indexAfterLastNewline = $mathtool.add($history.lastIndexOf($util.getNewline()), 1))
371 #if($indexAfterLastNewline < $history.length())
372 #set($entry = "$!history.substring($indexAfterLastNewline)")
373 #set($indexAfterLastPipe = $mathtool.add($entry.lastIndexOf('|'), 1))
374 #if($indexAfterLastPipe < $entry.length())
375 $entry.substring($indexAfterLastPipe)##
376 #end
377 #end
378 #end
379 ##
380 #*
381 * Get the status of the current message for it's code.
382 * unsent - not sent yet.
383 * pending - sent and awating a response
384 * accepted - sent and accepted by recipient
385 * declined - sent and declined by recipient
386 * canceled - sent then canceled by sender
387 * reported - as spam (by recipient)
388 * notSpam - reported as spam and investigated (by admin)
389 * sendingFailed - failed to send message
390 * else - unknown status
391 *
392 * $status (String) the status of the message.
393 *###
394 #macro(messageStatusForCode, $status)
395 #if($status == 'unsent')
396 $services.localization.render('xe.invitation.messageStatus.unsent')##
397 #elseif($status == 'pending')
398 $services.localization.render('xe.invitation.messageStatus.pending')##
399 #elseif($status == 'accepted')
400 $services.localization.render('xe.invitation.messageStatus.accepted')##
401 #elseif($status == 'declined')
402 $services.localization.render('xe.invitation.messageStatus.declined')##
403 #elseif($status == 'canceled')
404 $services.localization.render('xe.invitation.messageStatus.canceled')##
405 #elseif($status == 'reported')
406 $services.localization.render('xe.invitation.messageStatus.reported')##
407 #elseif($status == 'notSpam')
408 $services.localization.render('xe.invitation.messageStatus.investigated')##
409 #elseif($status == 'sendingFailed')
410 $services.localization.render('xe.invitation.messageStatus.sendingFailed')##
411 #else
412 $services.localization.render('xe.invitation.messageStatus.unknown', [$escapetool.xml($status)])##
413 #end
414 #end
415 {{/velocity}}