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