PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/availability/condition/group/classes/condition.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 292 lines | 174 code | 31 blank | 87 comment | 33 complexity | 471c5442a3278eae8ad267389ac4a84b 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. * Condition main class.
  18. *
  19. * @package availability_group
  20. * @copyright 2014 The Open University
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace availability_group;
  24. defined('MOODLE_INTERNAL') || die();
  25. /**
  26. * Condition main class.
  27. *
  28. * @package availability_group
  29. * @copyright 2014 The Open University
  30. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31. */
  32. class condition extends \core_availability\condition {
  33. /** @var array Array from group id => name */
  34. protected static $groupnames = array();
  35. /** @var int ID of group that this condition requires, or 0 = any group */
  36. protected $groupid;
  37. /**
  38. * Constructor.
  39. *
  40. * @param \stdClass $structure Data structure from JSON decode
  41. * @throws \coding_exception If invalid data structure.
  42. */
  43. public function __construct($structure) {
  44. // Get group id.
  45. if (!property_exists($structure, 'id')) {
  46. $this->groupid = 0;
  47. } else if (is_int($structure->id)) {
  48. $this->groupid = $structure->id;
  49. } else {
  50. throw new \coding_exception('Invalid ->id for group condition');
  51. }
  52. }
  53. public function save() {
  54. $result = (object)array('type' => 'group');
  55. if ($this->groupid) {
  56. $result->id = $this->groupid;
  57. }
  58. return $result;
  59. }
  60. public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
  61. $course = $info->get_course();
  62. $context = \context_course::instance($course->id);
  63. $allow = true;
  64. if (!has_capability('moodle/site:accessallgroups', $context, $userid)) {
  65. // Get all groups the user belongs to.
  66. $groups = $info->get_modinfo()->get_groups();
  67. if ($this->groupid) {
  68. $allow = in_array($this->groupid, $groups);
  69. } else {
  70. // No specific group. Allow if they belong to any group at all.
  71. $allow = $groups ? true : false;
  72. }
  73. // The NOT condition applies before accessallgroups (i.e. if you
  74. // set something to be available to those NOT in group X,
  75. // people with accessallgroups can still access it even if
  76. // they are in group X).
  77. if ($not) {
  78. $allow = !$allow;
  79. }
  80. }
  81. return $allow;
  82. }
  83. public function get_description($full, $not, \core_availability\info $info) {
  84. global $DB;
  85. if ($this->groupid) {
  86. // Need to get the name for the group. Unfortunately this requires
  87. // a database query. To save queries, get all groups for course at
  88. // once in a static cache.
  89. $course = $info->get_course();
  90. if (!array_key_exists($this->groupid, self::$groupnames)) {
  91. $coursegroups = $DB->get_records(
  92. 'groups', array('courseid' => $course->id), '', 'id, name');
  93. foreach ($coursegroups as $rec) {
  94. self::$groupnames[$rec->id] = $rec->name;
  95. }
  96. }
  97. // If it still doesn't exist, it must have been misplaced.
  98. if (!array_key_exists($this->groupid, self::$groupnames)) {
  99. $name = get_string('missing', 'availability_group');
  100. } else {
  101. $context = \context_course::instance($course->id);
  102. $name = format_string(self::$groupnames[$this->groupid], true,
  103. array('context' => $context));
  104. }
  105. } else {
  106. return get_string($not ? 'requires_notanygroup' : 'requires_anygroup',
  107. 'availability_group');
  108. }
  109. return get_string($not ? 'requires_notgroup' : 'requires_group',
  110. 'availability_group', $name);
  111. }
  112. protected function get_debug_string() {
  113. return $this->groupid ? '#' . $this->groupid : 'any';
  114. }
  115. /**
  116. * Include this condition only if we are including groups in restore, or
  117. * if it's a generic 'same activity' one.
  118. *
  119. * @param int $restoreid The restore Id.
  120. * @param int $courseid The ID of the course.
  121. * @param base_logger $logger The logger being used.
  122. * @param string $name Name of item being restored.
  123. * @param base_task $task The task being performed.
  124. *
  125. * @return Integer groupid
  126. */
  127. public function include_after_restore($restoreid, $courseid, \base_logger $logger,
  128. $name, \base_task $task) {
  129. return !$this->groupid || $task->get_setting_value('groups');
  130. }
  131. public function update_after_restore($restoreid, $courseid, \base_logger $logger, $name) {
  132. global $DB;
  133. if (!$this->groupid) {
  134. return false;
  135. }
  136. $rec = \restore_dbops::get_backup_ids_record($restoreid, 'group', $this->groupid);
  137. if (!$rec || !$rec->newitemid) {
  138. // If we are on the same course (e.g. duplicate) then we can just
  139. // use the existing one.
  140. if ($DB->record_exists('groups',
  141. array('id' => $this->groupid, 'courseid' => $courseid))) {
  142. return false;
  143. }
  144. // Otherwise it's a warning.
  145. $this->groupid = -1;
  146. $logger->process('Restored item (' . $name .
  147. ') has availability condition on group that was not restored',
  148. \backup::LOG_WARNING);
  149. } else {
  150. $this->groupid = (int)$rec->newitemid;
  151. }
  152. return true;
  153. }
  154. public function update_dependency_id($table, $oldid, $newid) {
  155. if ($table === 'groups' && (int)$this->groupid === (int)$oldid) {
  156. $this->groupid = $newid;
  157. return true;
  158. } else {
  159. return false;
  160. }
  161. }
  162. /**
  163. * Wipes the static cache used to store grouping names.
  164. */
  165. public static function wipe_static_cache() {
  166. self::$groupnames = array();
  167. }
  168. public function is_applied_to_user_lists() {
  169. // Group conditions are assumed to be 'permanent', so they affect the
  170. // display of user lists for activities.
  171. return true;
  172. }
  173. public function filter_user_list(array $users, $not, \core_availability\info $info,
  174. \core_availability\capability_checker $checker) {
  175. global $CFG, $DB;
  176. // If the array is empty already, just return it.
  177. if (!$users) {
  178. return $users;
  179. }
  180. require_once($CFG->libdir . '/grouplib.php');
  181. $course = $info->get_course();
  182. // List users for this course who match the condition.
  183. if ($this->groupid) {
  184. $groupusers = groups_get_members($this->groupid, 'u.id', 'u.id ASC');
  185. } else {
  186. $groupusers = $DB->get_records_sql("
  187. SELECT DISTINCT gm.userid
  188. FROM {groups} g
  189. JOIN {groups_members} gm ON gm.groupid = g.id
  190. WHERE g.courseid = ?", array($course->id));
  191. }
  192. // List users who have access all groups.
  193. $aagusers = $checker->get_users_by_capability('moodle/site:accessallgroups');
  194. // Filter the user list.
  195. $result = array();
  196. foreach ($users as $id => $user) {
  197. // Always include users with access all groups.
  198. if (array_key_exists($id, $aagusers)) {
  199. $result[$id] = $user;
  200. continue;
  201. }
  202. // Other users are included or not based on group membership.
  203. $allow = array_key_exists($id, $groupusers);
  204. if ($not) {
  205. $allow = !$allow;
  206. }
  207. if ($allow) {
  208. $result[$id] = $user;
  209. }
  210. }
  211. return $result;
  212. }
  213. /**
  214. * Returns a JSON object which corresponds to a condition of this type.
  215. *
  216. * Intended for unit testing, as normally the JSON values are constructed
  217. * by JavaScript code.
  218. *
  219. * @param int $groupid Required group id (0 = any group)
  220. * @return stdClass Object representing condition
  221. */
  222. public static function get_json($groupid = 0) {
  223. $result = (object)array('type' => 'group');
  224. // Id is only included if set.
  225. if ($groupid) {
  226. $result->id = (int)$groupid;
  227. }
  228. return $result;
  229. }
  230. public function get_user_list_sql($not, \core_availability\info $info, $onlyactive) {
  231. global $DB;
  232. // Get enrolled users with access all groups. These always are allowed.
  233. list($aagsql, $aagparams) = get_enrolled_sql(
  234. $info->get_context(), 'moodle/site:accessallgroups', 0, $onlyactive);
  235. // Get all enrolled users.
  236. list ($enrolsql, $enrolparams) =
  237. get_enrolled_sql($info->get_context(), '', 0, $onlyactive);
  238. // Condition for specified or any group.
  239. $matchparams = array();
  240. if ($this->groupid) {
  241. $matchsql = "SELECT 1
  242. FROM {groups_members} gm
  243. WHERE gm.userid = userids.id
  244. AND gm.groupid = " .
  245. self::unique_sql_parameter($matchparams, $this->groupid);
  246. } else {
  247. $matchsql = "SELECT 1
  248. FROM {groups_members} gm
  249. JOIN {groups} g ON g.id = gm.groupid
  250. WHERE gm.userid = userids.id
  251. AND g.courseid = " .
  252. self::unique_sql_parameter($matchparams, $info->get_course()->id);
  253. }
  254. // Overall query combines all this.
  255. $condition = $not ? 'NOT' : '';
  256. $sql = "SELECT userids.id
  257. FROM ($enrolsql) userids
  258. WHERE (userids.id IN ($aagsql)) OR $condition EXISTS ($matchsql)";
  259. return array($sql, array_merge($enrolparams, $aagparams, $matchparams));
  260. }
  261. }