Show last authors
1 {{include reference="XWiki.ConfigurableClassMacros" /}}
2
3 {{velocity}}
4 #*
5 * This part takes the configuration from any documents containing XWiki.ConfigurableClass objects and creates a form
6 * for each. To includeForm this document, you may specify:
7 *
8 * $section - String - The section which we are administrating eg: "Registration", "Users", or "Import".
9 * If none is specified then it checks for a request parameter called "section" and uses that,
10 * if no parameter, then this code assumes that it is part of the admin icons sheet and adds icons
11 * for any section which is not in $sections, in that event, this code assumes it is being run
12 * inside of a <ul> block.
13 *
14 * $sections - List<String> - If section is not specified, any sections on this list will not have icons made for them,
15 * the assumption being that the icons are already there. If section is specified then this
16 * is not taken into account and may safely be undefined.
17 *
18 * $currentDoc - String (document.fullName) - The administration document, users who don't have permission to edit
19 * it will not be able to include applications (possibly injecting
20 * arbitrary code.) if none specified then $doc.getFullName() is used.
21 *
22 * $globaladmin - boolean - If set true then we will assume we are administrationg the entire wiki.
23 * If not set then we look for a request parameter called "editor" if that exists and equals
24 * "globaladmin" then $globaladmin is true, if it doesn't exist then we check to see if
25 * $currentDoc.getFullName() equals "XWiki.XWikiPreferences".
26 *###
27 ##
28 ## Form submission depends on this.
29 $xwiki.jsfx.use('js/xwiki/actionbuttons/actionButtons.js', true)
30 ## In case of conflict issue we want to display the diff properly
31 #set ($discard = $xwiki.ssfx.use('uicomponents/viewers/diff.css', true))
32 #set ($discard = $xwiki.jsfx.use('uicomponents/viewers/diff.js'))
33 ##
34 #if(!$section)
35 #set($section = $request.getParameter('section'))
36 #end
37 #if(!$currentDoc)
38 #set($currentDoc = $doc.getFullName())
39 #end
40 ## Get value of $globaladmin if not specified.
41 #if("$!globaladmin" == '')
42 #if($editor != 'globaladmin'
43 && $request.getParameter('editor') != 'globaladmin'
44 && $currentDoc != 'XWiki.XWikiPreferences')
45 ##
46 #set($globaladmin = false)
47 #else
48 #set($globaladmin = true)
49 #end
50 #end
51 #set($currentSpace = $xwiki.getDocument($currentDoc).getSpace())
52 ##
53 ## This application should not run with programming rights because it evaluates code which may not be trustworthy.
54 ## Removing the next line will open a security hole.
55 $doc.dropPermissions()##
56 ##
57 ##------------------------------------------------------------------------------------------------------------
58 ## If $section exists then we are viewing the admin page for a particular section.
59 ## eg: 'Registration', 'Presentation', 'Import' etc.
60 ##------------------------------------------------------------------------------------------------------------
61 ##
62 #if($section && $section != '')
63 ##
64 ## This is for keeping track of whether we have shown the heading yet or not.
65 ## If the heading doesn't need to be shown, but an error occurs in processing, then we show the heading
66 ## so that the user knows what the error relates to.
67 #set($headingShowing = false)
68 ##
69 ## Searches the database for names of apps to be configured
70 #set($outputList = [])
71 #findNamesOfAppsToConfigure($section, $globaladmin, $xwiki.getDocument($currentDoc).getSpace(), $outputList)
72 ##
73 #foreach($appName in $outputList)
74 ##
75 ## Make sure the current user has permission to edit the configurable application.
76 #set($userHasAccessToDocument = $xcontext.hasAccessLevel('edit', $appName))
77 ##
78 ## If the document was not last saved by a user with edit privilege on this page
79 ## then we can't safely display the page but we should warn the viewer.
80 #if($userHasAccessToDocument)
81 ## Get the configurable application
82 #set($app = $xwiki.getDocument($appName))
83 ##
84 #set($documentSavedByAuthorizedUser = false)
85 #checkDocumentSavedByAuthorizedUser($app, $currentDoc, $documentSavedByAuthorizedUser)
86 #end
87 ##
88 ## There is no need to display a heading unless:
89 ## 1. There was already a section before this document.
90 ## 2. This is not the first document in this section.
91 ##
92 ## If we are displaying the heading and there is an error to be shown Javascript will not strip the heading.
93 #if(!$appName.equals($outputList.get(0)) || $sections.contains($section))
94 ## Create a document heading.
95 #showHeading($appName, $headingShowing)
96 #end
97 ##
98 #if(!$userHasAccessToDocument)
99 #showHeading($appName, $headingShowing)
100
101 {{error}}{{translation key="xe.admin.configurable.noPermissionThisApplication"/}}{{/error}}
102
103 #elseif(!$documentSavedByAuthorizedUser)
104 #showHeading($appName, $headingShowing)
105
106 {{error}}{{translation key="xe.admin.configurable.applicationAuthorNoAdmin" parameters="$app.Author"/}}{{/error}}
107
108 ##
109 ##------------------------------------------------------------------------------------------------------------
110 ## If the document is locked and not by the current user and forceEdit is not set true,
111 #elseif($app.getLocked() && $app.getLockingUser() != $xcontext.getUser() && !$request.getParameter('forceEdit'))
112 #set($requestURL = "$request.getRequestURL()")
113 #if($requestURL.indexOf('?') == -1)
114 #set($requestURL = "${requestURL}?$request.queryString")
115 #end
116 #showHeading($appName, $headingShowing)
117
118 {{error}}{{translation key="doclockedby"/}} $app.getLockingUser() [[{{translation key="forcelock"/}}>>${requestURL}&forceEdit=1]]{{/error}}
119
120 #else
121 ## If the document is not already locked, attempt to acquire the lock.
122 #if(!$app.getLocked())
123
124 {{html wiki=true}}
125 <noscript>
126
127 {{warning}}{{translation key="xe.admin.configurable.cannotLockNoJavascript"/}}{{/warning}}
128
129 </noscript>
130 <script type="text/javascript">
131 document.observe("xwiki:dom:loaded", function() {
132 XWiki.DocumentLock && new XWiki.DocumentLock('$escapetool.javascript($app.prefixedFullName)').lock();
133 });
134 </script>
135 {{/html}}
136 #end
137 ##------------------------------------------------------------------------------------------------------------
138 ## Done Locking.
139 ##
140 ## Get all objects of the "ConfigurableClass" from this document.
141 #set($allConfigurableObjs = $app.getObjects($nameOfThisDocument))
142 ## Separate out the objects which are for this section.
143 #set($configurableObjs = [])
144 #foreach($configurableObj in $allConfigurableObjs)
145 #if($app.getValue('displayInSection', $configurableObj) == $section)
146 ## If this is space admin, then don't display global, if global don't display space.
147 #if($globaladmin == ($app.getValue('configureGlobally', $configurableObj) == 1))
148 #set($discard = $configurableObjs.add($configurableObj))
149 #end
150 #end
151 #end
152 #if($configurableObjs.size() == 0)
153 ## Internal error, not translated.
154 #showHeading($appName, $headingShowing)
155
156 {{error}}Internal error: All objects were filtered out for application: $appName.{{/error}}
157
158 #else
159 #set($formAction = $xwiki.getURL($app.getFullName(), 'save'))
160 #set($formId = "${section.toLowerCase()}_${app.getFullName()}")
161 #set($escapedAppName = $escapetool.xml($app.getFullName()))
162 #foreach($configurableObj in $configurableObjs)
163 ## Display the header if one exists.
164 #set($heading = $app.getValue('heading', $configurableObj))
165 #if($heading && $heading != '')
166 == #evaluate($heading) ==
167 #end
168 ##
169 #set($codeToExecute = "$!app.getValue('codeToExecute', $configurableObj)")
170 #if($codeToExecute != '')
171 (%class="codeToExecute"%)(((##
172 #evaluate($codeToExecute)##
173 )))
174 #end
175 ##
176 ## If propertiesToShow is set, then we will only show the properties contained therein.
177 #set($propertiesToShow = $app.getValue('propertiesToShow', $configurableObj))
178 #if(!$propertiesToShow || $propertiesToShow.getClass().getName().indexOf('List') == -1)
179 #set($propertiesToShow = [])
180 #end
181 ##
182 ## If linkPrefix is set, then we will make each property label a link which starts with that prefix.
183 #set($linkPrefix = "$!app.getValue('linkPrefix', $configurableObj)")
184 ##
185 ## If the Configurable object specifies a configuration class, use it,
186 ## otherwise assume custom forms are used instead.
187 #set($configClassName = "$!app.getValue('configurationClass', $configurableObj)")
188 #if($configClassName != '')
189 #set($objClass = $xwiki.getDocument($configClassName).getxWikiClass())
190 #if(!$objClass || $objClass.getClass().getName().indexOf('.Class') == -1)
191 #showHeading($appName, $headingShowing)
192
193 {{error}}{{translation key="xe.admin.configurable.configurationClassNonexistant"/}}{{/error}}
194
195 #else
196 ## Use the first object from the document which is of the configuration class.
197 #set($obj = $app.getObject($objClass.getName()))
198 ##
199 #if(!$obj || $obj.getClass().getName().indexOf('.Object') == -1)
200 #showHeading($appName, $headingShowing)
201
202 {{error}}
203 {{translation key="xe.admin.configurable.noObjectOfConfigurationClassFound" parameters="$objClass.getName(), $app.getFullName()"/}}
204 {{/error}}
205
206 #else
207 ##
208 ## Merge save buttons, remove headings from subsections, and make information links into popups.
209 ## This is not done if there is only a custom defined form.
210 $xwiki.jsx.use($nameOfThisDocument)##
211 ##
212 ## We don't begin the form until we have content for it so that a configurable can specify a
213 ## custom form in codeToExecute and if that configurable object is the first of it's kind in that
214 ## document, the custom form will not be put inside of our form.
215 #if(!$insideForm)
216 ## We are opening a form and fieldset without closing it, thus we cannot clean this html.
217
218 {{html clean=false}}
219 <form id="$formId" method="post" action="$formAction" class="xform">
220 <fieldset>
221 {{/html}}
222 #set($insideForm = true)
223 #end
224
225 {{html}}
226 $formHtml.toString()
227 {{/html}}
228 #end## If object exists
229 #end## If class exists
230 #end## If class name is specified.
231 #end## Foreach configurable object found in this document
232 ## If a form was started then we end it.
233 #if($insideForm)
234
235 ## This is closing an open form which was opened above, we cannot clean this html.
236 {{html clean=false}}
237 ## We add in a redirect field to prevent the user from being carried away when they save
238 ## if they don't have javascript.
239 #set($thisURL = $request.getRequestURL())
240 #if($request.getQueryString() && $request.getQueryString().length() > 0)
241 #set($thisURL = "${thisURL}?$request.getQueryString()")
242 #end
243 <input type="hidden" id="${escapedAppName}_redirect" name="$redirectParameter" value="$escapetool.xml($thisURL)" />
244 <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" />
245 </fieldset>
246 <div class="bottombuttons">
247 <p class="admin-buttons">
248 <span class="buttonwrapper">
249 ## Text to display on the button. If there is a heading then this button should be labeled
250 ## that it is for saving this section. Otherwise it should be a generic "save" button.
251 #if($headingShowing)
252 #set($buttonText = "$services.localization.render('admin.save') $escapedAppName")
253 #else
254 #set($buttonText = "$services.localization.render('admin.save')")
255 #end
256 <input class="button" type="submit" name="action_saveandcontinue" value="$buttonText" />
257 </span>
258 </p>
259 </div> ## bottombuttons
260 </form>
261 #set($insideForm = false)
262 {{/html}}
263 #end
264 #end## If there are configurable objects
265 #end## If document is not locked or forceEdit is enabled
266 #end## Foreach document name in names to configure
267
268 {{html}}
269 <script type="text/javascript">
270 /* <![CDATA[ */
271 ## Alt+Shift+S presses the first saveAndContinue button it finds, not what we want so we will disable edit shortcuts.
272 document.observe('xwiki:dom:loaded', function() {
273 XWiki.actionButtons.EditActions = Object.extend(XWiki.actionButtons.EditActions, {addShortcuts : function() { }});
274 });
275 //]]>
276 </script>
277 {{/html}}##
278 ##
279 #else
280 ##
281 ##------------------------------------------------------------------------------------------------------------
282 ## If section is not set then we are viewing the main administration page.
283 ##------------------------------------------------------------------------------------------------------------
284 ##
285 ## If there is no list called sections then we set sections to an empty list.
286 #if(!$sections || $sections.getClass().getName().indexOf('List') == -1)
287 #set($sections = [])
288 #end
289 ##
290 ## We have to create a list of documents which the current user doesn't have permission to view.
291 ## So we can add an error message to the bottom of the page if there are any.
292 #set($appsUserCannotView = [])
293 ##
294 ## A list of sections (to be added) which the user is not allowed to edit, icons will be displayed with a message
295 #set($sectionsUserCannotEdit = [])
296 ## List of sections to be added, in order by creationDate of oldest contained application.
297 #set($sectionsToAdd = [])
298 ## Map of URL of icon to use by the name of the section to use that icon on.
299 #set($iconBySection = {})
300 ##
301 #set($outputList = [])
302 #findNamesOfAppsToConfigure("", $globaladmin, $currentSpace, $outputList)
303 ##
304 #foreach($appName in $outputList)
305 ##
306 ## Get the configurable application
307 #set($app = $xwiki.getDocument($appName))
308 ##
309 ## If getDocument returns null, then warn the user that they don't have view access to that application.
310 #if(!$app)
311 #set($discard = $appsUserCannotView.add($appName))
312 #end
313 ##
314 #set($configurableObjects = $app.getObjects($nameOfThisDocument))
315 #foreach($configurableObject in $configurableObjects)
316 #set($displayInSection = $app.getValue('displayInSection', $configurableObject))
317 ##
318 ## If there is no section for this configurable or if the section cannot be edited, then check if the
319 ## application can be edited by the current user, if so then we display the icon from the current app and
320 ## don't display any message to tell the user they can't edit that section.
321 #if(!$sections.contains($displayInSection) || $sectionsUserCannotEdit.contains($displayInSection))
322 ##
323 ## If there is no section for this configurable, then we will have to add one.
324 #if(!$sections.contains($displayInSection) && !$sectionsToAdd.contains($displayInSection))
325 #set($discard = $sectionsToAdd.add($displayInSection))
326 #end
327 ##
328 ## If an attachment by the filename iconAttachment exists and is an image
329 #set($attachment = $app.getAttachment("$app.getValue('iconAttachment', $configurableObject)"))
330 #if($attachment && $attachment.isImage())
331 ## Set the icon for this section as the attachment URL.
332 #set($discard = $iconBySection.put($displayInSection, $app.getAttachmentURL($attachment.getFilename())))
333 #end
334 ##
335 ## If the user doesn't have edit access to the application, we want to show a message on the icon
336 #if(!$xcontext.hasAccessLevel("edit", $app.getFullName()))
337 #if(!$sectionsUserCannotEdit.contains($displayInSection))
338 #set($discard = $sectionsUserCannotEdit.add($displayInSection))
339 #end
340 #elseif($sectionsUserCannotEdit.contains($displayInSection))
341 ## If the user didn't have access to the section before but does have access to _this_ app which is
342 ## configured in the section, then the section becomes accessible.
343 #set($discard = $sectionsUserCannotEdit.remove($displayInSection))
344 #end
345 #end## If section doesn't exist or user doesn't have access.
346 #end## Foreach configurable object in this app.
347 #end## Foreach application which is configurable.
348 ##
349 ## Now we go through sectionsToAdd and generate icons for them
350 #set($defaultIcon = $xwiki.getAttachmentURL($nameOfThisDocument, 'DefaultAdminSectionIcon.png'))
351 #if($globaladmin)
352 #set($queryString = "editor=globaladmin&amp;section=")
353 #else
354 #set($queryString = "space=${currentSpace}&amp;section=")
355 #if($request.getParameter('editor'))
356 #set($queryString = "editor=$escapetool.url($request.getParameter('editor'))&amp;$queryString")
357 #end
358 #end
359
360 ## This is an html fragment and thus cannot be cleaned
361 {{html clean=false}}
362 #foreach($sectionToAdd in $sectionsToAdd)
363 #set($icon = $iconBySection.get($sectionToAdd))
364 #if(!$icon)
365 #set($icon = $defaultIcon)
366 #end
367 <li class="$escapetool.xml($sectionToAdd).replaceAll(' ', '_')">
368 #set($hasAccess = !$sectionsUserCannotEdit.contains($sectionToAdd))
369 #if($hasAccess)
370 <a href="$xwiki.getURL($currentDoc, $xcontext.getAction(), "$queryString$escapetool.url($sectionToAdd)")">
371 #else
372 <a title="$services.localization.render('xe.admin.configurable.sectionIconNoAccessTooltip')">
373 #end
374 <span>
375 <img src="$icon" alt="$escapetool.xml($sectionToAdd) icon"/>
376 ## Try to translate the names of the sections, build the key by adding an "admin." in front.
377 ## Not the best way to translate, but very inline with the way the translations are done in XWiki.AdminSheet for individual administration page titles.
378 ## If there is no translation (translated message is equals to key), don't display the message key, but the section name instead.
379 #if($services.localization.get("admin.${sectionToAdd.toLowerCase()}"))
380 #set($sectionDisplayName = $services.localization.render("admin.${sectionToAdd.toLowerCase()}"))
381 #else
382 #set($sectionDisplayName = $sectionToAdd)
383 #end
384 $escapetool.xml($sectionDisplayName)
385 </span>
386 #if(!$hasAccess)
387 <br/><span class="errormessage">$services.localization.render('xe.admin.configurable.sectionIconNoAccess')</span>
388 #end
389 </a>
390 </li>
391 #end
392 {{/html}}
393
394 ## Finally we display an error message if there are any applications which we were unable to view.
395 #if($appsUserCannotView.size() > 0)
396
397 {{error}}$services.localization.render('xe.admin.configurable.noViewAccessSomeApplications', [$appsUserCannotView]){{/error}}
398
399 #end
400 #end## If we should be looking at the main administration page.
401 {{/velocity}}