Code source wiki de MacroService

Version 9.1 par Xavier Richard le 30/06/2022 à 07:54

Afficher les derniers auteurs
1 {{include reference="CKEditor.VelocityMacros" /}}
2
3 {{velocity output="false"}}
4 ## ================================================================
5 ## Returned JSON format:
6 ##
7 ## {
8 ## 'options': {
9 ## 'allMacrosExcludedCategories': [
10 ## (translated category name), ...
11 ## ]
12 ## },
13 ## 'list': [
14 ## {
15 ## 'id': (macro id),
16 ## 'name': (translated macro name),
17 ## 'description': (translated macro description),
18 ## 'defaultCategory': (translated macro category)
19 ## },
20 ## ...
21 ## ],
22 ## 'notinstalled': [
23 ## {
24 ## 'id': (macro id),
25 ## 'name': (translated macro name),
26 ## 'description': (translated macro description),
27 ## 'defaultCategory': '_notinstalled',
28 ## 'extensionId': (extension id)
29 ## 'extensionVersion': (extension version)
30 ## 'extensionType': (extension type)
31 ## 'extensionRecommended': (is extension recommended)
32 ## 'extensionName': (extension name)
33 ## 'extensionSummary': (extension summary)
34 ## ]
35 ## },
36 ## ...
37 ## ]
38 ## }
39 ## ================================================================
40 #macro (getMacroList $syntaxId)
41 #set ($syntax = $services.rendering.resolveSyntax($syntaxId))
42 #set ($macroDescriptors = $services.rendering.getMacroDescriptors($syntax))
43 #if (!$macroDescriptors)
44 ## Before XWiki 9.7RC1 we had to use APIs that require programming rights.
45 #set ($macroDescriptors = [])
46 #try()
47 #set ($macroManager = $services.component.getInstance('org.xwiki.rendering.macro.MacroManager'))
48 #foreach ($macroId in $macroManager.getMacroIds($syntax))
49 #set ($macroDescriptor = $macroManager.getMacro($macroId).descriptor)
50 #set ($discard = $macroDescriptors.add($macroDescriptor))
51 #end
52 #end
53 #end
54 #set ($data = {})
55 #set ($allMacrosExcludedCategories = [])
56 #set ($discard = $allMacrosExcludedCategories.add("#maybeTranslate('rendering.macroCategory.Internal' 'Internal')"))
57 #set ($discard = $allMacrosExcludedCategories.add("#maybeTranslate('rendering.macroCategory.Deprecated' 'Deprecated')"))
58 #set ($discard = $data.put('options', { 'allMacrosExcludedCategories' : $allMacrosExcludedCategories }))
59 #set ($macroList = [])
60 #foreach ($macroDescriptor in $macroDescriptors)
61 #set ($macroTranslationKey = "rendering.macro.$macroDescriptor.id")
62 #set ($macroCategoryTranslationKey = "rendering.macroCategory.$macroDescriptor.defaultCategory")
63 #set ($discard = $macroList.add({
64 'id': $macroDescriptor.id,
65 'name': "#maybeTranslate(""${macroTranslationKey}.name"" $macroDescriptor.name)",
66 'description': "#maybeTranslate(""${macroTranslationKey}.description"" $macroDescriptor.description)",
67 'defaultCategory': "#maybeTranslate($macroCategoryTranslationKey $macroDescriptor.defaultCategory)"
68 }))
69 #end
70 #set ($macroList = $resolvedSortTool.sort($macroList, 'name'))
71 #set ($discard = $data.put('list', $macroList))
72 ## Get macros provided by compatible available extensions
73 #set ($macroExtensionsList = [])
74 #set($extensionQuery = $services.extension.index.newQuery("$!request.search"))
75 #set ($discard = $extensionQuery.addFilter('components__org.xwiki.rendering.macro.Macro', '', 'MATCH'))
76 #if ($xcontext.isMainWiki())
77 #set ($discard = $extensionQuery.setCompatible(true, '', "wiki:$xcontext.database"))
78 #else
79 #set ($discard = $extensionQuery.setCompatible(true, "wiki:$xcontext.database"))
80 #end
81 #set ($discard = $extensionQuery.setInstalled(false, '', "wiki:$xcontext.database"))
82 #set ($extensions = $services.extension.index.repository.search($extensionQuery))
83 #set ($macroExtensionCategory = $services.localization.render('ckeditor.plugin.macro.notinstalled'))
84 #if ($extensions.size > 0)
85 #set ($macroExtensionsMap = {})
86 #foreach ($extension in $extensions)
87 ## TODO: move to a proper generic API to check if an extension can be installed by a given user
88 #set ($extensionInstallAllowed = $services.security.authorization.hasAccess('programming', $xcontext.userReference, $NULL)
89 || (($extension.type == 'xar' || $extension.type == 'webjar')
90 && $services.security.authorization.hasAccess('admin', $xcontext.userReference, "wiki:$xcontext.database") && $services.extension.isAllowed($extension, "wiki:$xcontext.database")))
91 #foreach ($extensionComponent in $extension.getComponents())
92 #if ($extensionComponent.roleType == 'org.xwiki.rendering.macro.Macro')
93 #set ($discard = $macroExtensionsList.add({
94 'id' : {
95 'id' : $extensionComponent.roleHint
96 },
97 'name': $extensionComponent.roleHint,
98 'description': $extension.summary,
99 'defaultCategory': '_notinstalled',
100 'extensionId' : $extension.id.id,
101 'extensionVersion' : $extension.id.version.value,
102 'extensionType' : $extension.type,
103 'extensionRecommended': $extension.recommended,
104 'extensionName': $extension.name,
105 'extensionSummary': $extension.summary,
106 'extensionInstallAllowed': $extensionInstallAllowed
107 }))
108 #end
109 #end
110 #end
111 #set ($discard = $data.put('notinstalled', $macroExtensionsList))
112 #end
113 #end
114
115 #macro (maybeGetMacroDescriptor $macroIdAsString)
116 #set ($xmacro = $NULL)
117 #set ($macroDescriptor = $NULL)
118 #set ($macroId = $services.rendering.resolveMacroId($macroIdAsString))
119 #if ($macroId)
120 #set ($macroDescriptor = $services.rendering.getMacroDescriptor($macroId))
121 #if (!$macroDescriptor && $macroId.syntax)
122 ## Try the macro id without the syntax.
123 #set ($macroId = $services.rendering.resolveMacroId($macroId.id))
124 #set ($macroDescriptor = $services.rendering.getMacroDescriptor($macroId))
125 #end
126 #else
127 ## Either the macro id could not be resolved (unlikely) or we are on an older XWiki instance (before 10.10RC1) where
128 ## we had to use APIs that require programming rights.
129 #getMacroWithPR($macroIdAsString)
130 #if ($xmacro)
131 #set ($macroDescriptor = $xmacro.descriptor)
132 #end
133 #end
134 #if ($macroDescriptor)
135 #getMacroDescriptor($macroDescriptor)
136 #if ($xmacro)
137 ## supportsInlineMode was not exposed on the macro descriptor before XWiki 10.10RC1.
138 #set ($data.supportsInlineMode = $xmacro.supportsInlineMode())
139 #end
140 #end
141 #end
142
143 #macro (getMacroWithPR $macroIdAsString)
144 #set ($xmacro = $NULL)
145 #try()
146 #set ($macroIdFactory = $services.component.getInstance('org.xwiki.rendering.macro.MacroIdFactory'))
147 #set ($macroId = $macroIdFactory.createMacroId($macroIdAsString))
148 #set ($macroManager = $services.component.getInstance('org.xwiki.rendering.macro.MacroManager'))
149 #if ($macroManager.exists($macroId))
150 #set ($xmacro = $macroManager.getMacro($macroId))
151 #elseif ($macroId.syntax)
152 ## Try the macro id without the syntax.
153 #set ($macroId = $macroIdFactory.createMacroId($macroId.id))
154 #if ($macroManager.exists($macroId))
155 #set ($xmacro = $macroManager.getMacro($macroId))
156 #end
157 #end
158 #end
159 #end
160
161 #macro (getMacroDescriptor $macroDescriptor)
162 ## Translate the macro name and description.
163 #set ($macroTranslationKey = "rendering.macro.$macroDescriptor.id")
164 #ckeditor_initRequiredSkinExtensions()
165 #set ($data = {
166 'id': $macroDescriptor.id,
167 'name': "#maybeTranslate(""${macroTranslationKey}.name"" $macroDescriptor.name)",
168 'description': "#maybeTranslate(""${macroTranslationKey}.description"" $macroDescriptor.description)",
169 'defaultCategory': $macroDescriptor.defaultCategory,
170 'supportsInlineMode': $macroDescriptor.supportsInlineMode(),
171 'parameterDescriptorMap': {}
172 })
173 #if ($macroDescriptor.contentDescriptor)
174 ## Translate the content label and description.
175 ## Treat the macro content as if it is the last macro parameter.
176 #set ($data.contentDescriptor = {
177 'name': "#maybeTranslate('rendering.macroContent' 'Content')",
178 'description': "#maybeTranslate(""${macroTranslationKey}.content.description""
179 $macroDescriptor.contentDescriptor.description)",
180 'mandatory': $macroDescriptor.contentDescriptor.mandatory,
181 'deprecated': $macroDescriptor.contentDescriptor.deprecated,
182 'advanced': $macroDescriptor.contentDescriptor.advanced,
183 'defaultValue': $macroDescriptor.contentDescriptor.defaultValue,
184 'type': $macroDescriptor.contentDescriptor.type,
185 'editTemplate': '<textarea name="$content" rows="7"></textarea>',
186 'index': $macroDescriptor.parameterDescriptorMap.size()
187 })
188 #fixDescriptorType($data.contentDescriptor)
189 #end
190 #set ($groupDescriptorTree = {})
191 #foreach ($entry in $macroDescriptor.parameterDescriptorMap.entrySet())
192 #set ($parameterDescriptor = $entry.value)
193 ## Translate the parameter name and description.
194 #set ($parameterTranslationKey = "${macroTranslationKey}.parameter.$parameterDescriptor.id")
195 ## Note: The displayHidden parameter is new in XWiki 12.4RC1 so make sure we set 'hidden' to false if it doesn't
196 ## exist
197 #if ("$!parameterDescriptor.displayHidden" != '')
198 #set ($parameterHidden = $parameterDescriptor.displayHidden)
199 #else
200 #set ($parameterHidden = false)
201 #end
202 #set ($translatedParameterDescriptor = {
203 'id': $parameterDescriptor.id,
204 'name': "#maybeTranslate(""${parameterTranslationKey}.name"" $parameterDescriptor.name)",
205 'description': "#maybeTranslate(""${parameterTranslationKey}.description"" $parameterDescriptor.description)",
206 'mandatory': $parameterDescriptor.mandatory,
207 'deprecated': $parameterDescriptor.deprecated,
208 'advanced': $parameterDescriptor.advanced,
209 'defaultValue': $parameterDescriptor.defaultValue,
210 'type': $parameterDescriptor.displayType,
211 'hidden' : $parameterHidden,
212 'index': $foreach.index
213 })
214 #if ("$!translatedParameterDescriptor.type" == '')
215 ## displayType is not available before XWiki 11.0 so we need to fall back on parameterType.
216 #set ($translatedParameterDescriptor.type = $parameterDescriptor.parameterType)
217 #end
218 #set ($translatedParameterDescriptor.caseInsensitive = $translatedParameterDescriptor.type.isEnum())
219 #set ($groupDescriptor = $parameterDescriptor.groupDescriptor)
220 #if ($groupDescriptor)
221 #handleMacroParameterGroup($groupDescriptor $groupDescriptorTree $translatedParameterDescriptor)
222 #end
223 #if ($translatedParameterDescriptor.type.getName() == 'java.lang.String'
224 && ($parameterDescriptor.defaultValue == 'false' || $parameterDescriptor.defaultValue == 'true')
225 && $macroDescriptor.parametersBeanClass.getSimpleName() == 'WikiMacroParameters')
226 #set ($translatedParameterDescriptor.defaultValue = $parameterDescriptor.defaultValue == 'true')
227 #set ($translatedParameterDescriptor.type = $translatedParameterDescriptor.defaultValue.getClass())
228 #end
229 #set ($htmlDisplayerParameters = {'name': $parameterDescriptor.id})
230 #if ($translatedParameterDescriptor.group)
231 #set ($discard = $htmlDisplayerParameters.put('data-property-group',
232 $stringtool.join($translatedParameterDescriptor.group, '/')))
233 #end
234 #set ($translatedParameterDescriptor.editTemplate = $services.display.html.display(
235 $translatedParameterDescriptor.type, $translatedParameterDescriptor.defaultValue, $htmlDisplayerParameters, 'edit'
236 ))
237 #if ("$!translatedParameterDescriptor.editTemplate" == '')
238 #set ($translatedParameterDescriptor.editTemplate = "#getMacroParameterEditTemplate(
239 $translatedParameterDescriptor)")
240 #end
241 #set ($translatedParameterDescriptor.editTemplate = $translatedParameterDescriptor.editTemplate.trim())
242 #fixDescriptorType($translatedParameterDescriptor)
243 ## Make sure the key is lowercase (for XWiki <9.0).
244 ## See XWIKI-13990: Inconsistency between Java-based and Wiki-based rendering macros regarding the parameter
245 ## descriptor map keys
246 #set ($discard = $data.parameterDescriptorMap.put($entry.key.toLowerCase(), $translatedParameterDescriptor))
247 #end
248 #if ($groupDescriptorTree.groups)
249 #set ($data.groupDescriptorTree = $groupDescriptorTree.groups)
250 #end
251 #set ($data.requiredSkinExtensions = "#ckeditor_getRequiredSkinExtensions()")
252 #end
253
254 #macro (fixDescriptorType $descriptor)
255 ## The goal of this code is to obtain a normalized string representation of the type specified in the descriptor.
256 ## See XCOMMONS-1583: Define a stable way to serialize types
257 ##
258 ## The type specified in the descriptor can be any implementation of java.lang.reflect.Type, not necessarily a
259 ## java.lang.Class. We can't use toString() because the return of Class#toString() is different than Class#getName().
260 ## We can't use Type#getTypeName() either because the access to this method is restricted from Velocity. The only
261 ## option for now is to try #getName() first and fall back on #toString() for types that are not instances of
262 ## java.lang.Class.
263 #set ($typeName = $descriptor.type.getName())
264 #if ("$!typeName" == '')
265 ## Probably not a java.lang.Class. Fall back on #toString().
266 #set ($typeName = "$!descriptor.type")
267 #end
268 ## Remove whitespace from the type name in order to have a single string representation.
269 #set ($descriptor.type = $typeName.replaceAll('\s+', ''))
270 #end
271
272 ## Builds the group tree with the following structure:
273 ##
274 ## {
275 ## 'parentGroupId': {
276 ## 'id': 'parentGroupId',
277 ## 'name': 'Parent Group',
278 ## 'feature': 'someFeature',
279 ## 'groups': {
280 ## 'childGroupId': {...},
281 ## ...
282 ## }
283 ## },
284 ## ...
285 ## }
286 #macro (handleMacroParameterGroup $groupDescriptor $groupDescriptorTree $translatedParameterDescriptor)
287 #if ($groupDescriptor.group && $groupDescriptor.group.size() > 0)
288 #set ($translatedParameterDescriptor.group = $groupDescriptor.group)
289 #set ($parentGroup = $groupDescriptorTree)
290 #foreach ($groupId in $groupDescriptor.group)
291 #if (!$parentGroup.groups)
292 #set ($parentGroup.groups = {})
293 #end
294 #set ($childGroup = $parentGroup.groups.get($groupId))
295 #if (!$childGroup)
296 #if ($groupId == $translatedParameterDescriptor.id)
297 #set ($groupName = $translatedParameterDescriptor.name)
298 #else
299 #set ($groupTranslationKey = "${macroTranslationKey}.group.$groupId")
300 #set ($groupName = "#maybeTranslate(""${groupTranslationKey}.name"" $groupId)")
301 #end
302 #set ($childGroup = {
303 'id': $groupId,
304 'name': $groupName
305 })
306 #set ($discard = $parentGroup.groups.put($groupId, $childGroup))
307 #end
308 #set ($parentGroup = $childGroup)
309 #end
310 #if ("$!groupDescriptor.feature" != '')
311 #set ($parentGroup.feature = $groupDescriptor.feature)
312 #end
313 #elseif ($groupDescriptor.feature)
314 ## This group is made of a single parameter. The feature then refers to this parameter.
315 #set ($translatedParameterDescriptor.feature = $groupDescriptor.feature)
316 #end
317 #end
318
319 #macro (getMacroParameterEditTemplate $translatedParameterDescriptor)
320 #if ($translatedParameterDescriptor.type.getName() == 'boolean'
321 || $translatedParameterDescriptor.type.getName() == 'java.lang.Boolean')
322 <input type="checkbox" name="$escapetool.xml($translatedParameterDescriptor.id)" value="true"/>##
323 ## We need to submit something in case the checkbox is not checked.
324 <input type="hidden" name="$escapetool.xml($translatedParameterDescriptor.id)" value="false"/>
325 #elseif ($translatedParameterDescriptor.type.isEnum())
326 #if ($translatedParameterDescriptor.defaultValue)
327 #set ($enumValues = $translatedParameterDescriptor.defaultValue.values())
328 #else
329 ## A parameter of type enum that doesn't have a default value is very unlikely. We attempt to read the list of
330 ## possible values from the enum type in this case, which is currently forbidden, but at least it will generate
331 ## a warning in the logs that will help us investigate the problem.
332 #set ($enumValues = $translatedParameterDescriptor.type.getEnumConstants())
333 #end
334 <select name="$escapetool.xml($translatedParameterDescriptor.id)">##
335 #foreach ($enumValue in $enumValues)
336 #set ($value = $enumValue.name())
337 #set ($label = "#maybeTranslate(""${parameterTranslationKey}.value.$value"" $enumValue)")
338 <option value="$escapetool.xml($value)">$escapetool.xml($label)</option>##
339 #end
340 </select>
341 #else
342 <input type="text" name="$escapetool.xml($translatedParameterDescriptor.id)"/>
343 #end
344 #end
345
346 #macro (maybeTranslate $key $defaultValue)
347 #if ($services.localization.get($key))
348 $services.localization.render($key)##
349 #else
350 $!defaultValue##
351 #end
352 #end
353
354 #macro (installMacroExtension $extensionId, $extensionVersion)
355 #set ($extension = $services.extension.index.repository.resolve("$extensionId/$extensionVersion"))
356 #if ($extension)
357 ## Find where to install it
358 ## 1) Check if a diffferent version is already installed
359 ## 2) Check if it's allowed to install it at current wiki level
360 #set ($rootNamespace = $NULL)
361 #set ($currentWikiNamespace = "wiki:$xcontext.database")
362 #if ($services.extension.installed.getInstalledExtension($extensionId, $rootNamespace))
363 #set ($extensionNamespace = $rootNamespace)
364 #elseif ($services.extension.installed.getInstalledExtension($extensionId, $currentWikiNamespace))
365 #set ($extensionNamespace = $currentWikiNamespace)
366 #else
367 #if ($services.extension.isAllowed($extension, "wiki:$xcontext.database"))
368 #set ($extensionNamespace = $currentWikiNamespace)
369 #else
370 #set ($extensionNamespace = $NULL)
371 #end
372 #end
373 ## Make the install non interractive
374 #set ($installRequest = $services.extension.createInstallRequest($extensionId, $extensionVersion, $extensionNamespace))
375 #set ($discard = $installRequest.setInteractive(false))
376 ## Start the install
377 #set ($job = $services.extension.install($installRequest))
378 ## Wait for the job to finish
379 #set ($discard = $job.join())
380 #if ($job.status.error)
381 ## The install failed
382 $response.sendError(500, $exceptiontool.getRootCauseMessage($job.status.error))
383 #else
384 ## The install succeeded
385 #set ($data = {
386 'extensionId': $extensionId,
387 'extensionVersion': $extensionVersion,
388 'extensionNamespace': $extensionNamespace
389 })
390 #end
391 #else
392 $response.sendError(404, $exceptiontool.getRootCauseMessage($job.status.error))
393 #end
394 #end
395 {{/velocity}}
396
397 {{velocity wiki="false"}}
398 #if ("$!request.action" == 'install')
399 #if ($services.csrf.isTokenValid($request.form_token))
400 #installMacroExtension($request.extensionId, $request.extensionVersion)
401 #else
402 $response.sendError(403)
403 #end
404 #elseif ("$!request.data" != '')
405 #set ($data = $NULL)
406 #if ($request.data == 'list')
407 #getMacroList($request.syntaxId)
408 #elseif ($request.data == 'descriptor')
409 #maybeGetMacroDescriptor($request.macroId)
410 #end
411 #if ($data)
412 #set ($discard = $response.setContentType('application/json'))
413 $jsontool.serialize($data)
414 #else
415 $response.sendError(404)
416 #end
417 #end
418 {{/velocity}}