Wiki-Quellcode von User Directory Macros
Zuletzt geändert von admin am 2023/07/25 15:00
Zeige letzte Bearbeiter
| author | version | line-number | content |
|---|---|---|---|
| 1 | {{velocity output='false'}} | ||
| 2 | ## Users class | ||
| 3 | #set ($xwikiUsersClassReference = $services.model.createDocumentReference($xcontext.database, 'XWiki', 'XWikiUsers')) | ||
| 4 | #set ($xwikiUsersClass = $xwiki.getDocument($xwikiUsersClassReference).xWikiClass) | ||
| 5 | ## Configuration class | ||
| 6 | #set ($directoryPreferencesClassReference = $services.model.createDocumentReference($xcontext.database, 'XWiki', 'UserDirectoryPreferencesClass')) | ||
| 7 | #set ($directoryPreferencesClassName = $services.model.serialize($directoryPreferencesClassReference)) | ||
| 8 | ## Default Configuration | ||
| 9 | #set ($defaultConfigurationDocReference = $services.model.createDocumentReference($xcontext.database, 'XWiki', 'UserDirectoryConfiguration')) | ||
| 10 | #set ($defaultConfigurationDoc = $xwiki.getDocument($defaultConfigurationDocReference)) | ||
| 11 | #set ($defaultConfiguration = $defaultConfigurationDoc.getObject($directoryPreferencesClassName)) | ||
| 12 | |||
| 13 | ## We use an ordered set to collect the live table columns because we want to avoid duplicates (they break the live | ||
| 14 | ## table filtering query) and at the same time we want to preserve the column order. | ||
| 15 | #set ($columns = $collectiontool.orderedSet) | ||
| 16 | ## Add the fixed columns that we want the user directory to always show. | ||
| 17 | #set ($discard = $columns.addAll(['_avatar', 'doc.name'])) | ||
| 18 | |||
| 19 | ## Default configuration | ||
| 20 | ## The columns that the user directory will default to when no user preferences exist or when the user resets to default. | ||
| 21 | ## These defaults can be configured by the wiki's admins. | ||
| 22 | #set ($isGlobalUserDirectory = $doc.fullName != 'Main.UserDirectory') | ||
| 23 | #if ($isGlobalUserDirectory) | ||
| 24 | ## Fallback defaults. | ||
| 25 | #set ($defaultColumnsString = 'first_name last_name') | ||
| 26 | #else | ||
| 27 | ## Admin configured defaults. | ||
| 28 | #set ($defaultColumnsString = "$!defaultConfiguration.getValue('columns').trim()") | ||
| 29 | #end | ||
| 30 | #set ($defaultColumns = $defaultColumnsString.split('\s+')) | ||
| 31 | |||
| 32 | ## Current Configuration | ||
| 33 | #if ($isGlobalUserDirectory || $isGuest || $isSuperAdmin) | ||
| 34 | ## Use the default configuration when editing the default configuration itself or | ||
| 35 | ## when the current user doesn't have a profile document, so no preferences. | ||
| 36 | #set ($configurationDoc = $defaultConfigurationDoc) | ||
| 37 | #else | ||
| 38 | ## Use the current user's configuration | ||
| 39 | #set ($configurationDoc = $xwiki.getDocument($xcontext.userReference)) | ||
| 40 | #end | ||
| 41 | ## Get or create the current configuration object, taking into account the values from the request (which is needed for | ||
| 42 | ## the live preview). | ||
| 43 | #set ($configuration = $configurationDoc.updateObjectFromRequest($directoryPreferencesClassName)) | ||
| 44 | |||
| 45 | ## Read the configuration and initialize with defaults if necessary. | ||
| 46 | #set ($columnsString = $configuration.getValue('columns').trim()) | ||
| 47 | #if ($columnsString == $NULL) | ||
| 48 | #set ($columnsString = $defaultColumnsString) | ||
| 49 | #set ($discard = $configuration.set('columns', $columnsString)) | ||
| 50 | #end | ||
| 51 | |||
| 52 | ## Check if they are the default preferences. | ||
| 53 | #set ($isCustomized = false) | ||
| 54 | #if ($columnsString != $defaultColumnsString) | ||
| 55 | ## Mark it as a customized user directory. | ||
| 56 | #set ($isCustomized = true) | ||
| 57 | #end | ||
| 58 | |||
| 59 | ## Build the list of columns to display. | ||
| 60 | #foreach ($column in $columnsString.split('\s+')) | ||
| 61 | ## Skip invalid columns. | ||
| 62 | #if ($column.trim() != '' && $xwikiUsersClass.get($column)) | ||
| 63 | #set ($discard = $columns.add($column)) | ||
| 64 | #end | ||
| 65 | #end | ||
| 66 | |||
| 67 | ## | ||
| 68 | ## Build and display the resulting livetable, nothing else. | ||
| 69 | ## | ||
| 70 | #macro (displayUserDirectoryLiveTable) | ||
| 71 | {{html clean="false"}} | ||
| 72 | #set ($columnsProperties = {}) | ||
| 73 | #foreach ($column in $columns) | ||
| 74 | #set ($columnProperties = { | ||
| 75 | 'type': 'text', | ||
| 76 | 'html': false, | ||
| 77 | 'sortable': true, | ||
| 78 | 'filterable': true, | ||
| 79 | 'displayName': $xwikiUsersClass.get($column).translatedPrettyName | ||
| 80 | }) | ||
| 81 | #set ($classPropertyType = $xwikiUsersClass.get($column).classType) | ||
| 82 | #if ($column == '_avatar') | ||
| 83 | #set ($discard = $columnProperties.putAll({ | ||
| 84 | 'html': true, | ||
| 85 | 'sortable': false, | ||
| 86 | 'filterable': false, | ||
| 87 | 'link': 'view' | ||
| 88 | })) | ||
| 89 | #elseif ($column == 'doc.name') | ||
| 90 | #set ($columnProperties.link = 'view') | ||
| 91 | #elseif ($classPropertyType.endsWith('List')) | ||
| 92 | #set ($columnProperties.type = 'list') | ||
| 93 | #elseif ($classPropertyType.endsWith('Number')) | ||
| 94 | #set ($columnProperties.type = 'number') | ||
| 95 | #elseif ($classPropertyType.endsWith('Password')) | ||
| 96 | #set ($discard = $columnProperties.putAll({ | ||
| 97 | 'sortable': false, | ||
| 98 | 'filterable': false | ||
| 99 | })) | ||
| 100 | #elseif ($classPropertyType.endsWith('TextArea') || $classPropertyType.endsWith('Email') || $classPropertyType.endsWith('Groups')) | ||
| 101 | #set ($columnProperties.html = true) | ||
| 102 | #end | ||
| 103 | #set ($discard = $columnsProperties.put($column, $columnProperties)) | ||
| 104 | #end | ||
| 105 | ## | ||
| 106 | ## Allow other applications to provide a different data source for the user directory livetable. For example, some application might define a different membership relation. | ||
| 107 | #set ($userDirectoryLivetableResultsReference = $services.model.createDocumentReference($xcontext.database, 'XWiki', 'UserDirectoryLivetableResultsOverride')) | ||
| 108 | #if (!$xwiki.exists($userDirectoryLivetableResultsReference)) | ||
| 109 | ## If no override is present, use the default data source. | ||
| 110 | #set ($userDirectoryLivetableResultsReference = $services.model.createDocumentReference($xcontext.database, 'XWiki', 'UserDirectoryLivetableResults')) | ||
| 111 | #end | ||
| 112 | ## Note that we specify the class name even though we use a custom results page (which hard-codes it) because the class | ||
| 113 | ## name is needed by the live table filters, to have a proper drop down list for Static List fields for instance | ||
| 114 | ## (see XWIKI-9660). | ||
| 115 | #set ($options = { | ||
| 116 | 'className': $services.model.serialize($xwikiUsersClassReference, 'local'), | ||
| 117 | 'resultPage' : "$services.model.serialize($userDirectoryLivetableResultsReference)", | ||
| 118 | 'translationPrefix' : 'xe.userdirectory.', | ||
| 119 | 'tagCloud' : true, | ||
| 120 | 'rowCount': 10, | ||
| 121 | 'outputOnlyHtml': true | ||
| 122 | }) | ||
| 123 | ## Add a filter for subwikis | ||
| 124 | #if ($xcontext.database != $xcontext.mainWikiName && "$!services.wiki" != '' && "$!services.wiki.user" != '') | ||
| 125 | #set ($userScope = $services.wiki.user.getUserScope($services.wiki.currentWikiId)) | ||
| 126 | #if ($userScope == 'GLOBAL_ONLY') | ||
| 127 | #set ($discard = $options.put('extraParams', 'userScope=global')) | ||
| 128 | #else | ||
| 129 | #set ($discard = $options.put('extraParams', 'userScope=local')) | ||
| 130 | #end | ||
| 131 | #if ($userScope == 'LOCAL_AND_GLOBAL') | ||
| 132 | <form class='xform third' action=''> | ||
| 133 | <dl> | ||
| 134 | <dt> | ||
| 135 | <label for='userScopeFilter'>$services.localization.render('userdirectory.userScopeFilter')</label> | ||
| 136 | <span class='xHint'>$services.localization.render('userdirectory.userScopeFilter.hint')</span> | ||
| 137 | </dt> | ||
| 138 | <dd> | ||
| 139 | <select name='userScope' id='userScopeFilter'> | ||
| 140 | <option value='local'>$services.localization.render('userdirectory.userScopeFilter.local')</option> | ||
| 141 | <option value='global'>$services.localization.render('userdirectory.userScopeFilter.global')</option> | ||
| 142 | </select> | ||
| 143 | </dd> | ||
| 144 | </dl> | ||
| 145 | </form> | ||
| 146 | #end | ||
| 147 | #end | ||
| 148 | ## We can't filter the values of the 'disabled' user profile property directly from the 'extraParams' live table | ||
| 149 | ## results option because we can't express 'not equal' (we need to say: include only the user profiles for which the | ||
| 150 | ## value of the 'disabled' property is not equal to 1). An user profile that doesn't have any value set for the | ||
| 151 | ## 'disabled' property is enabled. | ||
| 152 | ## We don't hide the disabled user profiles when the active and disabled columns are present because the user can use | ||
| 153 | ## the live table filters to achieve this. | ||
| 154 | #set ($hideDisabledProfilesValue = $configuration.getValue('hideDisabledProfiles')) | ||
| 155 | #if (!$columns.contains('active') | ||
| 156 | && ($hideDisabledProfilesValue == 1 || ("$!hideDisabledProfilesValue" == '' && | ||
| 157 | $configuration.xWikiClass.get('hideDisabledProfiles').getValue('defaultValue') == 1))) | ||
| 158 | #set ($options.extraParams = "$!options.extraParams&hideDisabledProfiles=true") | ||
| 159 | #end | ||
| 160 | ## We need to know which users are disabled or inactive in order to display them differently. | ||
| 161 | #set ($discard = $columns.add('active')) | ||
| 162 | #set ($discard = $columnsProperties.putIfAbsent('active', {'type': 'hidden'})) | ||
| 163 | ## Display the computed livetable. | ||
| 164 | #livetable('userdirectory' $columns $columnsProperties $options) | ||
| 165 | {{/html}} | ||
| 166 | #end | ||
| 167 | |||
| 168 | ## xredirect value used to come back to the current URL when performing actions | ||
| 169 | #set ($xredirect = $doc.getURL($xcontext.action, $request.queryString)) | ||
| 170 | |||
| 171 | ## | ||
| 172 | ## Displays the customization form and preview. Also handles the form's actions. | ||
| 173 | ## | ||
| 174 | #macro (displayUserDirectoryCustomizationForm) | ||
| 175 | #if (!$configurationDoc.hasAccessLevel('edit')) | ||
| 176 | {{error}}$services.localization.render('platform.userdirectory.customizeNotAllowed'){{/error}} | ||
| 177 | #else | ||
| 178 | #handleUserDirectoryAction() | ||
| 179 | ## | ||
| 180 | ## Customization form | ||
| 181 | ## | ||
| 182 | (% id="HUserDirectoryConfiguration" %) | ||
| 183 | == {{translation key="userdirectory.configuration.title"/}} == | ||
| 184 | {{html clean="false"}} | ||
| 185 | <form class="user-directory-settings xform" action="$configurationDoc.getURL('save')" method="post"> | ||
| 186 | <div class="hidden"> | ||
| 187 | <input type="hidden" name="form_token" value="$escapetool.xml($services.csrf.token)" /> | ||
| 188 | <input type="hidden" name="objectPolicy" value="updateOrCreate" /> | ||
| 189 | <input type="hidden" name="xredirect" value="$escapetool.xml($xredirect)" /> | ||
| 190 | <input type="hidden" name="comment" value="Updated user directory preferences" /> | ||
| 191 | </div> | ||
| 192 | <dl> | ||
| 193 | #displayProperty('columns' $configuration 'edit') | ||
| 194 | #displayProperty('hideDisabledProfiles' $configuration 'edit') | ||
| 195 | </dl> | ||
| 196 | <p> | ||
| 197 | <input class="button" type="submit" name="action_save" | ||
| 198 | value="$escapetool.xml($services.localization.render('xe.userdirectory.customizeSaveButtonLabel'))"/> | ||
| 199 | #set ($resetQueryString = "$!request.queryString&" + $escapetool.url({ | ||
| 200 | 'action': 'reset', | ||
| 201 | 'form_token': $services.csrf.token, | ||
| 202 | 'xredirect': $xredirect | ||
| 203 | })) | ||
| 204 | #set ($resetURL = $doc.getURL($xcontext.action, $resetQueryString)) | ||
| 205 | <a href="$escapetool.xml($resetURL)" class="button secondary"> | ||
| 206 | $escapetool.xml($services.localization.render('xe.userdirectory.customizeResetButtonLabel')) | ||
| 207 | </a> | ||
| 208 | </p> | ||
| 209 | </form> | ||
| 210 | {{/html}} | ||
| 211 | #end | ||
| 212 | #end | ||
| 213 | |||
| 214 | #macro (handleUserDirectoryAction) | ||
| 215 | #if ("$!request.action" != '') | ||
| 216 | #if ($services.csrf.isTokenValid($request.form_token)) | ||
| 217 | #if ($request.action == 'reset') | ||
| 218 | #if ($isGlobalUserDirectory) | ||
| 219 | ## For the global configuration it might be best to keep the object but set default values. | ||
| 220 | #set ($discard = $configuration.set('columns', $defaultColumnsString)) | ||
| 221 | #else | ||
| 222 | ## For user preferences, just remove the object. | ||
| 223 | #set ($discard = $configurationDoc.removeObject($configuration)) | ||
| 224 | #end | ||
| 225 | #set ($discard = $configurationDoc.save('Reset user directory preferences.')) | ||
| 226 | #end | ||
| 227 | ## Redirect using xredirect so that the page can be safely refreshed after an action. | ||
| 228 | #set ($discard = $response.sendRedirect($request.xredirect)) | ||
| 229 | #elseif ($request.getHeader('X-Requested-With') == 'XMLHttpRequest') | ||
| 230 | #set ($discard = $response.sendError(401, 'CSRF token verification failed!')) | ||
| 231 | #else | ||
| 232 | #set ($discard = $response.sendRedirect($services.csrf.resubmissionURL)) | ||
| 233 | #end | ||
| 234 | #stop() | ||
| 235 | #end | ||
| 236 | #end | ||
| 237 | |||
| 238 | #macro (displayProperty $propertyName $object $action) | ||
| 239 | #set ($propertyClass = $object.xWikiClass.get($propertyName)) | ||
| 240 | #set ($isCheckbox = $propertyClass.getValue('displayFormType') == 'checkbox') | ||
| 241 | #set ($fieldDisplay = "#unwrapXPropertyDisplay($object.display($propertyName, $action))") | ||
| 242 | <dt> | ||
| 243 | <label #if ($action == 'edit' && !$isCheckbox) | ||
| 244 | for="$escapetool.xml("${object.xWikiClass.name}_${object.number}_$propertyName")"#end> | ||
| 245 | #if ($isCheckbox) | ||
| 246 | $fieldDisplay | ||
| 247 | #end | ||
| 248 | $escapetool.xml($propertyClass.translatedPrettyName) | ||
| 249 | </label> | ||
| 250 | <span class="xHint"> | ||
| 251 | $!escapetool.xml($propertyClass.hint) | ||
| 252 | </span> | ||
| 253 | </dt> | ||
| 254 | <dd>#if (!$isCheckbox)$fieldDisplay#end</dd> | ||
| 255 | #end | ||
| 256 | |||
| 257 | ## | ||
| 258 | ## Displays the user directory with customization status and customization form for when it is being customized. | ||
| 259 | ## | ||
| 260 | #macro (displayUserDirectoryCustomizationOptions $customize) | ||
| 261 | ## | ||
| 262 | ## Ability to customize the view. | ||
| 263 | ## | ||
| 264 | #if ($customize) | ||
| 265 | #displayUserDirectoryCustomizationForm() | ||
| 266 | #elseif ($isCustomized) | ||
| 267 | {{warning}} | ||
| 268 | $services.localization.render('xe.userdirectory.isCustomizedWarning', [ | ||
| 269 | "$doc.fullName", | ||
| 270 | $escapetool.url({ | ||
| 271 | 'customize': true, | ||
| 272 | 'action': 'reset', | ||
| 273 | 'xredirect': $xredirect, | ||
| 274 | 'form_token': $services.csrf.token | ||
| 275 | }), | ||
| 276 | "$doc.fullName", | ||
| 277 | 'customize=true' | ||
| 278 | ]) | ||
| 279 | {{/warning}} | ||
| 280 | #elseif ($isGuest) | ||
| 281 | {{info}} | ||
| 282 | $services.localization.render('xe.userdirectory.canCustomizeInfoGuest', ["path:$doc.getURL('login')"]) | ||
| 283 | {{/info}} | ||
| 284 | #else | ||
| 285 | {{info}} | ||
| 286 | $services.localization.render('xe.userdirectory.canCustomizeInfo', ["$doc.fullName", 'customize=true']) | ||
| 287 | {{/info}} | ||
| 288 | #end | ||
| 289 | #end | ||
| 290 | |||
| 291 | ## | ||
| 292 | ## Displays the user directory. | ||
| 293 | ## | ||
| 294 | #macro (displayUserDirectory $customize) | ||
| 295 | #set ($discard = $xwiki.jsx.use('XWiki.UserDirectoryMacros')) | ||
| 296 | #displayUserDirectoryCustomizationOptions($customize) | ||
| 297 | |||
| 298 | #if ($customize) | ||
| 299 | (% id="HUserDirectoryCustomizePreview" %) | ||
| 300 | == {{translation key="xe.userdirectory.customizePreviewTitle"/}} == | ||
| 301 | |||
| 302 | #end | ||
| 303 | #displayUserDirectoryLiveTable() | ||
| 304 | #end | ||
| 305 | {{/velocity}} |