Commit | Line | Data |
---|---|---|
8e355853 MG |
1 | <?php |
2 | // This file is part of Moodle - http://moodle.org/ | |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | /** | |
18 | * Contains class core_tag_external | |
19 | * | |
20 | * @package core_tag | |
21 | * @copyright 2015 Marina Glancy | |
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
23 | */ | |
24 | ||
e71687ba JL |
25 | defined('MOODLE_INTERNAL') || die(); |
26 | ||
8e355853 MG |
27 | require_once("$CFG->libdir/externallib.php"); |
28 | require_once("$CFG->dirroot/webservice/externallib.php"); | |
29 | ||
30 | /** | |
31 | * Tags-related web services | |
32 | * | |
33 | * @package core_tag | |
34 | * @copyright 2015 Marina Glancy | |
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
36 | */ | |
37 | class core_tag_external extends external_api { | |
38 | ||
39 | /** | |
40 | * Parameters for function update_tags() | |
41 | * | |
42 | * @return external_function_parameters | |
43 | */ | |
44 | public static function update_tags_parameters() { | |
45 | return new external_function_parameters( | |
46 | array( | |
47 | 'tags' => new external_multiple_structure( | |
48 | new external_single_structure( | |
49 | array( | |
50 | 'id' => new external_value(PARAM_INT, 'tag id'), | |
51 | 'rawname' => new external_value(PARAM_RAW, 'tag raw name (may contain capital letters)', | |
52 | VALUE_OPTIONAL), | |
53 | 'description' => new external_value(PARAM_RAW, 'tag description', VALUE_OPTIONAL), | |
54 | 'descriptionformat' => new external_value(PARAM_INT, 'tag description format', VALUE_OPTIONAL), | |
55 | 'flag' => new external_value(PARAM_INT, 'flag', VALUE_OPTIONAL), | |
e11d7380 MG |
56 | 'official' => new external_value(PARAM_INT, |
57 | '(deprecated, use isstandard) whether this flag is standard', VALUE_OPTIONAL), | |
58 | 'isstandard' => new external_value(PARAM_INT, 'whether this flag is standard', VALUE_OPTIONAL), | |
8e355853 MG |
59 | ) |
60 | ) | |
61 | ) | |
62 | ) | |
63 | ); | |
64 | } | |
65 | ||
8e355853 MG |
66 | /** |
67 | * Update tags | |
68 | * | |
69 | * @param array $tags | |
70 | */ | |
71 | public static function update_tags($tags) { | |
72 | global $CFG, $PAGE, $DB; | |
8e355853 MG |
73 | |
74 | // Validate and normalize parameters. | |
75 | $tags = self::validate_parameters(self::update_tags_parameters(), array('tags' => $tags)); | |
76 | ||
77 | $systemcontext = context_system::instance(); | |
78 | $canmanage = has_capability('moodle/tag:manage', $systemcontext); | |
79 | $canedit = has_capability('moodle/tag:edit', $systemcontext); | |
8e355853 MG |
80 | $warnings = array(); |
81 | ||
82 | if (empty($CFG->usetags)) { | |
83 | throw new moodle_exception('tagsaredisabled', 'tag'); | |
84 | } | |
85 | ||
86 | $renderer = $PAGE->get_renderer('core'); | |
87 | foreach ($tags['tags'] as $tag) { | |
88 | $tag = (array)$tag; | |
89 | if (array_key_exists('rawname', $tag)) { | |
90 | $tag['rawname'] = clean_param($tag['rawname'], PARAM_TAG); | |
91 | if (empty($tag['rawname'])) { | |
92 | unset($tag['rawname']); | |
8e355853 MG |
93 | } |
94 | } | |
95 | if (!$canmanage) { | |
96 | // User without manage capability can not change any fields except for descriptions. | |
97 | $tag = array_intersect_key($tag, array('id' => 1, | |
98 | 'description' => 1, 'descriptionformat' => 1)); | |
99 | } | |
100 | if (!$canedit) { | |
101 | // User without edit capability can not change description. | |
102 | $tag = array_diff_key($tag, | |
103 | array('description' => 1, 'descriptionformat' => 1)); | |
104 | } | |
105 | if (count($tag) <= 1) { | |
ef4c23cc MG |
106 | $warnings[] = array( |
107 | 'item' => $tag['id'], | |
108 | 'warningcode' => 'nothingtoupdate', | |
109 | 'message' => get_string('nothingtoupdate', 'core_tag') | |
110 | ); | |
8e355853 MG |
111 | continue; |
112 | } | |
c026a28d | 113 | if (!$tagobject = core_tag_tag::get($tag['id'], '*')) { |
8e355853 MG |
114 | $warnings[] = array( |
115 | 'item' => $tag['id'], | |
116 | 'warningcode' => 'tagnotfound', | |
117 | 'message' => get_string('tagnotfound', 'error') | |
118 | ); | |
119 | continue; | |
120 | } | |
121 | // First check if new tag name is allowed. | |
c026a28d | 122 | if (!empty($tag['rawname']) && ($existing = core_tag_tag::get_by_name($tagobject->tagcollid, $tag['rawname']))) { |
8e355853 MG |
123 | if ($existing->id != $tag['id']) { |
124 | $warnings[] = array( | |
125 | 'item' => $tag['id'], | |
126 | 'warningcode' => 'namesalreadybeeingused', | |
127 | 'message' => get_string('namesalreadybeeingused', 'core_tag') | |
128 | ); | |
129 | continue; | |
130 | } | |
131 | } | |
132 | if (array_key_exists('official', $tag)) { | |
e11d7380 MG |
133 | // Parameter 'official' deprecated and replaced with 'isstandard'. |
134 | $tag['isstandard'] = $tag['official'] ? 1 : 0; | |
8e355853 MG |
135 | unset($tag['official']); |
136 | } | |
c026a28d MG |
137 | if (isset($tag['flag'])) { |
138 | if ($tag['flag']) { | |
139 | $tagobject->flag(); | |
140 | } else { | |
141 | $tagobject->reset_flag(); | |
142 | } | |
143 | unset($tag['flag']); | |
144 | } | |
145 | unset($tag['id']); | |
146 | if (count($tag)) { | |
147 | $tagobject->update($tag); | |
8e355853 | 148 | } |
8e355853 | 149 | } |
ef4c23cc | 150 | return array('warnings' => $warnings); |
8e355853 MG |
151 | } |
152 | ||
153 | /** | |
154 | * Return structure for update_tag() | |
155 | * | |
156 | * @return external_description | |
157 | */ | |
158 | public static function update_tags_returns() { | |
ef4c23cc MG |
159 | return new external_single_structure( |
160 | array( | |
161 | 'warnings' => new external_warnings() | |
162 | ) | |
163 | ); | |
164 | } | |
165 | ||
166 | /** | |
167 | * Parameters for function get_tags() | |
168 | * | |
169 | * @return external_function_parameters | |
170 | */ | |
171 | public static function get_tags_parameters() { | |
172 | return new external_function_parameters( | |
173 | array( | |
174 | 'tags' => new external_multiple_structure( | |
175 | new external_single_structure( | |
176 | array( | |
177 | 'id' => new external_value(PARAM_INT, 'tag id'), | |
178 | ) | |
179 | ) | |
180 | ) | |
181 | ) | |
182 | ); | |
183 | } | |
184 | ||
ef4c23cc MG |
185 | /** |
186 | * Get tags by their ids | |
187 | * | |
188 | * @param array $tags | |
189 | */ | |
190 | public static function get_tags($tags) { | |
191 | global $CFG, $PAGE, $DB; | |
ef4c23cc MG |
192 | |
193 | // Validate and normalize parameters. | |
194 | $tags = self::validate_parameters(self::get_tags_parameters(), array('tags' => $tags)); | |
195 | ||
ef4c23cc | 196 | $systemcontext = context_system::instance(); |
67ee1030 FM |
197 | self::validate_context($systemcontext); |
198 | ||
ef4c23cc MG |
199 | $canmanage = has_capability('moodle/tag:manage', $systemcontext); |
200 | $canedit = has_capability('moodle/tag:edit', $systemcontext); | |
201 | ||
202 | $return = array(); | |
203 | $warnings = array(); | |
204 | ||
205 | if (empty($CFG->usetags)) { | |
206 | throw new moodle_exception('tagsaredisabled', 'tag'); | |
207 | } | |
208 | ||
209 | $renderer = $PAGE->get_renderer('core'); | |
210 | foreach ($tags['tags'] as $tag) { | |
211 | $tag = (array)$tag; | |
212 | if (!$tagobject = $DB->get_record('tag', array('id' => $tag['id']))) { | |
213 | $warnings[] = array( | |
214 | 'item' => $tag['id'], | |
215 | 'warningcode' => 'tagnotfound', | |
216 | 'message' => get_string('tagnotfound', 'error') | |
217 | ); | |
218 | continue; | |
219 | } | |
220 | $tagoutput = new \core_tag\output\tag($tagobject); | |
221 | // Do not return some information to users without permissions. | |
222 | $rv = $tagoutput->export_for_template($renderer); | |
223 | if (!$canmanage) { | |
224 | if (!$canedit) { | |
e11d7380 | 225 | unset($rv->isstandard); |
ef4c23cc MG |
226 | unset($rv->official); |
227 | } | |
228 | unset($rv->flag); | |
ef4c23cc MG |
229 | } |
230 | $return[] = $rv; | |
231 | } | |
232 | return array('tags' => $return, 'warnings' => $warnings); | |
233 | } | |
234 | ||
235 | /** | |
236 | * Return structure for get_tag() | |
237 | * | |
238 | * @return external_description | |
239 | */ | |
240 | public static function get_tags_returns() { | |
8e355853 MG |
241 | return new external_single_structure( |
242 | array( | |
243 | 'tags' => new external_multiple_structure( new external_single_structure( | |
244 | array( | |
245 | 'id' => new external_value(PARAM_INT, 'tag id'), | |
c026a28d | 246 | 'tagcollid' => new external_value(PARAM_INT, 'tag collection id'), |
8e355853 MG |
247 | 'name' => new external_value(PARAM_TAG, 'name'), |
248 | 'rawname' => new external_value(PARAM_RAW, 'tag raw name (may contain capital letters)'), | |
249 | 'description' => new external_value(PARAM_RAW, 'tag description'), | |
ef4c23cc MG |
250 | 'descriptionformat' => new external_format_value(PARAM_INT, 'tag description format'), |
251 | 'flag' => new external_value(PARAM_INT, 'flag', VALUE_OPTIONAL), | |
e11d7380 MG |
252 | 'official' => new external_value(PARAM_INT, |
253 | 'whether this flag is standard (deprecated, use isstandard)', VALUE_OPTIONAL), | |
254 | 'isstandard' => new external_value(PARAM_INT, 'whether this flag is standard', VALUE_OPTIONAL), | |
8e355853 | 255 | 'viewurl' => new external_value(PARAM_URL, 'URL to view'), |
ef4c23cc | 256 | ), 'information about one tag') |
8e355853 MG |
257 | ), |
258 | 'warnings' => new external_warnings() | |
259 | ) | |
260 | ); | |
261 | } | |
c026a28d MG |
262 | |
263 | /** | |
264 | * Parameters for function get_tagindex() | |
265 | * | |
266 | * @return external_function_parameters | |
267 | */ | |
268 | public static function get_tagindex_parameters() { | |
269 | return new external_function_parameters( | |
270 | array( | |
271 | 'tagindex' => new external_single_structure(array( | |
272 | 'tag' => new external_value(PARAM_TAG, 'tag name'), | |
273 | 'tc' => new external_value(PARAM_INT, 'tag collection id'), | |
274 | 'ta' => new external_value(PARAM_INT, 'tag area id'), | |
275 | 'excl' => new external_value(PARAM_BOOL, 'exlusive mode for this tag area', VALUE_OPTIONAL, 0), | |
276 | 'from' => new external_value(PARAM_INT, 'context id where the link was displayed', VALUE_OPTIONAL, 0), | |
277 | 'ctx' => new external_value(PARAM_INT, 'context id where to search for items', VALUE_OPTIONAL, 0), | |
278 | 'rec' => new external_value(PARAM_INT, 'search in the context recursive', VALUE_OPTIONAL, 1), | |
279 | 'page' => new external_value(PARAM_INT, 'page number (0-based)', VALUE_OPTIONAL, 0), | |
280 | ), 'parameters') | |
281 | ) | |
282 | ); | |
283 | } | |
284 | ||
285 | /** | |
286 | * Get tags by their ids | |
287 | * | |
288 | * @param array $params | |
289 | */ | |
290 | public static function get_tagindex($params) { | |
291 | global $PAGE; | |
292 | // Validate and normalize parameters. | |
293 | $tagindex = self::validate_parameters( | |
294 | self::get_tagindex_parameters(), array('tagindex' => $params)); | |
295 | $params = $tagindex['tagindex'] + array( | |
296 | 'excl' => 0, | |
297 | 'from' => 0, | |
298 | 'ctx' => 0, | |
299 | 'rec' => 1, | |
300 | 'page' => 0 | |
301 | ); | |
302 | ||
303 | // Login to the course / module if applicable. | |
304 | $context = $params['ctx'] ? context::instance_by_id($params['ctx']) : context_system::instance(); | |
c026a28d MG |
305 | self::validate_context($context); |
306 | ||
307 | $tag = core_tag_tag::get_by_name($params['tc'], $params['tag'], '*', MUST_EXIST); | |
308 | $tagareas = core_tag_collection::get_areas($params['tc']); | |
309 | $tagindex = $tag->get_tag_index($tagareas[$params['ta']], $params['excl'], $params['from'], | |
310 | $params['ctx'], $params['rec'], $params['page']); | |
311 | $renderer = $PAGE->get_renderer('core'); | |
312 | return $tagindex->export_for_template($renderer); | |
313 | } | |
314 | ||
315 | /** | |
316 | * Return structure for get_tag() | |
317 | * | |
318 | * @return external_description | |
319 | */ | |
320 | public static function get_tagindex_returns() { | |
321 | return new external_single_structure( | |
322 | array( | |
323 | 'tagid' => new external_value(PARAM_INT, 'tag id'), | |
324 | 'ta' => new external_value(PARAM_INT, 'tag area id'), | |
325 | 'component' => new external_value(PARAM_COMPONENT, 'component'), | |
326 | 'itemtype' => new external_value(PARAM_NOTAGS, 'itemtype'), | |
327 | 'nextpageurl' => new external_value(PARAM_URL, 'URL for the next page', VALUE_OPTIONAL), | |
328 | 'prevpageurl' => new external_value(PARAM_URL, 'URL for the next page', VALUE_OPTIONAL), | |
329 | 'exclusiveurl' => new external_value(PARAM_URL, 'URL for exclusive link', VALUE_OPTIONAL), | |
330 | 'exclusivetext' => new external_value(PARAM_TEXT, 'text for exclusive link', VALUE_OPTIONAL), | |
331 | 'title' => new external_value(PARAM_RAW, 'title'), | |
332 | 'content' => new external_value(PARAM_RAW, 'title'), | |
333 | 'hascontent' => new external_value(PARAM_INT, 'whether the content is present'), | |
334 | 'anchor' => new external_value(PARAM_TEXT, 'name of anchor', VALUE_OPTIONAL), | |
335 | ), 'tag index' | |
336 | ); | |
337 | } | |
f1218899 JL |
338 | |
339 | ||
340 | /** | |
341 | * Parameters for function get_tagindex_per_area() | |
342 | * | |
343 | * @return external_function_parameters | |
344 | * @since Moodle 3.7 | |
345 | */ | |
346 | public static function get_tagindex_per_area_parameters() { | |
347 | return new external_function_parameters( | |
348 | array( | |
349 | 'tagindex' => new external_single_structure(array( | |
350 | 'id' => new external_value(PARAM_INT, 'tag id', VALUE_OPTIONAL, 0), | |
351 | 'tag' => new external_value(PARAM_TAG, 'tag name', VALUE_OPTIONAL, ''), | |
352 | 'tc' => new external_value(PARAM_INT, 'tag collection id', VALUE_OPTIONAL, 0), | |
353 | 'ta' => new external_value(PARAM_INT, 'tag area id', VALUE_OPTIONAL, 0), | |
354 | 'excl' => new external_value(PARAM_BOOL, 'exlusive mode for this tag area', VALUE_OPTIONAL, 0), | |
355 | 'from' => new external_value(PARAM_INT, 'context id where the link was displayed', VALUE_OPTIONAL, 0), | |
356 | 'ctx' => new external_value(PARAM_INT, 'context id where to search for items', VALUE_OPTIONAL, 0), | |
357 | 'rec' => new external_value(PARAM_INT, 'search in the context recursive', VALUE_OPTIONAL, 1), | |
358 | 'page' => new external_value(PARAM_INT, 'page number (0-based)', VALUE_OPTIONAL, 0), | |
359 | ), 'parameters') | |
360 | ) | |
361 | ); | |
362 | } | |
363 | ||
364 | /** | |
365 | * Returns the tag index per multiple areas if requested. | |
366 | * | |
367 | * @param array $params Tag index required information. | |
368 | * @throws moodle_exception | |
369 | * @since Moodle 3.7 | |
370 | */ | |
371 | public static function get_tagindex_per_area($params) { | |
372 | global $CFG, $PAGE; | |
373 | // Validate and normalize parameters. | |
374 | $tagindex = self::validate_parameters( | |
375 | self::get_tagindex_per_area_parameters(), array('tagindex' => $params)); | |
376 | $params = $tagindex['tagindex'] + array( // Force defaults. | |
377 | 'id' => 0, | |
378 | 'tag' => '', | |
379 | 'tc' => 0, | |
380 | 'ta' => 0, | |
381 | 'excl' => 0, | |
382 | 'from' => 0, | |
383 | 'ctx' => 0, | |
384 | 'rec' => 1, | |
385 | 'page' => 0, | |
386 | ); | |
387 | ||
388 | if (empty($CFG->usetags)) { | |
389 | throw new moodle_exception('tagsaredisabled', 'tag'); | |
390 | } | |
391 | ||
392 | if (!empty($params['tag'])) { | |
393 | if (empty($params['tc'])) { | |
394 | // Tag name specified but tag collection was not. Try to guess it. | |
395 | $tags = core_tag_tag::guess_by_name($params['tag'], '*'); | |
396 | if (count($tags) > 1) { | |
397 | // It is in more that one collection, do not display. | |
398 | throw new moodle_exception('Tag is in more that one collection, please indicate one.'); | |
399 | } else if (count($tags) == 1) { | |
400 | $tag = reset($tags); | |
401 | } | |
402 | } else { | |
403 | if (!$tag = core_tag_tag::get_by_name($params['tc'], $params['tag'], '*')) { | |
404 | // Not found in collection. | |
405 | throw new moodle_exception('notagsfound', 'tag'); | |
406 | } | |
407 | } | |
408 | } else if (!empty($params['id'])) { | |
409 | $tag = core_tag_tag::get($params['id'], '*'); | |
410 | } | |
411 | ||
412 | if (empty($tag)) { | |
413 | throw new moodle_exception('notagsfound', 'tag'); | |
414 | } | |
415 | ||
416 | // Login to the course / module if applicable. | |
417 | $context = !empty($params['ctx']) ? context::instance_by_id($params['ctx']) : context_system::instance(); | |
418 | self::validate_context($context); | |
419 | ||
420 | $tag = core_tag_tag::get_by_name($params['tc'], $tag->name, '*', MUST_EXIST); | |
421 | $tagareas = core_tag_collection::get_areas($params['tc']); | |
422 | $tagareaid = $params['ta']; | |
423 | ||
424 | $exclusivemode = 0; | |
425 | // Find all areas in this collection and their items tagged with this tag. | |
426 | if ($tagareaid) { | |
427 | $tagareas = array($tagareas[$tagareaid]); | |
428 | } | |
429 | if (!$tagareaid && count($tagareas) == 1) { | |
430 | // Automatically set "exclusive" mode for tag collection with one tag area only. | |
431 | $params['excl'] = 1; | |
432 | } | |
433 | ||
434 | $renderer = $PAGE->get_renderer('core'); | |
435 | $result = array(); | |
436 | foreach ($tagareas as $ta) { | |
437 | $tagindex = $tag->get_tag_index($ta, $params['excl'], $params['from'], $params['ctx'], $params['rec'], $params['page']); | |
438 | if (!empty($tagindex->hascontent)) { | |
439 | $result[] = $tagindex->export_for_template($renderer); | |
440 | } | |
441 | } | |
442 | return $result; | |
443 | } | |
444 | ||
445 | /** | |
446 | * Return structure for get_tagindex_per_area | |
447 | * | |
448 | * @return external_description | |
449 | * @since Moodle 3.7 | |
450 | */ | |
451 | public static function get_tagindex_per_area_returns() { | |
452 | return new external_multiple_structure( | |
453 | self::get_tagindex_returns() | |
454 | ); | |
455 | } | |
ba224fb4 | 456 | } |