Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * Condition main class.
19
 *
20
 * @package availability_grouping
21
 * @copyright 2014 The Open University
22
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace availability_grouping;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
/**
30
 * Condition main class.
31
 *
32
 * @package availability_grouping
33
 * @copyright 2014 The Open University
34
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class condition extends \core_availability\condition {
37
    /** @var array Array from grouping id => name */
38
    protected static $groupingnames = array();
39
 
40
    /** @var int ID of grouping that this condition requires */
41
    protected $groupingid = 0;
42
 
43
    /** @var bool If true, indicates that activity $cm->grouping is used */
44
    protected $activitygrouping = false;
45
 
46
    /**
47
     * Constructor.
48
     *
49
     * @param \stdClass $structure Data structure from JSON decode
50
     * @throws \coding_exception If invalid data structure.
51
     */
52
    public function __construct($structure) {
53
        // Get grouping id.
54
        if (isset($structure->id)) {
55
            if (is_int($structure->id)) {
56
                $this->groupingid = $structure->id;
57
            } else {
58
                throw new \coding_exception('Invalid ->id for grouping condition');
59
            }
60
        } else if (isset($structure->activity)) {
61
            if (is_bool($structure->activity) && $structure->activity) {
62
                $this->activitygrouping = true;
63
            } else {
64
                throw new \coding_exception('Invalid ->activity for grouping condition');
65
            }
66
        } else {
67
            throw new \coding_exception('Missing ->id / ->activity for grouping condition');
68
        }
69
    }
70
 
71
    public function save() {
72
        $result = (object)array('type' => 'grouping');
73
        if ($this->groupingid) {
74
            $result->id = $this->groupingid;
75
        } else {
76
            $result->activity = true;
77
        }
78
        return $result;
79
    }
80
 
81
    public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
82
        $context = \context_course::instance($info->get_course()->id);
83
        $allow = true;
84
        if (!has_capability('moodle/site:accessallgroups', $context, $userid)) {
85
            // If the activity has 'group members only' and you don't have accessallgroups...
86
            $groups = $info->get_modinfo()->get_groups($this->get_grouping_id($info));
87
            if (!$groups) {
88
                // ...and you don't belong to a group, then set it so you can't see/access it.
89
                $allow = false;
90
            }
91
 
92
            // The NOT condition applies before accessallgroups (i.e. if you
93
            // set something to be available to those NOT in grouping X,
94
            // people with accessallgroups can still access it even if
95
            // they are in grouping X).
96
            if ($not) {
97
                $allow = !$allow;
98
            }
99
        }
100
        return $allow;
101
    }
102
 
103
    /**
104
     * Gets the actual grouping id for the condition. This is either a specified
105
     * id, or a special flag indicating that we use the one for the current cm.
106
     *
107
     * @param \core_availability\info $info Info about context cm
108
     * @return int Grouping id
109
     * @throws \coding_exception If it's set to use a cm but there isn't grouping
110
     */
111
    protected function get_grouping_id(\core_availability\info $info) {
112
        if ($this->activitygrouping) {
113
            $groupingid = $info->get_course_module()->groupingid;
114
            if (!$groupingid) {
115
                throw new \coding_exception(
116
                        'Not supposed to be able to turn on activitygrouping when no grouping');
117
            }
118
            return $groupingid;
119
        } else {
120
            return $this->groupingid;
121
        }
122
    }
123
 
124
    public function get_description($full, $not, \core_availability\info $info) {
125
        global $DB;
126
        $course = $info->get_course();
127
 
128
        // Need to get the name for the grouping. Unfortunately this requires
129
        // a database query. To save queries, get all groupings for course at
130
        // once in a static cache.
131
        $groupingid = $this->get_grouping_id($info);
132
        if (!array_key_exists($groupingid, self::$groupingnames)) {
133
            $coursegroupings = $DB->get_records(
134
                    'groupings', array('courseid' => $course->id), '', 'id, name');
135
            foreach ($coursegroupings as $rec) {
136
                self::$groupingnames[$rec->id] = $rec->name;
137
            }
138
        }
139
 
140
        // If it still doesn't exist, it must have been misplaced.
141
        if (!array_key_exists($groupingid, self::$groupingnames)) {
142
            $name = get_string('missing', 'availability_grouping');
143
        } else {
144
            // Not safe to call format_string here; use the special function to call it later.
145
            $name = self::description_format_string(self::$groupingnames[$groupingid]);
146
        }
147
 
148
        return get_string($not ? 'requires_notgrouping' : 'requires_grouping',
149
                'availability_grouping', $name);
150
    }
151
 
152
    protected function get_debug_string() {
153
        if ($this->activitygrouping) {
154
            return 'CM';
155
        } else {
156
            return '#' . $this->groupingid;
157
        }
158
    }
159
 
160
    /**
161
     * Include this condition only if we are including groups in restore, or
162
     * if it's a generic 'same activity' one.
163
     *
164
     * @param int $restoreid The restore Id.
165
     * @param int $courseid The ID of the course.
166
     * @param base_logger $logger The logger being used.
167
     * @param string $name Name of item being restored.
168
     * @param base_task $task The task being performed.
169
     *
170
     * @return Integer groupid
171
     */
