Версия 1.1 от Admin xWiKi на 15.10.2019, 13:19

Последние авторы
1 {{velocity output="false"}}
2 ## Constants:
3 #set($redirectParameter = 'xredirect')
4 #set($nameOfThisDocument = 'XWiki.ConfigurableClass')
5
6
7 #*
8 * Try to determine whether a document was edited by a user who has edit right on this page. This is tricky because
9 * documents are imported with the name XWiki.XWikiGuest who has no access to anything after import.
10 *
11 * @param theDoc - Document who's editor should be checked for edit access on this document.
12 *###
13 #macro(checkDocumentSavedByAuthorizedUser, $docToCheck, $currentDoc, $hasAccess)
14 ## The system is started and the only user is XWikiGuest who has admin right but gives it up when he imports the default
15 ## documents, we are checking to see if this looks like the guest imported the document with the first import.
16 #if($docToCheck.getWiki() == $xcontext.getMainWikiName()
17 && $docToCheck.getVersion() == '1.1'
18 && $docToCheck.getCreator() != $docToCheck.getContentAuthor()
19 && $docToCheck.getContentAuthor() == 'XWiki.XWikiGuest')
20 ##
21 #set($userToCheck = $docToCheck.getCreator())
22 #else
23 #set($userToCheck = $docToCheck.getAuthor())
24 #end
25 #set ($hasAccess = $NULL)
26 #setVariable ("$hasAccess" $xwiki.hasAccessLevel('edit', $userToCheck, $currentDoc))
27 #end
28
29
30 #*
31 * Find names of documents which contain objects of the class 'XWiki.ConfigurableClass'
32 *
33 * @param $section - String - Look for apps which specify that they should be configured in this section,
34 * if null or "" then returns them for all sections.
35 *
36 * @param $globaladmin - boolean - If true then we will look for applications which should be configured globally.
37 *
38 * @param $space - String - If not looking for apps which are configured globally, then this is the space where we
39 * will look for apps in. If null or "" or if $globaladmin is true, then all spaces will be
40 * searched.
41 *
42 * @param $outputList - List - The returns from this macro will be put in this list, passing the list as a parameter
43 * a safety measure because macros can't return values.
44 *###
45 #macro(findNamesOfAppsToConfigure, $section, $globaladmin, $space, $outputList)
46 #set ($fromClause = [
47 'BaseObject as obj',
48 'StringProperty as category',
49 'IntegerProperty as sectionOrder',
50 'IntegerProperty as global'
51 ])
52 #set ($whereClause = [
53 "obj.name = doc.fullName and obj.className = :className",
54 "category.id = obj.id and category.name = 'displayInCategory'",
55 "sectionOrder.id = obj.id and sectionOrder.name = 'sectionOrder'",
56 "global.id = obj.id and global.name = 'configureGlobally' and global.value = :global"
57 ])
58 #set ($params = {'className' : $nameOfThisDocument})
59 ## Order by category and section priority, leaving empty/null category at the end, because we want to read the
60 ## category meta data from the first (most important) section in each category.
61 #set ($orderByClause = [
62 "case when category.value is null or category.value = '' then 1 else 0 end",
63 'category.value',
64 'sectionOrder.value'
65 ])
66 #if ($globaladmin == true)
67 #set ($discard = $params.put('global', 1))
68 #else
69 #set ($discard = $params.put('global', 0))
70 #if ("$!space" != '')
71 #set ($discard = $whereClause.add('doc.space = :space'))
72 #set ($discard = $params.put('space', $space))
73 #end
74 #end
75 #if ("$!section" != '')
76 #set ($discard = $fromClause.add('StringProperty as section'))
77 #set ($discard = $whereClause.add("section.id = obj.id and section.name = 'displayInSection' and section.value = :section"))
78 #set ($discard = $params.put('section', $section))
79 #end
80 #set ($statement = ', ' + $stringtool.join($fromClause, ', ') +
81 ' where ' + $stringtool.join($whereClause, ' and ') +
82 ' order by ' + $stringtool.join($orderByClause, ', '))
83 ## We can't remove duplicates using the unique filter because the select clause will be extended with the information
84 ## needed by the order by clause. Thus we remove the duplicates after we get the results.
85 #set ($orderedSetOfAppNames = $collectionstool.orderedSet)
86 #set ($discard = $orderedSetOfAppNames.addAll($services.query.hql($statement).bindValues($params).execute()))
87 #set ($discard = $outputList.addAll($orderedSetOfAppNames))
88 #end
89
90 #*
91 * Augment the $adminMenu variable with all $nameOfThisDocument (i.e. XWiki.ConfigurableClass) xobjects found on this wiki.
92 *###
93 #macro(findCustomSectionsToConfigure $adminMenu)
94 #set ($outputList = [])
95 #set ($global = ($editor == 'globaladmin'))
96 #findNamesOfAppsToConfigure('', $global, $currentSpace, $outputList)
97 #set ($sectionsByName = {})
98 #set ($categoriesByName = {})
99 #foreach ($category in $adminMenu)
100 #set ($discard = $categoriesByName.put($category.id, $category))
101 #foreach ($section in $category.children)
102 #set ($discard = $sectionsByName.put($section.id, $section))
103 #end
104 #end
105 ##
106 #set ($query = "editor=$escapetool.url(${editor})")
107 #if ($editor != 'globaladmin')
108 #set ($query = $query + "&space=$escapetool.url(${currentSpace})")
109 #end
110 #foreach ($appName in $outputList)
111 ##
112 ## Get the configurable application
113 #set ($app = $xwiki.getDocument($appName))
114 ##
115 ## If getDocument returns null, then warn the user that they don't have view access to that application.
116 #if (!$app)
117 #set ($discard = $appsUserCannotView.add($appName))
118 #end
119 ##
120 #foreach ($configurableObject in $app.getObjects($nameOfThisDocument))
121 #set ($displayInCategory = $app.getValue('displayInCategory', $configurableObject))
122 ## It's OK to not specify a category, in which case the app will be added to a default one (i.e. "other").
123 #if ("$!displayInCategory" != '')
124 #if ($categoriesByName.containsKey($displayInCategory))
125 ## Add a new section in this category.
126 #set ($appCategory = $categoriesByName.get($displayInCategory))
127 #else
128 ## Add a new category.
129 #set ($key = "admin.$displayInCategory.toLowerCase()")
130 #set ($name = $displayInCategory)
131 #if ($services.localization.get($key))
132 #set ($name = $services.localization.render($key))
133 #end
134 #set ($appCategory= {
135 'id': $displayInCategory,
136 'name': $name,
137 'children': []
138 })
139 #set ($discard = $categoriesByName.put($displayInCategory, $appCategory))
140 ## Insert the category at the end for now. We'll sort the categories after we add all of them.
141 #set ($discard = $adminMenu.add($appCategory))
142 #end
143 #set ($categoryIcon = $app.getValue('categoryIcon', $configurableObject))
144 #if ("$!categoryIcon" != '')
145 #set ($appCategory.icon = $categoryIcon)
146 #end
147 #set ($displayBeforeCategory = $app.getValue('displayBeforeCategory', $configurableObject))
148 #if ("$!displayBeforeCategory" != '')
149 #set ($appCategory.displayBeforeCategory = $displayBeforeCategory)
150 #end
151 #else
152 #set ($appCategory = $categoriesByName.get('other'))
153 #end
154 ##
155 #set ($displayInSection = $app.getValue('displayInSection', $configurableObject))
156 ##
157 ## If there is no section specified in the object, just skip it
158 #if ("$!displayInSection" == '')
159 ## Skip, bad object
160 ## If there is no section for this configurable or if the section cannot be edited, then check if the
161 ## application can be edited by the current user, if so then we display the icon from the current app and
162 ## don't display any message to tell the user they can't edit that section.
163 #elseif ($sectionsByName.containsKey($displayInSection))
164 #set ($appSection = $sectionsByName.get($displayInSection))
165 #set ($appSection.configurable = true)
166 #set ($newSection = false)
167 #else
168 ##
169 ## If there is no section for this configurable, then we will have to add one.
170 #set ($key = "admin.$displayInSection.toLowerCase()")
171 #set ($name = $displayInSection)
172 #if ($services.localization.get($key))
173 #set ($name = $services.localization.render($key))
174 #end
175 #set ($appSection = {
176 'id': $displayInSection,
177 'name': $name,
178 'url': $xwiki.getURL($currentDoc, $adminAction, "${query}&section=$escapetool.url($displayInSection)"),
179 'configurable': true,
180 'order': $configurableObject.getValue('sectionOrder')
181 })
182 #if ($app.getValue('configureGlobally', $configurableObject) != 1)
183 #set ($appSection.perSpace = true)
184 #end
185 #set ($key = "admin.${displayInSection.toLowerCase()}.description")
186 #if ($services.localization.get($key))
187 #set ($appSection.description = $services.localization.render($key))
188 #end
189 #set ($discard = $sectionsByName.put($displayInSection, $appSection))
190 #set ($discard = $appCategory.children.add($appSection))
191 #set ($newSection = true)
192 #end
193 ##
194 ## If an attachment by the filename iconAttachment exists and is an image
195 #set ($attachment = $app.getAttachment("$!app.getValue('iconAttachment', $configurableObject)"))
196 #if ($attachment && $attachment.isImage())
197 ## Set the icon for this section as the attachment URL.
198 #set ($appSection.iconReference = "${appName}@$attachment.getFilename()")
199 #elseif (!$appSection.iconReference)
200 #set ($appSection.iconReference = 'XWiki.ConfigurableClass@DefaultAdminSectionIcon.png')
201 #end
202 ##
203 ## If the user doesn't have edit access to the application, we want to show a message on the icon
204 #if (!$xcontext.hasAccessLevel('edit', $app.getFullName()) && $newSection)
205 #set ($appSection.readOnly = true)
206 #elseif ($xcontext.hasAccessLevel('edit', $app.getFullName()) && $appSection.readOnly)
207 #set ($appSection.readOnly = false)
208 #end
209 #end## Foreach configurable object in this app.
210 #end## Foreach application which is configurable.
211 ##
212 ## Sort the categories
213 ##
214 #foreach ($category in $adminMenu)
215 #set ($category.score = 0)
216 #end
217 #foreach ($round in [1..$adminMenu.size()])
218 #set ($scoreChanged = false)
219 #foreach ($category in $adminMenu)
220 #if ($category.displayBeforeCategory)
221 #set ($newScore = $categoriesByName.get($category.displayBeforeCategory).score + 1)
222 #if ($newScore && $newScore > $category.score)
223 #set ($category.score = $newScore)
224 #set ($scoreChanged = true)
225 #end
226 #end
227 #end
228 #if (!$scoreChanged)
229 #break
230 #end
231 #end
232 #set ($adminMenu = $sorttool.sort($adminMenu, 'score:desc'))
233 #end
234
235
236 #*
237 * Show the heading for configuration for a given application.
238 *
239 * $appName (String) Name of the application to show configuration heading for.
240 *
241 * $headingAlreadyShowing (boolean) If true then we don't make another heading. Otherwise it is set to true.
242 *###
243 #macro(showHeading, $appName, $headingAlreadyShowing)
244 #if(!$headingAlreadyShowing)
245 #set($headingAlreadyShowing = true)
246
247 = {{translation key="admin.customize"/}} [[$appName>>$appName]]: =
248 #end
249 #end
250
251 #define($formHtml)
252 #if ($objClass.getPropertyNames().size() > 0)
253 <dl>
254 #foreach($propName in $objClass.getPropertyNames())
255 #if($propertiesToShow.size() > 0 && !$propertiesToShow.contains($propName))
256 ## Silently skip over this property.
257 #else
258 #set($prettyName = "#evaluate($app.displayPrettyName($propName, $obj))")
259 ##
260 #set($hintKey = "${obj.xWikiClass.name}_${propName}.hint")
261 #set($hint = $services.localization.render($hintKey))
262 #if($hint == $hintKey)
263 #set($hint = $NULL)
264 #end
265 ##
266 ## Further processing of the field display HTML is needed.
267 ## Step 1: Strip <pre> tags which $obj.display inserts, this won't affect content because it's escaped.
268 #set($out = $obj.display($propName, 'edit').replaceAll('<[/]?+pre>', ''))
269 ## Step 2: Select only content between first < and last > because $obj.display inserts html macros.
270 ## Careful not to remove html macros from the content because they are not escaped!
271 #set ($out = $out.substring($out.indexOf('<'), $mathtool.add(1, $out.lastIndexOf('>'))))
272 ## Step 3: Prepend app name to all ID and FOR attributes to prevent id collision with multiple apps on one page.
273 #set ($oldId = "$objClass.getName()_$obj.getNumber()_$propName")
274 #set ($newId = "${escapedAppName}_$oldId")
275 #set ($out = $out.replaceAll(" (id|for)=('|"")$regextool.quote($oldId)",
276 " ${escapetool.d}1=${escapetool.d}2$regextool.quoteReplacement($newId)"))
277 ## App Name is prepended to for= to make label work with id which is modified to prevent collisions.
278 <dt><label#if ($out.matches("(?s).*id=['""]${newId}['""].*")) for="${newId}"#end>##
279 #if ($out.indexOf('type=''checkbox''') != -1 && $out.indexOf('class="xwiki-form-listclass"') == -1)
280 $out ##
281 #set ($out = '')
282 #end
283 $escapetool.xml($prettyName)
284 </label>
285 #if($linkPrefix != '')
286 #set($linkScript = "$linkPrefix$propName")
287 <a href="$escapetool.xml("#evaluate($linkScript)")" class="xHelp" title="$services.localization.render('admin.documentation')">$services.localization.render('admin.documentation')</a>
288 #end
289 #if ($hint)
290 <span class="xHint">$hint</span>
291 #end
292 </dt>
293 #if ($out != '')
294 <dd>$out</dd>
295 #end
296 #end## If property is in propertiesToShow
297 #end## Foreach property in this class
298 </dl>
299 #end
300 #end## define $formHtml
301 {{/velocity}}