Wiki-Quellcode von MacroService

Version 2.1 von Daniel Herrmann am 2025/07/19 16:48

Zeige letzte Bearbeiter
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
42 ## Loads the css resources to display the macros list
43 ## TODO: Refactor once we add support for loading css files from javascript without velocity.
44 #if ($xcontext.action == 'get')
45 #template('display_macros.vm')
46 #initRequiredSkinExtensions()
47 #end
48
49 #set ($discard = $xwiki.linkx.use($services.webjars.url('selectize.js', 'css/selectize.bootstrap3.css'),
50 {'type': 'text/css', 'rel': 'stylesheet'}))
51 #set ($discard = $xwiki.ssfx.use('uicomponents/suggest/xwiki.selectize.css', true))
52
53 #if ($xcontext.action == 'get')
54 #getRequiredSkinExtensions($requiredSkinExtensions)
55 #set ($discard = $response.setHeader('X-XWIKI-HTML-HEAD', $requiredSkinExtensions))
56 #end
57
58 #set ($syntax = $services.rendering.resolveSyntax($syntaxId))
59 #set ($macroDescriptors = $services.rendering.getMacroDescriptors($syntax))
60 #set ($data = {})
61 #set ($allMacrosExcludedCategories = [])
62 #set ($discard = $allMacrosExcludedCategories.add("#maybeTranslate('rendering.macroCategory.Internal' 'Internal')"))
63 #set ($discard = $allMacrosExcludedCategories.add("#maybeTranslate('rendering.macroCategory.Deprecated' 'Deprecated')"))
64 #set ($discard = $data.put('options', { 'allMacrosExcludedCategories' : $allMacrosExcludedCategories }))
65 ## If the current user do not want to display hidden documents, we initialize the set of hidden default
66 ## categories.
67 ## TODO: Make the list of hidden by default categories configurable from the administration (XWIKI-19993).
68 #if(!$services.user.getProperties().displayHiddenDocuments())
69 #set ($hiddenCategories = $services.rendering.getHiddenMacroCategories())
70 #else
71 #set ($hiddenCategories = [])
72 #end
73 #set ($macroList = [])
74 #set ($installedMacros = [])
75 #foreach ($macroDescriptor in $macroDescriptors)
76 #set ($discard = $installedMacros.add($macroDescriptor.id.id))
77
78 #set ($macroTranslationKey = "rendering.macro.$macroDescriptor.id")
79 #set ($categories = [])
80 #set ($hidden = false)
81 #foreach ($category in $services.rendering.getMacroCategories($macroDescriptor.id))
82 #set ($macroCategoryTranslationKey = "rendering.macroCategory.$category")
83 #set ($hidden = $hidden || $hiddenCategories.contains($category))
84 #set ($discard = $categories.add({
85 'id': $category,
86 'label': "#maybeTranslate($macroCategoryTranslationKey $category)"
87 }))
88 #end
89
90 #if (!$hidden)
91 #set ($defaultCategoryTranslation = "rendering.macroCategory.${macroDescriptor.defaultCategory}")
92 #set ($discard = $macroList.add({
93 'id': $macroDescriptor.id,
94 'name': "#maybeTranslate(""${macroTranslationKey}.name"" $macroDescriptor.name)",
95 'description': "#maybeTranslate(""${macroTranslationKey}.description"" $macroDescriptor.description)",
96 'defaultCategory': "#maybeTranslate($defaultCategoryTranslation $macroDescriptor.defaultCategory)",
97 'categories': $categories
98 }))
99 #end
100 #end
101 #set ($macroList = $collectiontool.sort($macroList, 'name'))
102 #set ($discard = $data.put('list', $macroList))
103 ## Get macros provided by compatible available extensions
104 #set ($macroExtensionsList = [])
105 #set($extensionQuery = $services.extension.index.newQuery("$!request.search"))
106 #set ($discard = $extensionQuery.addFilter('components__org.xwiki.rendering.macro.Macro', '', 'MATCH'))
107 #if ($xcontext.isMainWiki())
108 #set ($discard = $extensionQuery.setCompatible(true, '', "wiki:$xcontext.database"))
109 #else
110 #set ($discard = $extensionQuery.setCompatible(true, "wiki:$xcontext.database"))
111 #end
112 #set ($discard = $extensionQuery.setInstalled(false, '', "wiki:$xcontext.database"))
113 #set ($extensions = $services.extension.index.repository.search($extensionQuery))
114 #if ($extensions.size > 0)
115 #set ($macroExtensionsMap = {})
116 #foreach ($extension in $extensions)
117 ## TODO: move to a proper generic API to check if an extension can be installed by a given user
118 #set ($extensionInstallAllowed = $services.security.authorization.hasAccess('programming', $xcontext.userReference, $NULL)
119 || (($extension.type == 'xar' || $extension.type == 'webjar')
120 && $services.security.authorization.hasAccess('admin', $xcontext.userReference, "wiki:$xcontext.database") && $services.extension.isAllowed($extension, "wiki:$xcontext.database")))
121 #foreach ($extensionComponent in $extension.getComponents())
122 #if ($extensionComponent.roleType == 'org.xwiki.rendering.macro.Macro')
123 ## Skip macros identifiers for which a macro is already installed
124 #if (!$installedMacros.contains($extensionComponent.roleHint))
125 #set ($discard = $macroExtensionsList.add({
126 'id' : {
127 'id' : $extensionComponent.roleHint
128 },
129 'name': $extensionComponent.roleHint,
130 'description': $extension.summary,
131 'defaultCategory': '_notinstalled',
132 'categories': [{
133 'id' :'_notinstalled',
134 'label': $services.localization.render('macroSelector.filter.category.notinstalled')
135 }],
136 'extensionId' : $extension.id.id,
137 'extensionVersion' : $extension.id.version.value,
138 'extensionType' : $extension.type,
139 'extensionRecommended': $extension.recommended,
140 'extensionName': $extension.name,
141 'extensionSummary': $extension.summary,
142 'extensionInstallAllowed': $extensionInstallAllowed
143 }))
144 #end
145 #end
146 #end
147 #end
148 #set ($discard = $data.put('notinstalled', $macroExtensionsList))
149 #end
150 #end
151
152 #macro (maybeGetMacroDescriptor $macroIdAsString)
153 #ckeditor_initRequiredSkinExtensions()
154 #set ($macroDescriptor = $services.wysiwyg.getMacroDescriptorUI($macroIdAsString))
155 #if ($macroDescriptor)
156 #set ($data = {
157 'descriptor': $macroDescriptor,
158 'requiredSkinExtensions': "#ckeditor_getRequiredSkinExtensions()"
159 })
160 #end
161 #end
162
163 #macro (maybeTranslate $key $defaultValue)
164 #if ($services.localization.get($key))
165 $services.localization.render($key)##
166 #else
167 $!defaultValue##
168 #end
169 #end
170
171 #macro (installMacroExtension $extensionId, $extensionVersion)
172 #set ($extension = $services.extension.index.repository.resolve("$extensionId/$extensionVersion"))
173 #if ($extension)
174 ## Find where to install it
175 ## 1) Check if a diffferent version is already installed
176 ## 2) Check if it's allowed to install it at current wiki level
177 #set ($rootNamespace = $NULL)
178 #set ($currentWikiNamespace = "wiki:$xcontext.database")
179 #if ($services.extension.installed.getInstalledExtension($extensionId, $rootNamespace))
180 #set ($extensionNamespace = $rootNamespace)
181 #elseif ($services.extension.installed.getInstalledExtension($extensionId, $currentWikiNamespace))
182 #set ($extensionNamespace = $currentWikiNamespace)
183 #else
184 #if ($services.extension.isAllowed($extension, "wiki:$xcontext.database"))
185 #set ($extensionNamespace = $currentWikiNamespace)
186 #else
187 #set ($extensionNamespace = $NULL)
188 #end
189 #end
190 ## Make the install non interractive
191 #set ($installRequest = $services.extension.createInstallRequest($extensionId, $extensionVersion, $extensionNamespace))
192 #set ($discard = $installRequest.setInteractive(false))
193 ## Start the install
194 #set ($job = $services.extension.install($installRequest))
195 ## Wait for the job to finish
196 #set ($discard = $job.join())
197 #if ($job.status.error)
198 ## The install failed
199 $response.sendError(500, $exceptiontool.getRootCauseMessage($job.status.error))
200 #else
201 ## The install succeeded
202 #set ($data = {
203 'extensionId': $extensionId,
204 'extensionVersion': $extensionVersion,
205 'extensionNamespace': $extensionNamespace
206 })
207 #end
208 #else
209 $response.sendError(404, $exceptiontool.getRootCauseMessage($job.status.error))
210 #end
211 #end
212
213 #macro (getMacroParameters $macroId $macroParameters)
214 #set ($macroId = $services.rendering.resolveMacroId($macroId))
215 #set ($macroParameters = $jsontool.fromString($macroParameters))
216 #foreach($macroParameter in $macroParameters.entrySet())
217 ## TODO: Do we need to take into account the macro parameter type? We could have a macro parameter that is editable
218 ## inline but whose value is not a List<Block> but rather a String (plain text).
219 #set ($macroParameter.value = $services.wysiwyg.fromAnnotatedXHTML($macroParameter.value, $macroId.syntax))
220 #end
221 #set ($data = $macroParameters)
222 #end
223
224 #set ($data = $NULL)
225 #if ("$!request.action" == 'install')
226 #if ($services.csrf.isTokenValid($request.form_token))
227 #installMacroExtension($request.extensionId, $request.extensionVersion)
228 #else
229 $response.sendError(403)
230 #end
231 #elseif ($request.data == 'list')
232 #getMacroList($request.syntaxId)
233 #elseif ($request.data == 'descriptor')
234 #maybeGetMacroDescriptor($request.macroId)
235 #elseif ($request.data == 'macroParameters')
236 #getMacroParameters($request.macroId, $request.macroParameters)
237 #end
238 #if ($response.isCommitted())
239 ## Do nothing.
240 #elseif ($data)
241 #jsonResponse($data)
242 #elseif ("$!request.action" != '' || "$!request.data" != '')
243 $response.sendError(404)
244 #end
245 {{/velocity}}