172
    public function include_after_restore($restoreid, $courseid, \base_logger $logger,
173
            $name, \base_task $task) {
174
        return !$this->groupingid || $task->get_setting_value('groups');
175
    }
176
 
177
    public function update_after_restore($restoreid, $courseid, \base_logger $logger, $name) {
178
        global $DB;
179
        if (!$this->groupingid) {
180
            // If using 'same as activity' option, no need to change it.
181
            return false;
182
        }
183
        $rec = \restore_dbops::get_backup_ids_record($restoreid, 'grouping', $this->groupingid);
184
        if (!$rec || !$rec->newitemid) {
185
            // If we are on the same course (e.g. duplicate) then we can just
186
            // use the existing one.
187
            if ($DB->record_exists('groupings',
188
                    array('id' => $this->groupingid, 'courseid' => $courseid))) {
189
                return false;
190
            }
191
            // Otherwise it's a warning.
192
            $this->groupingid = -1;
193
            $logger->process('Restored item (' . $name .
194
                    ') has availability condition on grouping that was not restored',
195
                    \backup::LOG_WARNING);
196
        } else {
197
            $this->groupingid = (int)$rec->newitemid;
198
        }
199
        return true;
200
    }
201
 
202
    public function update_dependency_id($table, $oldid, $newid) {
203
        if ($table === 'groupings' && (int)$this->groupingid === (int)$oldid) {
204
            $this->groupingid = $newid;
205
            return true;
206
        } else {
207
            return false;
208
        }
209
    }
210
 
211
    /**
212
     * Wipes the static cache used to store grouping names.
213
     */
214
    public static function wipe_static_cache() {
215
        self::$groupingnames = array();
216
    }
217
 
218
    public function is_applied_to_user_lists() {
219
        // Grouping conditions are assumed to be 'permanent', so they affect the
220
        // display of user lists for activities.
221
        return true;
222
    }
223
 
224
    public function filter_user_list(array $users, $not, \core_availability\info $info,
225
            \core_availability\capability_checker $checker) {
226
        global $CFG, $DB;
227
 
228
        // If the array is empty already, just return it.
229
        if (!$users) {
230
            return $users;
231
        }
232
 
233
        // List users for this course who match the condition.
234
        $groupingusers = $DB->get_records_sql("
235
                SELECT DISTINCT gm.userid
236
                  FROM {groupings_groups} gg
237
                  JOIN {groups_members} gm ON gm.groupid = gg.groupid
238
                 WHERE gg.groupingid = ?",
239
                array($this->get_grouping_id($info)));
240
 
241
        // List users who have access all groups.
242
        $aagusers = $checker->get_users_by_capability('moodle/site:accessallgroups');
243
 
244
        // Filter the user list.
245
        $result = array();
246
        foreach ($users as $id => $user) {
247
            // Always include users with access all groups.
248
            if (array_key_exists($id, $aagusers)) {
249
                $result[$id] = $user;
250
                continue;
251
            }
252
            // Other users are included or not based on grouping membership.
253
            $allow = array_key_exists($id, $groupingusers);
254
            if ($not) {
255
                $allow = !$allow;
256
            }
257
            if ($allow) {
258
                $result[$id] = $user;
259
            }
260
        }
261
        return $result;
262
    }
263
 
264
    /**
265
     * Returns a JSON object which corresponds to a condition of this type.
266
     *
267
     * Intended for unit testing, as normally the JSON values are constructed
268
     * by JavaScript code.
269
     *
270
     * @param int $groupingid Required grouping id (0 = grouping linked to activity)
271
     * @return stdClass Object representing condition
272
     */
273
    public static function get_json($groupingid = 0) {
274
        $result = (object)array('type' => 'grouping');
275
        if ($groupingid) {
276
            $result->id = (int)$groupingid;
277
        } else {
278
            $result->activity = true;
279
        }
280
        return $result;
281
    }
282
 
283
    public function get_user_list_sql($not, \core_availability\info $info, $onlyactive) {
284
        global $DB;
285
 
286
        // Get enrolled users with access all groups. These always are allowed.
287
        list($aagsql, $aagparams) = get_enrolled_sql(
288
                $info->get_context(), 'moodle/site:accessallgroups', 0, $onlyactive);
289
 
290
        // Get all enrolled users.
291
        list ($enrolsql, $enrolparams) =
292
                get_enrolled_sql($info->get_context(), '', 0, $onlyactive);
293
 
294
        // Condition for specified or any group.
295
        $matchparams = array();
296
        $matchsql = "SELECT 1
297
                       FROM {groups_members} gm
298
                       JOIN {groupings_groups} gg ON gg.groupid = gm.groupid
299
                      WHERE gm.userid = userids.id
300
                            AND gg.groupingid = " .
301
                self::unique_sql_parameter($matchparams, $this->get_grouping_id($info));
302
 
303
        // Overall query combines all this.
304
        $condition = $not ? 'NOT' : '';
305
        $sql = "SELECT userids.id
306
                  FROM ($enrolsql) userids
307
                 WHERE (userids.id IN ($aagsql)) OR $condition EXISTS ($matchsql)";
308
        return array($sql, array_merge($enrolparams, $aagparams, $matchparams));
309
    }
310
}