PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/tag/classes/privacy/provider.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 283 lines | 138 code | 27 blank | 118 comment | 12 complexity | 083ed832462c0382069c94e1eb1c3cd9 MD5 | raw file
  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. * Privacy Subsystem implementation for core_tag.
  18. *
  19. * @package core_tag
  20. * @copyright 2018 Zig Tan <zig@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace core_tag\privacy;
  24. defined('MOODLE_INTERNAL') || die();
  25. use \core_privacy\local\metadata\collection;
  26. use core_privacy\local\request\approved_contextlist;
  27. use core_privacy\local\request\contextlist;
  28. use core_privacy\local\request\transform;
  29. use core_privacy\local\request\writer;
  30. /**
  31. * Privacy Subsystem implementation for core_tag.
  32. *
  33. * @copyright 2018 Zig Tan <zig@moodle.com>
  34. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35. */
  36. class provider implements
  37. // Tags store user data.
  38. \core_privacy\local\metadata\provider,
  39. // The tag subsystem provides data to other components.
  40. \core_privacy\local\request\subsystem\plugin_provider,
  41. // The tag subsystem may have data that belongs to this user.
  42. \core_privacy\local\request\plugin\provider {
  43. /**
  44. * Returns meta data about this system.
  45. *
  46. * @param collection $collection The initialised collection to add items to.
  47. * @return collection A listing of user data stored through this system.
  48. */
  49. public static function get_metadata(collection $collection) : collection {
  50. // The table 'tag' contains data that a user has entered.
  51. // It is currently linked with a userid, but this field will hopefulyl go away.
  52. // Note: The userid is not necessarily 100% accurate. See MDL-61555.
  53. $collection->add_database_table('tag', [
  54. 'name' => 'privacy:metadata:tag:name',
  55. 'rawname' => 'privacy:metadata:tag:rawname',
  56. 'description' => 'privacy:metadata:tag:description',
  57. 'flag' => 'privacy:metadata:tag:flag',
  58. 'timemodified' => 'privacy:metadata:tag:timemodified',
  59. 'userid' => 'privacy:metadata:tag:userid',
  60. ], 'privacy:metadata:tag');
  61. // The table 'tag_instance' contains user data.
  62. // It links the user of a specific tag, to the item which is tagged.
  63. // In some cases the userid who 'owns' the tag is also stored.
  64. $collection->add_database_table('tag_instance', [
  65. 'tagid' => 'privacy:metadata:taginstance:tagid',
  66. 'ordering' => 'privacy:metadata:taginstance:ordering',
  67. 'timecreated' => 'privacy:metadata:taginstance:timecreated',
  68. 'timemodified' => 'privacy:metadata:taginstance:timemodified',
  69. 'tiuserid' => 'privacy:metadata:taginstance:tiuserid',
  70. ], 'privacy:metadata:taginstance');
  71. // The table 'tag_area' does not contain any specific user data.
  72. // It links components and item types to collections and describes how they can be associated.
  73. // The table 'tag_coll' does not contain any specific user data.
  74. // It describes a list of tag collections configured by the administrator.
  75. // The table 'tag_correlation' does not contain any user data.
  76. // It is a cache for other data already stored.
  77. return $collection;
  78. }
  79. /**
  80. * Store all tags which match the specified component, itemtype, and itemid.
  81. *
  82. * In most situations you will want to specify $onlyuser as false.
  83. * This will fetch only tags where the user themselves set the tag, or where tags are a shared resource.
  84. *
  85. * If you specify $onlyuser as true, only the tags created by that user will be included.
  86. *
  87. * @param int $userid The user whose information is to be exported
  88. * @param \context $context The context to export for
  89. * @param array $subcontext The subcontext within the context to export this information
  90. * @param string $component The component to fetch data from
  91. * @param string $itemtype The itemtype that the data was exported in within the component
  92. * @param int $itemid The itemid within that tag
  93. * @param bool $onlyuser Whether to only export ratings that the current user has made, or all tags
  94. */
  95. public static function export_item_tags(
  96. int $userid,
  97. \context $context,
  98. array $subcontext,
  99. string $component,
  100. string $itemtype,
  101. int $itemid,
  102. bool $onlyuser = false
  103. ) {
  104. global $DB;
  105. // Ignore mdl_tag.userid here because it only reflects the user who originally created the tag.
  106. $sql = "SELECT
  107. t.rawname
  108. FROM {tag} t
  109. INNER JOIN {tag_instance} ti ON ti.tagid = t.id
  110. WHERE ti.component = :component
  111. AND ti.itemtype = :itemtype
  112. AND ti.itemid = :itemid
  113. ";
  114. if ($onlyuser) {
  115. $sql .= "AND ti.tiuserid = :userid";
  116. } else {
  117. $sql .= "AND (ti.tiuserid = 0 OR ti.tiuserid = :userid)";
  118. }
  119. $params = [
  120. 'component' => $component,
  121. 'itemtype' => $itemtype,
  122. 'itemid' => $itemid,
  123. 'userid' => $userid,
  124. ];
  125. if ($tags = $DB->get_fieldset_sql($sql, $params)) {
  126. $writer = \core_privacy\local\request\writer::with_context($context)
  127. ->export_related_data($subcontext, 'tags', $tags);
  128. }
  129. }
  130. /**
  131. * Deletes all tag instances for given context, component, itemtype, itemid
  132. *
  133. * In most situations you will want to specify $userid as null. Per-user tag instances
  134. * are possible in Tags API, however there are no components or standard plugins that actually use them.
  135. *
  136. * @param \context $context The context to export for
  137. * @param string $component Tagarea component
  138. * @param string $itemtype Tagarea item type
  139. * @param int $itemid The itemid within that component and itemtype (optional)
  140. * @param int $userid Only delete tag instances made by this user, per-user tags must be enabled for the tagarea
  141. */
  142. public static function delete_item_tags(\context $context, $component, $itemtype,
  143. $itemid = null, $userid = null) {
  144. global $DB;
  145. $params = ['contextid' => $context->id, 'component' => $component, 'itemtype' => $itemtype];
  146. if ($itemid) {
  147. $params['itemid'] = $itemid;
  148. }
  149. if ($userid) {
  150. $params['userid'] = $userid;
  151. }
  152. $DB->delete_records('tag_instance', $params);
  153. }
  154. /**
  155. * Deletes all tag instances for given context, component, itemtype using subquery for itemids
  156. *
  157. * In most situations you will want to specify $userid as null. Per-user tag instances
  158. * are possible in Tags API, however there are no components or standard plugins that actually use them.
  159. *
  160. * @param \context $context The context to export for
  161. * @param string $component Tagarea component
  162. * @param string $itemtype Tagarea item type
  163. * @param string $itemidstest an SQL fragment that the itemid must match. Used
  164. * in the query like WHERE itemid $itemidstest. Must use named parameters,
  165. * and may not use named parameters called contextid, component or itemtype.
  166. * @param array $params any query params used by $itemidstest.
  167. */
  168. public static function delete_item_tags_select(\context $context, $component, $itemtype,
  169. $itemidstest, $params = []) {
  170. global $DB;
  171. $params += ['contextid' => $context->id, 'component' => $component, 'itemtype' => $itemtype];
  172. $DB->delete_records_select('tag_instance',
  173. 'contextid = :contextid AND component = :component AND itemtype = :itemtype AND itemid ' . $itemidstest,
  174. $params);
  175. }
  176. /**
  177. * Get the list of contexts that contain user information for the specified user.
  178. *
  179. * @param int $userid The user to search.
  180. * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
  181. */
  182. public static function get_contexts_for_userid(int $userid) : contextlist {
  183. $contextlist = new contextlist();
  184. $contextlist->add_from_sql("SELECT c.id
  185. FROM {context} c
  186. JOIN {tag} t ON t.userid = :userid
  187. WHERE contextlevel = :contextlevel",
  188. ['userid' => $userid, 'contextlevel' => CONTEXT_SYSTEM]);
  189. return $contextlist;
  190. }
  191. /**
  192. * Export all user data for the specified user, in the specified contexts.
  193. *
  194. * @param approved_contextlist $contextlist The approved contexts to export information for.
  195. */
  196. public static function export_user_data(approved_contextlist $contextlist) {
  197. global $DB;
  198. $context = \context_system::instance();
  199. if (!$contextlist->count() || !in_array($context->id, $contextlist->get_contextids())) {
  200. return;
  201. }
  202. $user = $contextlist->get_user();
  203. $sql = "SELECT id, userid, tagcollid, name, rawname, isstandard, description, descriptionformat, flag, timemodified
  204. FROM {tag} WHERE userid = ?";
  205. $rs = $DB->get_recordset_sql($sql, [$user->id]);
  206. foreach ($rs as $record) {
  207. $subcontext = [get_string('tags', 'tag'), $record->id];
  208. $tag = (object)[
  209. 'id' => $record->id,
  210. 'userid' => transform::user($record->userid),
  211. 'name' => $record->name,
  212. 'rawname' => $record->rawname,
  213. 'isstandard' => transform::yesno($record->isstandard),
  214. 'description' => writer::with_context($context)->rewrite_pluginfile_urls($subcontext,
  215. 'tag', 'description', $record->id, strval($record->description)),
  216. 'descriptionformat' => $record->descriptionformat,
  217. 'flag' => $record->flag,
  218. 'timemodified' => transform::datetime($record->timemodified),
  219. ];
  220. writer::with_context($context)->export_data($subcontext, $tag);
  221. writer::with_context($context)->export_area_files($subcontext, 'tag', 'description', $record->id);
  222. }
  223. $rs->close();
  224. }
  225. /**
  226. * Delete all data for all users in the specified context.
  227. *
  228. * We do not delete tag instances in this method - this should be done by the components that define tagareas.
  229. * We only delete tags themselves in case of system context.
  230. *
  231. * @param context $context The specific context to delete data for.
  232. */
  233. public static function delete_data_for_all_users_in_context(\context $context) {
  234. global $DB;
  235. // Tags can only be defined in system context.
  236. if ($context->id == \context_system::instance()->id) {
  237. $DB->delete_records('tag_instance');
  238. $DB->delete_records('tag', []);
  239. }
  240. }
  241. /**
  242. * Delete all user data for the specified user, in the specified contexts.
  243. *
  244. * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
  245. */
  246. public static function delete_data_for_user(approved_contextlist $contextlist) {
  247. global $DB;
  248. $context = \context_system::instance();
  249. if (!$contextlist->count() || !in_array($context->id, $contextlist->get_contextids())) {
  250. return;
  251. }
  252. // Do not delete tags themselves in case they are used by somebody else.
  253. // If the user is the only one using the tag, it will be automatically deleted anyway during the next cron cleanup.
  254. $DB->set_field_select('tag', 'userid', 0, 'userid = ?', [$contextlist->get_user()->id]);
  255. }
  256. }