Wiki-Quellcode von MacroService

Zuletzt geändert von Daniel Herrmann am 2026/02/04 20:23

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