Wiki source code of Wiki Users
Last modified by superadmin on 2025/05/22 17:45
Hide last authors
| author | version | line-number | content |
|---|---|---|---|
| |
1.1 | 1 | {{velocity output="false"}} |
| 2 | ## Use XWikiAllGroup as the group target. | ||
| 3 | #set($groupDoc = $xwiki.getDocument('XWiki.XWikiAllGroup')) | ||
| 4 | #macro(hasGroupRight $right $hasGroupRight) | ||
| 5 | #set($result = $xwiki.hasAccessLevel($right, $xcontext.user, $groupDoc.fullName)) | ||
| 6 | #set($hasGroupRight = $NULL) | ||
| 7 | #setVariable("$hasGroupRight" $result) | ||
| 8 | #end | ||
| 9 | #hasGroupRight('edit' $hasEditGroupRight) | ||
| 10 | #hasGroupRight('delete' $hasDeleteGroupRight) | ||
| 11 | |||
| 12 | #macro (displayInviteWikiUserForm) | ||
| 13 | <form id='inviteUserForm' class='xform' method='post'> | ||
| 14 | <h2>$services.localization.render('platform.wiki.currentwiki.member.add')</h2> | ||
| 15 | <dl> | ||
| 16 | <dt> | ||
| 17 | <label for='userInput'> | ||
| 18 | $services.localization.render('platform.wiki.currentwiki.invite.username.label') | ||
| 19 | </label> | ||
| 20 | <span class='xHint'> | ||
| 21 | $services.localization.render('platform.wiki.currentwiki.invite.username.hint') | ||
| 22 | </span> | ||
| 23 | </dt> | ||
| 24 | <dd> | ||
| 25 | ## The workspace can accept only global users. | ||
| 26 | #set ($userPickerParams = { | ||
| 27 | 'id': 'userInput', | ||
| 28 | 'name': 'name', | ||
| 29 | 'data-userScope': 'GLOBAL_ONLY' | ||
| 30 | }) | ||
| 31 | #userPicker(true $userPickerParams) | ||
| 32 | </dd> | ||
| 33 | <dt> | ||
| 34 | <label for='message'> | ||
| 35 | $services.localization.render('platform.wiki.currentwiki.invite.message.label') | ||
| 36 | </label> | ||
| 37 | <span class='xHint'> | ||
| 38 | $services.localization.render('platform.wiki.currentwiki.invite.message.hint') | ||
| 39 | </span> | ||
| 40 | </dt> | ||
| 41 | <dd> | ||
| 42 | <textarea name='message'></textarea> | ||
| 43 | </dd> | ||
| 44 | </dl> | ||
| 45 | <p class="buttons"> | ||
| 46 | <span class='buttonwrapper'> | ||
| 47 | <input type="submit" id="addMembers" class="button" | ||
| 48 | value="$services.localization.render('xe.admin.groups.addUser.submit')" /> | ||
| 49 | </span> | ||
| 50 | <span class='buttonwrapper'> | ||
| 51 | <input id='inviteUserButton' type='submit' class='button' name='inviteUser' | ||
| 52 | value="$services.localization.render('platform.wiki.currentwiki.invite.button.label')"/> | ||
| 53 | </span> | ||
| 54 | </p> | ||
| 55 | <div class="hidden"> | ||
| 56 | <input type='hidden' name='form_token' value='$!services.csrf.getToken()' /> | ||
| 57 | <input type='hidden' name='editor' value='globaladmin'/> | ||
| 58 | <input type='hidden' name='section' value='Users'/> | ||
| 59 | </div> | ||
| 60 | </form> | ||
| 61 | #end | ||
| 62 | |||
| 63 | #macro (displayWikiMembers) | ||
| 64 | <div class='xform'> | ||
| 65 | <h2>$services.localization.render('admin.xwiki.members.title')</h2> | ||
| 66 | </div> | ||
| 67 | #set ($columnOptions = { | ||
| 68 | "member" : {'type': 'text', 'html': true}, | ||
| 69 | 'scope': {'filterable': false, 'sortable': false, 'html': true}, | ||
| 70 | "_actions" : { | ||
| 71 | 'actions': ['delete'], | ||
| 72 | 'actionCallbacks': {'delete': 'table.deleteRow(i);'}, | ||
| 73 | 'ajaxActions': {'delete': true}, | ||
| 74 | 'filterable': false | ||
| 75 | } | ||
| 76 | }) | ||
| 77 | #set ($columns = ['member']) | ||
| 78 | #if ($services.wiki.user.userScope != 'LOCAL_ONLY') | ||
| 79 | #set ($discard = $columns.add('scope')) | ||
| 80 | #end | ||
| 81 | #if ($hasDeleteGroupRight) | ||
| 82 | #set ($discard = $columns.add('_actions')) | ||
| 83 | #end | ||
| 84 | <div class="medium-avatars"> | ||
| 85 | #livetable('groupusers', $columns, $columnOptions, { | ||
| 86 | 'url': $groupDoc.getURL('view', 'xpage=getgroupmembers'), | ||
| 87 | 'translationPrefix': 'xe.admin.groups.', | ||
| 88 | 'javascriptName': 'editgrouptable', | ||
| 89 | 'outputOnlyHtml': true | ||
| 90 | }) | ||
| 91 | </div> | ||
| 92 | #end | ||
| 93 | |||
| 94 | #macro (displayWikiCandidateMembers) | ||
| 95 | <div id='candidates' class='xform'> | ||
| 96 | <h2>$services.localization.render('platform.wiki.currentwiki.candidates.label')</h2> | ||
| 97 | #set ($groupDoc = $xwiki.getDocument('XWiki.XWikiAllGroup')) | ||
| 98 | #set ($candidateMembers = $groupDoc.getObjects($candidateClass)) | ||
| 99 | #if ($candidateMembers.isEmpty()) | ||
| 100 | <p>$services.localization.render('platform.wiki.currentwiki.candidates.empty')</p> | ||
| 101 | #else | ||
| 102 | <div class='xHint'>$services.localization.render('platform.wiki.currentwiki.candidates.hint')</div> | ||
| 103 | #foreach ($candidateMember in $candidateMembers) | ||
| 104 | #displayWikiCandidateMember($candidateMember) | ||
| 105 | #end | ||
| 106 | #end | ||
| 107 | </div> | ||
| 108 | #end | ||
| 109 | |||
| 110 | #macro (displayWikiCandidateMember $candidateMember) | ||
| 111 | #set ($userFullName = $candidateMember.getValue('userName')) | ||
| 112 | #set ($userURL = $xwiki.getURL($userFullName)) | ||
| 113 | #set ($userComment = $candidateMember.getValue('userComment')) | ||
| 114 | #set ($status = $candidateMember.getValue('status')) | ||
| 115 | #set ($type = $candidateMember.getValue('type')) | ||
| 116 | <div class='candidate'> | ||
| 117 | <div class='candidateAvatar'><a href="$userURL">#mediumUserAvatar($userFullName)</a></div> | ||
| 118 | <div class='candidateDetails'> | ||
| 119 | <form class='xformInline' method='post'> | ||
| 120 | <div class='candidateNameAndComment'> | ||
| 121 | $xwiki.getUserName($userFullName)#if("$!userComment" != ''): <span class='candidateCommentSpan'>$userComment</span>#end | ||
| 122 | </div> | ||
| 123 | <div class='date xHint'> | ||
| 124 | #if ($candidateMember.getValue('date')) | ||
| 125 | $candidateMember.date | ||
| 126 | #end | ||
| 127 | </div> | ||
| 128 | <div class='candidateStatus'> | ||
| 129 | <label>$services.localization.render('platform.wiki.currentwiki.candidates.status.label')</label> $status | ||
| 130 | </div> | ||
| 131 | <div class='candidateType'> | ||
| 132 | <label>$services.localization.render('platform.wiki.currentwiki.candidates.type.label')</label> $type | ||
| 133 | </div> | ||
| 134 | #if ($status != 'pending' || $type == 'invitation') | ||
| 135 | <div class='reviewer'> | ||
| 136 | <label>$services.localization.render('platform.wiki.currentwiki.candidates.reviewer.label')</label> | ||
| 137 | $xwiki.getUserName($candidateMember.getValue('reviewer')) | ||
| 138 | </div> | ||
| 139 | #end | ||
| 140 | <div class='reviewerComment'> | ||
| 141 | <label> | ||
| 142 | $services.localization.render('platform.wiki.currentwiki.candidates.reviewermessage.label') | ||
| 143 | </label> | ||
| 144 | #if($status == 'pending' && $type == 'request') | ||
| 145 | <textarea name='reviewerComment'></textarea> | ||
| 146 | #else | ||
| 147 | <span class='reviewerCommentSpan'>$!candidateMember.getValue('reviewerComment')</span> | ||
| 148 | #end | ||
| 149 | </div> | ||
| 150 | <div class='reviewerPrivateComment'> | ||
| 151 | <label>$services.localization.render('platform.wiki.currentwiki.candidates.reviewerprivatecomment.label')</label> | ||
| 152 | #if($status == 'pending' && $type == 'request') | ||
| 153 | <textarea name='reviewerPrivateComment'></textarea> | ||
| 154 | #else | ||
| 155 | <span class='reviewerPrivateCommentSpan'>$!candidateMember.getValue('reviewerPrivateComment')</span> | ||
| 156 | #end | ||
| 157 | </div> | ||
| 158 | <div class='date xHint'> | ||
| 159 | #if ($candidateMember.getValue('resolutionDate')) | ||
| 160 | $candidateMember.resolutionDate | ||
| 161 | #end | ||
| 162 | </div> | ||
| 163 | <div class='reviewerActions'> | ||
| 164 | #if ($status == 'pending' && $type == 'request') | ||
| 165 | <span class='buttonwrapper acceptUserButton'> | ||
| 166 | <input type='submit' class='button' name='acceptUser' | ||
| 167 | value="$services.localization.render('platform.wiki.currentwiki.candidates.accept.label')"/> | ||
| 168 | </span> | ||
| 169 | </span class='buttonwrapper rejectUserButton'> | ||
| 170 | <input type='submit' class='button secondary' name='rejectUser' | ||
| 171 | value="$services.localization.render('platform.wiki.currentwiki.candidates.reject.label')"/> | ||
| 172 | </span> | ||
| 173 | #end | ||
| 174 | #if ($status == 'pending' && $type == 'invitation') | ||
| 175 | </span class='buttonwrapper cancelInvitationButton'> | ||
| 176 | <input type='submit' class='button' name='cancelInvitation' | ||
| 177 | value="$services.localization.render('platform.wiki.currentwiki.candidates.invitation.cancel.label')"/> | ||
| 178 | </span> | ||
| 179 | #end | ||
| 180 | </div> | ||
| 181 | <input type='hidden' name='candidateNumber' value='$candidateMember.number'/> | ||
| 182 | <input type='hidden' name='editor' value='globaladmin'/> | ||
| 183 | <input type='hidden' name='section' value='Users'/> | ||
| 184 | <input type='hidden' name='form_token' value='$!services.csrf.token' /> | ||
| 185 | </form> | ||
| 186 | </div> | ||
| 187 | <div class='clearfloats'></div> | ||
| 188 | </div> | ||
| 189 | #end | ||
| 190 | |||
| 191 | #macro (printException $exception) | ||
| 192 | |||
| 193 | #if($exception.message) | ||
| 194 | {{error}}$services.localization.render('platform.wiki.error.exceptionWithMessage', [$exception.message]){{/error}} | ||
| 195 | #else | ||
| 196 | {{error}}$exception.class{{/error}} | ||
| 197 | #end | ||
| 198 | |||
| 199 | #end | ||
| 200 | {{/velocity}} | ||
| 201 | |||
| 202 | {{velocity}} | ||
| 203 | ### MANAGE CANDIDACIES ### | ||
| 204 | #set ($candidateClass = 'WikiManager.WikiCandidateMemberClass') | ||
| 205 | #set ($xwikiGroupsClass = 'XWiki.XWikiGroups') | ||
| 206 | #set ($wiki = $services.wiki.getById($services.wiki.currentWikiId)) | ||
| 207 | #set ($wikiPrettyName = $wiki.prettyName) | ||
| 208 | #if ("$!wikiPrettyName" == '') | ||
| 209 | #set ($wikiPrettyName = $wiki.id) | ||
| 210 | #end | ||
| 211 | ## OPERATIONS | ||
| 212 | #if(($request.acceptUser || $request.rejectUser || $request.inviteUser || $request.cancelInvitation) && $hasAdmin) | ||
| 213 | ## Operation are enabled if the form_token is valid | ||
| 214 | #if ($services.csrf.isTokenValid($request.form_token)) | ||
| 215 | #if ($request.acceptUser || $request.rejectUser) | ||
| 216 | ## Handle a candidate members's request. | ||
| 217 | ## | ||
| 218 | #set ($candidateNumber = $numbertool.toNumber("$!{request.candidateNumber}").intValue()) | ||
| 219 | #set ($candidacy = $services.wiki.user.getCandidacy($wiki.id, $candidateNumber)) | ||
| 220 | #if ($candidacy && $candidacy.status == 'PENDING') | ||
| 221 | #if ($request.acceptUser) | ||
| 222 | #set ($success = $services.wiki.user.acceptRequest($candidacy, $request.reviewerComment, $request.reviewerPrivateComment)) | ||
| 223 | #elseif ($request.rejectUser) | ||
| 224 | #set ($success = $services.wiki.user.refuseRequest($candidacy, $request.reviewerComment, $request.reviewerPrivateComment)) | ||
| 225 | #end | ||
| 226 | #if ($success) | ||
| 227 | #if ($request.acceptUser) | ||
| 228 | {{info}}{{translation key="platform.wiki.currentwiki.candidateAcceptedSuccess"/}}{{/info}} | ||
| 229 | #else | ||
| 230 | {{info}}{{translation key="platform.wiki.currentwiki.candidateRejectedSuccess"/}}{{/info}} | ||
| 231 | #end | ||
| 232 | |||
| 233 | #else | ||
| 234 | |||
| 235 | {{error}}{{translation key="platform.wiki.currentwiki.candidateReviewFailure"/}}{{/error}} | ||
| 236 | |||
| 237 | #end | ||
| 238 | #end | ||
| 239 | #elseif($request.inviteUser) | ||
| 240 | ## Handle inviting users. | ||
| 241 | ## | ||
| 242 | #set ($names = []) | ||
| 243 | #set ($namesArray = $request.getParameterValues('name')) | ||
| 244 | #set ($discard = $names.addAll($namesArray.subList(0, $namesArray.size()))) | ||
| 245 | #set ($discard = $names.removeAll([''])) | ||
| 246 | #set ($message = $request.message) | ||
| 247 | ## | ||
| 248 | ## Remove users that are already members. | ||
| 249 | #set ($alreadyMembers = []) | ||
| 250 | #set ($members = $services.wiki.user.getMembers($wiki.id)) | ||
| 251 | #foreach ($name in $names) | ||
| 252 | #if ($members.contains($name)) | ||
| 253 | #set ($discard = $alreadyMembers.add($name)) | ||
| 254 | |||
| 255 | {{error}}$services.localization.render('platform.wiki.currentwiki.inviteUserAlreadyMember', [$xwiki.getUserName($name, false)]){{/error}} | ||
| 256 | |||
| 257 | #end | ||
| 258 | #end | ||
| 259 | #set ($discard = $names.removeAll($alreadyMembers)) | ||
| 260 | ## | ||
| 261 | ## Remove users that have already been invited. | ||
| 262 | #set ($alreadyInvited = []) | ||
| 263 | #set ($allInvitations = $services.wiki.user.getAllInvitations($wiki.id)) | ||
| 264 | #foreach ($name in $names) | ||
| 265 | #foreach ($candidateMember in $allInvitations) | ||
| 266 | #if ($name == $candidateMember.userId && $candidateMember.status == 'PENDING') | ||
| 267 | #set ($errorMessageKey = 'platform.wiki.currentwiki.inviteUserAlreadyInvited') | ||
| 268 | #set ($errorMessageKey = 'platform.wiki.currentwiki.inviteRequestAlreadyExists') | ||
| 269 | |||
| 270 | {{error}}$services.localization.render($errorMessageKey, [$xwiki.getUserName($name, false)]){{/error}} | ||
| 271 | |||
| 272 | #set ($discard = $alreadyInvited.add($name)) | ||
| 273 | #break | ||
| 274 | #end | ||
| 275 | #end | ||
| 276 | #end | ||
| 277 | #set ($discard = $names.removeAll($alreadyInvited)) | ||
| 278 | ## | ||
| 279 | #foreach ($userName in $names) | ||
| 280 | #set ($discard = $services.wiki.user.invite($userName, $wiki.id, $message)) | ||
| 281 | {{info}}$services.localization.render('platform.wiki.currentwiki.inviteSuccess', [$xwiki.getUserName($userName, false)]){{/info}} | ||
| 282 | |||
| 283 | #end | ||
| 284 | #elseif ($request.cancelInvitation) | ||
| 285 | ## | ||
| 286 | ## Handle cancelling an invitation. | ||
| 287 | #set ($candidateNumber = $numbertool.toNumber("$!{request.candidateNumber}").intValue()) | ||
| 288 | #set ($candidateMember = $services.wiki.user.getCandidacy($wiki.id, $candidateNumber)) | ||
| 289 | #if ($candidateMember && $candidateMember.status == 'PENDING') | ||
| 290 | ## Remove the invitation | ||
| 291 | #set ($success = $services.wiki.user.cancelCandidacy($candidateMember)) | ||
| 292 | #if($success) | ||
| 293 | |||
| 294 | {{info}}{{translation key="platform.wiki.currentwiki.invitationCancelSuccess"/}}{{/info}} | ||
| 295 | |||
| 296 | #else | ||
| 297 | |||
| 298 | {{error}}{{translation key="platform.wiki.currentwiki.invitationCancelFailure"/}}{{/error}} | ||
| 299 | |||
| 300 | #end | ||
| 301 | #end | ||
| 302 | #end | ||
| 303 | #else | ||
| 304 | |||
| 305 | {{warning}} | ||
| 306 | {{translation key="platform.wiki.csrf.error" /}} | ||
| 307 | {{/warning}} | ||
| 308 | |||
| 309 | #end | ||
| 310 | #end | ||
| 311 | ### MEMBERSHIP TYPE AND USER SCOPE ### | ||
| 312 | #set($discard = $xwiki.ssx.use('XWiki.XWikiGroupSheet')) | ||
| 313 | #set($discard = $xwiki.jsx.use('WikiManager.WikiUsers')) | ||
| 314 | #set($userConfRef = $services.model.createDocumentReference('', 'WikiManager', 'WikiUserConfiguration')) | ||
| 315 | #set($userConfDoc = $xwiki.getDocument($userConfRef)) | ||
| 316 | #set($userConfObj = $userConfDoc.getObject('WikiManager.WikiUserClass')) | ||
| 317 | #if("$!userConfDoc.getValue('membershipType', $userConfObj)" == '') | ||
| 318 | ## set a default value for membershipType | ||
| 319 | #set($discard = $userConfObj.set('membershipType', 'invite')) | ||
| 320 | #end | ||
| 321 | #set($updateWikiUserReference = $services.model.createDocumentReference('', 'WikiManager', 'UpdateWikiUser')) | ||
| 322 | #set($redirectURL = $doc.getExternalURL($xcontext.action, $request.queryString)) | ||
| 323 | {{html clean="false" wiki="true"}} | ||
| 324 | <form id='setUserConfigurationForm' class='xform' action="$xwiki.getURL($updateWikiUserReference)" method='POST'> | ||
| 325 | <input type="hidden" name="form_token" value="$!services.csrf.getToken()" /> | ||
| 326 | <h2>$services.localization.render('admin.xwiki.usersconfiguration.title')</h2> | ||
| 327 | <dl> | ||
| 328 | <dt> | ||
| 329 | <span class='xHint'>{{translation key="platform.wiki.currentwiki.prop.membershipType.hint"/}}</span> | ||
| 330 | </dt> | ||
| 331 | <dd>((($userConfDoc.display('membershipType', 'edit'))))</dd> | ||
| 332 | </dl> | ||
| 333 | <dl> | ||
| 334 | <dt> | ||
| 335 | <span class='xHint'>{{translation key="platform.wiki.create.wizard.userScope.hint"/}}</span> | ||
| 336 | </dt> | ||
| 337 | <dd>((($userConfDoc.display('userScope', 'edit'))))</dd> | ||
| 338 | </dl> | ||
| 339 | <p class="buttons"> | ||
| 340 | <span class='buttonwrapper'> | ||
| 341 | <input type="submit" class="button" value="$services.localization.render('admin.save')"/> | ||
| 342 | </span> | ||
| 343 | </p> | ||
| 344 | {{/html}} | ||
| 345 | |||
| 346 | {{html clean="false"}} | ||
| 347 | <div class="hidden"> | ||
| 348 | #set ($redirectURL = $doc.getExternalURL($xcontext.action, $request.queryString)) | ||
| 349 | <input type='hidden' name='xredirect' value="$redirectURL" /> | ||
| 350 | </div> | ||
| 351 | </form> | ||
| 352 | |||
| 353 | ## CANDIDACIES AND MEMBERS MANAGEMENT UI | ||
| 354 | ## This part is enabled only if we allow glocal users | ||
| 355 | #if ("$!services.wiki.user.userScope" != 'LOCAL_ONLY') | ||
| 356 | #if ($hasEditGroupRight) | ||
| 357 | #set ($discard = $xwiki.ssx.use('WikiManager.WikiUsers')) | ||
| 358 | #displayInviteWikiUserForm | ||
| 359 | #end | ||
| 360 | #displayWikiMembers | ||
| 361 | #displayWikiCandidateMembers | ||
| 362 | #end | ||
| 363 | |||
| 364 | #if ("$!services.wiki.user.userScope" != 'GLOBAL_ONLY') | ||
| 365 | <div class='xform'> | ||
| 366 | <h2>$services.localization.render('admin.xwiki.users.title')</h2> | ||
| 367 | </div> | ||
| 368 | #end | ||
| 369 | {{/html}} | ||
| 370 | {{/velocity}} |