MDL-62418 tool_policy: Redirect always to home when agreed all policies
[moodle.git] / admin / tool / policy / classes / output / page_agreedocs.php
CommitLineData
6109f234
SA
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 * Provides {@link tool_policy\output\renderer} class.
19 *
20 * @package tool_policy
21 * @category output
22 * @copyright 2018 Sara Arjona <sara@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26namespace tool_policy\output;
27
28defined('MOODLE_INTERNAL') || die();
29
30use context_system;
31use core\output\notification;
e8cf2ffd 32use core\session\manager;
6109f234
SA
33use core_user;
34use html_writer;
35use moodle_url;
36use renderable;
37use renderer_base;
38use single_button;
39use templatable;
40use tool_policy\api;
41use tool_policy\policy_version;
42
43/**
44 * Represents a page for showing all the policy documents which a user has to agree to.
45 *
46 * @copyright 2018 Sara Arjona <sara@moodle.com>
47 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
48 */
49class page_agreedocs implements renderable, templatable {
50
51 /** @var array $policies List of public policies objects with information about the user acceptance. */
52 protected $policies = null;
53
54 /** @var array $agreedocs List of policy identifiers which the user has agreed using the form. */
55 protected $agreedocs = null;
56
57 /** @var string $action Form action to identify when user agreeds policies. */
58 protected $action = null;
59
60 /** @var int User id who wants to accept this page. */
61 protected $behalfid = null;
62
63 /** @var object User who wants to accept this page. */
64 protected $behalfuser = null;
65
66 /** @var boolean True if signup user has agreed to all the policies; false otherwise. */
67 protected $signupuserpolicyagreed = false;
68
69 /** @var array Info or error messages to show. */
70 protected $messages = [];
71
72 /**
73 * Prepare the page for rendering.
74 *
75 * @param array $agreedocs Array with the policy identifiers which the user has agreed using the form.
76 * @param int $behalfid The userid to accept the policy versions as (such as child's id).
77 * @param string $action Form action to identify when user agreeds policies.
78 */
79 public function __construct($agreedocs = null, $behalfid = 0, $action = null) {
80 global $USER;
e8cf2ffd 81 $realuser = manager::get_realuser();
6109f234
SA
82
83 $this->agreedocs = $agreedocs;
84 if (empty($this->agreedocs)) {
85 $this->agreedocs = [];
86 }
87
6109f234
SA
88 $this->action = $action;
89
e8cf2ffd
MG
90 $behalfid = $behalfid ?: $USER->id;
91 if ($realuser->id != $behalfid) {
92 $this->behalfuser = core_user::get_user($behalfid, '*', MUST_EXIST);
93 $this->behalfid = $this->behalfuser->id;
6109f234
SA
94 }
95
96 $this->policies = api::list_current_versions(policy_version::AUDIENCE_LOGGEDIN);
97 if (empty($this->behalfid)) {
98 $userid = $USER->id;
99 } else {
100 $userid = $this->behalfid;
101 }
102 $this->accept_and_revoke_policies();
103 $this->prepare_global_page_access($userid);
104 $this->prepare_user_acceptances($userid);
105 }
106
107 /**
108 * Accept and revoke the policy versions.
109 * The capabilities for accepting/revoking policies are checked into the api functions.
110 *
111 */
112 protected function accept_and_revoke_policies() {
113 global $USER;
114
115 if (!empty($USER->id)) {
116 // Existing user.
117 if (!empty($this->action) && confirm_sesskey()) {
118 // The form has been sent. Update policies acceptances according to $this->agreedocs.
119 $lang = current_language();
120 // Accept / revoke policies.
121 $acceptversionids = array();
122 foreach ($this->policies as $policy) {
123 if (in_array($policy->id, $this->agreedocs)) {
124 // Save policy version doc to accept it.
125 $acceptversionids[] = $policy->id;
126 } else {
127 // Revoke policy doc.
128 api::revoke_acceptance($policy->id, $this->behalfid);
129 }
130 }
131 // Accept all policy docs saved in $acceptversionids.
132 api::accept_policies($acceptversionids, $this->behalfid, null, $lang);
133 // Show a message to let know the user he/she must agree all the policies.
134 if (count($acceptversionids) != count($this->policies)) {
135 $message = (object) [
136 'type' => 'error',
137 'text' => get_string('mustagreetocontinue', 'tool_policy')
138 ];
139 } else {
140 $message = (object) [
141 'type' => 'success',
142 'text' => get_string('acceptancessavedsucessfully', 'tool_policy')
143 ];
144 }
145 $this->messages[] = $message;
4e9e2b0a 146 } else if (!empty($this->policies) && empty($USER->policyagreed)) {
6109f234
SA
147 // Inform users they must agree to all policies before continuing.
148 $message = (object) [
149 'type' => 'error',
150 'text' => get_string('mustagreetocontinue', 'tool_policy')
151 ];
152 $this->messages[] = $message;
153 }
154 } else {
155 // New user.
156 if (!empty($this->action) && confirm_sesskey()) {
157 // The form has been sent.
158 $currentpolicyversionids = [];
159 foreach ($this->policies as $policy) {
160 $currentpolicyversionids[] = $policy->id;
161 }
162 // If the user has accepted all the policies, add it to the session to let continue with the signup process.
163 $this->signupuserpolicyagreed = empty(array_diff($currentpolicyversionids, $this->agreedocs));
164 \cache::make('core', 'presignup')->set('tool_policy_userpolicyagreed',
165 $this->signupuserpolicyagreed);
166 } else if (empty($this->policies)) {
167 // There are no policies to agree to. Update the policyagreed value to avoid show empty consent page.
168 \cache::make('core', 'presignup')->set('tool_policy_userpolicyagreed', 1);
169 }
170 if (!empty($this->policies) && !$this->signupuserpolicyagreed) {
171 // During the signup process, inform users they must agree to all policies before continuing.
172 $message = (object) [
173 'type' => 'error',
174 'text' => get_string('mustagreetocontinue', 'tool_policy')
175 ];
176 $this->messages[] = $message;
177 }
178 }
179 }
180
181 /**
182 * Before display the consent page, the user has to view all the still-non-accepted policy docs.
183 * This function checks if the non-accepted policy docs have been shown and redirect to them.
184 *
185 * @param array $userid User identifier who wants to access to the consent page.
186 * @param url $returnurl URL to return after shown the policy docs.
187 */
188 protected function redirect_to_policies($userid, $returnurl = null) {
189 global $USER;
190
191 $acceptances = api::get_user_acceptances($userid);
192 $allpolicies = $this->policies;
193 if (!empty($userid)) {
194 foreach ($allpolicies as $policy) {
195 if (api::is_user_version_accepted($userid, $policy->id, $acceptances)) {
196 // If this version is accepted by the user, remove from the pending policies list.
197 unset($allpolicies[array_search($policy, $allpolicies)]);
198 }
199 }
200 }
201
202 if (!empty($allpolicies)) {
203 $currentpolicyversionids = [];
204 foreach ($allpolicies as $policy) {
205 $currentpolicyversionids[] = $policy->id;
206 }
207
208 $cache = \cache::make('core', 'presignup');
209 $cachekey = 'tool_policy_viewedpolicies';
210
211 $viewedpolicies = $cache->get($cachekey);
212 if (!empty($viewedpolicies)) {
213 // Get the list of the policies docs which the user haven't viewed during this session.
214 $pendingpolicies = array_diff($currentpolicyversionids, $viewedpolicies);
215 } else {
216 $pendingpolicies = $currentpolicyversionids;
217 }
218 if (count($pendingpolicies) > 0) {
219 // Still is needed to show some policies docs. Save in the session and redirect.
220 $policyversionid = array_shift($pendingpolicies);
221 $viewedpolicies[] = $policyversionid;
222 $cache->set($cachekey, $viewedpolicies);
223 if (empty($returnurl)) {
224 $returnurl = new moodle_url('/admin/tool/policy/index.php');
225 }
226 $urlparams = ['versionid' => $policyversionid,
227 'returnurl' => $returnurl,
228 'numpolicy' => count($currentpolicyversionids) - count($pendingpolicies),
229 'totalpolicies' => count($currentpolicyversionids),
230 ];
231 redirect(new moodle_url('/admin/tool/policy/view.php', $urlparams));
232 }
233 }
234 }
235
236 /**
237 * Redirect to $SESSION->wantsurl if defined or to $CFG->wwwroot if not.
238 */
239 protected function redirect_to_previous_url() {
3d34aa5c 240 global $SESSION;
6109f234
SA
241
242 if (!empty($SESSION->wantsurl)) {
243 $returnurl = $SESSION->wantsurl;
244 unset($SESSION->wantsurl);
245 } else {
3d34aa5c 246 $returnurl = (new moodle_url('/admin/tool/policy/user.php'))->out();
6109f234
SA
247 }
248
249 redirect($returnurl);
250 }
251
252 /**
253 * Sets up the global $PAGE and performs the access checks.
254 *
255 * @param int $userid
256 */
257 protected function prepare_global_page_access($userid) {
258 global $PAGE, $SESSION, $SITE, $USER;
259
260 // Guest users or not logged users (but the users during the signup process) are not allowed to access to this page.
261 $newsignupuser = !empty($SESSION->wantsurl) && strpos($SESSION->wantsurl, 'login/signup.php') !== false;
262 if (isguestuser() || (empty($USER->id) && !$newsignupuser)) {
263 $this->redirect_to_previous_url();
264 }
265
266 // Check for correct user capabilities.
267 if (!empty($USER->id)) {
268 // For existing users, it's needed to check if they have the capability for accepting policies.
e8cf2ffd 269 api::can_accept_policies($this->behalfid, true);
6109f234
SA
270 } else {
271 // For new users, the behalfid parameter is ignored.
272 if ($this->behalfid != $USER->id) {
273 redirect(new moodle_url('/admin/tool/policy/index.php'));
274 }
275 }
276
277 // If the current user has the $USER->policyagreed = 1 or $userpolicyagreed = 1
278 // and $SESSION->wantsurl is defined, redirect to the return page.
279 $hasagreedsignupuser = empty($USER->id) && $this->signupuserpolicyagreed;
280 $hasagreedloggeduser = $USER->id == $userid && !empty($USER->policyagreed);
5bf7f59a 281 if (!is_siteadmin() && ($hasagreedsignupuser || $hasagreedloggeduser)) {
6109f234
SA
282 $this->redirect_to_previous_url();
283 }
284
285 $myparams = [];
286 if (!empty($USER->id) && !empty($this->behalfid) && $this->behalfid != $USER->id) {
287 $myparams['userid'] = $this->behalfid;
288 }
289 $myurl = new moodle_url('/admin/tool/policy/index.php', $myparams);
290
291 // Redirect to policy docs before the consent page.
292 $this->redirect_to_policies($userid, $myurl);
293
294 // Page setup.
295 $PAGE->set_context(context_system::instance());
6109f234
SA
296 $PAGE->set_url($myurl);
297 $PAGE->set_heading($SITE->fullname);
298 $PAGE->set_title(get_string('policiesagreements', 'tool_policy'));
299 $PAGE->navbar->add(get_string('policiesagreements', 'tool_policy'), new moodle_url('/admin/tool/policy/index.php'));
300 }
301
302 /**
303 * Prepare user acceptances.
304 *
305 * @param int $userid
306 */
307 protected function prepare_user_acceptances($userid) {
308 global $USER;
309
310 // Get all the policy version acceptances for this user.
311 $acceptances = api::get_user_acceptances($userid);
312 $lang = current_language();
313 foreach ($this->policies as $policy) {
314 // Get a link to display the full policy document.
315 $policy->url = new moodle_url('/admin/tool/policy/view.php',
316 array('policyid' => $policy->policyid, 'returnurl' => qualified_me()));
317 $policyattributes = array('data-action' => 'view',
318 'data-versionid' => $policy->id,
319 'data-behalfid' => $this->behalfid);
320 $policymodal = html_writer::link($policy->url, $policy->name, $policyattributes);
321
322 // Check if this policy version has been agreed or not.
323 if (!empty($userid)) {
324 // Existing user.
325 $versionagreed = false;
326 $policy->versionacceptance = api::get_user_version_acceptance($userid, $policy->id, $acceptances);
327 if (!empty($policy->versionacceptance)) {
328 // The policy version has ever been agreed. Check if status = 1 to know if still is accepted.
329 $versionagreed = $policy->versionacceptance->status;
330 if ($versionagreed) {
331 if ($policy->versionacceptance->lang != $lang) {
332 // Add a message because this version has been accepted in a different language than the current one.
333 $policy->versionlangsagreed = get_string('policyversionacceptedinotherlang', 'tool_policy');
334 }
335 if ($policy->versionacceptance->usermodified != $userid && $USER->id == $userid) {
336 // Add a message because this version has been accepted in behalf of current user.
337 $policy->versionbehalfsagreed = get_string('policyversionacceptedinbehalf', 'tool_policy');
338 }
339 }
340 }
341 } else {
342 // New user.
343 $versionagreed = in_array($policy->id, $this->agreedocs);
344 }
345 $policy->versionagreed = $versionagreed;
346 $policy->policylink = html_writer::link($policy->url, $policy->name);
347 $policy->policymodal = $policymodal;
348 }
349 }
350
351 /**
352 * Export the page data for the mustache template.
353 *
354 * @param renderer_base $output renderer to be used to render the page elements.
355 * @return stdClass
356 */
357 public function export_for_template(renderer_base $output) {
358 global $USER;
359
360 $myparams = [];
361 if (!empty($USER->id) && !empty($this->behalfid) && $this->behalfid != $USER->id) {
362 $myparams['userid'] = $this->behalfid;
363 }
364 $data = (object) [
365 'pluginbaseurl' => (new moodle_url('/admin/tool/policy'))->out(false),
366 'myurl' => (new moodle_url('/admin/tool/policy/index.php', $myparams))->out(false),
367 'sesskey' => sesskey(),
368 ];
369
370 if (!empty($this->messages)) {
371 foreach ($this->messages as $message) {
372 switch ($message->type) {
373 case 'error':
374 $data->messages[] = $output->notification($message->text, notification::NOTIFY_ERROR);
375 break;
376
377 case 'success':
378 $data->messages[] = $output->notification($message->text, notification::NOTIFY_SUCCESS);
379 break;
380
381 default:
382 $data->messages[] = $output->notification($message->text, notification::NOTIFY_INFO);
383 break;
384 }
385 }
386 }
387
388 $data->policies = array_values($this->policies);
389
390 // If viewing docs in behalf of other user, get his/her full name and profile link.
391 if (!empty($this->behalfuser)) {
392 $userfullname = fullname($this->behalfuser, has_capability('moodle/site:viewfullnames', \context_system::instance()) ||
393 has_capability('moodle/site:viewfullnames', \context_user::instance($this->behalfid)));
394 $data->behalfuser = html_writer::link(\context_user::instance($this->behalfid)->get_url(), $userfullname);
395 }
396
d5cfbc91
MG
397 // User can cancel accepting policies only if it is a part of signup.
398 $data->cancancel = !isloggedin() || isguestuser();
399
6109f234
SA
400 return $data;
401 }
402
403}