AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Provides {@link tool_policy\output\renderer} class.** @package tool_policy* @category output* @copyright 2018 Sara Arjona <sara@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/namespace tool_policy\output;defined('MOODLE_INTERNAL') || die();use context_system;use core\output\notification;use core\session\manager;use core_user;use html_writer;use moodle_url;use renderable;use renderer_base;use single_button;use templatable;use tool_policy\api;use tool_policy\policy_version;/*** Represents a page for showing all the policy documents which a user has to agree to.** @copyright 2018 Sara Arjona <sara@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class page_agreedocs implements renderable, templatable {/** @var array $policies List of public policies objects with information about the user acceptance. */protected $policies = null;/** @var array List of policy version ids that were displayed to the user to agree with. */protected $listdocs = null;/** @var array $agreedocs List of policy identifiers which the user has agreed using the form. */protected $agreedocs = null;/** @var array $declinedocs List of policy identifiers that the user declined. */protected $declinedocs = null;/** @var string $action Form action to identify when user agreeds policies. */protected $action = null;/** @var int User id who wants to accept this page. */protected $behalfid = null;/** @var object User who wants to accept this page. */protected $behalfuser = null;/** @var boolean True if signup user has agreed to all the policies; false otherwise. */protected $signupuserpolicyagreed = false;/** @var array Info or error messages to show. */protected $messages = [];/** @var bool This is an existing user (rather than non-loggedin/guest). */protected $isexistinguser;/*** Prepare the page for rendering.** @param array $listdocs List of policy version ids that were displayed to the user to agree with.* @param array $agreedocs List of policy version ids that the user actually agreed with.* @param array $declinedocs List of policy version ids that the user declined.* @param int $behalfid The userid to accept the policy versions as (such as child's id).* @param string $action Form action to identify when user agreeds policies.*/public function __construct(array $listdocs, array $agreedocs = [], array $declinedocs = [], $behalfid = 0, $action = null) {global $USER;$realuser = manager::get_realuser();$this->listdocs = $listdocs;$this->agreedocs = $agreedocs;$this->declinedocs = $declinedocs;$this->action = $action;$this->isexistinguser = isloggedin() && !isguestuser();$behalfid = $behalfid ?: $USER->id;if ($realuser->id != $behalfid) {$this->behalfuser = core_user::get_user($behalfid, '*', MUST_EXIST);$this->behalfid = $this->behalfuser->id;}$this->policies = api::list_current_versions(policy_version::AUDIENCE_LOGGEDIN);if (!$this->isexistinguser) {// During the signup, show compulsory policies only.foreach ($this->policies as $ix => $policyversion) {if ($policyversion->optional == policy_version::AGREEMENT_OPTIONAL) {unset($this->policies[$ix]);}}$this->policies = array_values($this->policies);}if (empty($this->behalfid)) {$userid = $USER->id;} else {$userid = $this->behalfid;}$this->accept_and_revoke_policies();$this->prepare_global_page_access($userid);$this->prepare_user_acceptances($userid);}/*** Accept and revoke the policy versions.* The capabilities for accepting/revoking policies are checked into the api functions.**/protected function accept_and_revoke_policies() {global $USER;if ($this->isexistinguser) {// Existing user.if (!empty($this->action) && confirm_sesskey()) {// The form has been sent, update policies acceptances.$lang = current_language();// Accept / revoke policies.$acceptversionids = [];$declineversionids = [];foreach ($this->policies as $policy) {if (in_array($policy->id, $this->listdocs)) {if (in_array($policy->id, $this->agreedocs)) {$acceptversionids[] = $policy->id;} else if (in_array($policy->id, $this->declinedocs)) {$declineversionids[] = $policy->id;} else {// If the policy was displayed but not answered, revoke the eventually given acceptance.api::revoke_acceptance($policy->id, $this->behalfid);}}}api::accept_policies($acceptversionids, $this->behalfid, null, $lang);api::decline_policies($declineversionids, $this->behalfid, null, $lang);// Show a message to let know the user he/she must agree all the policies.if ((count($acceptversionids) + count($declineversionids)) != count($this->policies)) {$message = (object) ['type' => 'error','text' => get_string('mustagreetocontinue', 'tool_policy')];} else {$message = (object) ['type' => 'success','text' => get_string('acceptancessavedsucessfully', 'tool_policy')];}$this->messages[] = $message;} else if (!empty($this->policies) && empty($USER->policyagreed)) {// Inform users they must agree to all policies before continuing.$message = (object) ['type' => 'error','text' => get_string('mustagreetocontinue', 'tool_policy')];$this->messages[] = $message;}} else {// New user.if (!empty($this->action) && confirm_sesskey()) {$currentpolicyversionids = [];$presignupcache = \cache::make('core', 'presignup');$acceptances = $presignupcache->get('tool_policy_policyversionidsagreed');if (!$acceptances) {$acceptances = [];}foreach ($this->policies as $policy) {$currentpolicyversionids[] = $policy->id;if (in_array($policy->id, $this->listdocs)) {if (in_array($policy->id, $this->agreedocs)) {$acceptances[] = $policy->id;} else {$acceptances = array_values(array_diff($acceptances, [$policy->id]));}}}// If the user has accepted all the policies, add it to the session to let continue with the signup process.$this->signupuserpolicyagreed = empty(array_diff($currentpolicyversionids, $acceptances));$presignupcache->set('tool_policy_userpolicyagreed', $this->signupuserpolicyagreed);$presignupcache->set('tool_policy_policyversionidsagreed', $acceptances);} else if (empty($this->policies)) {// There are no policies to agree to. Update the policyagreed value to avoid show empty consent page.\cache::make('core', 'presignup')->set('tool_policy_userpolicyagreed', 1);}if (!empty($this->policies) && !$this->signupuserpolicyagreed) {// During the signup process, inform users they must agree to all policies before continuing.$message = (object) ['type' => 'error','text' => get_string('mustagreetocontinue', 'tool_policy')];$this->messages[] = $message;}}}/*** Before display the consent page, the user has to view all the still-non-accepted policy docs.* This function checks if the non-accepted policy docs have been shown and redirect to them.** @param int $userid User identifier who wants to access to the consent page.* @param moodle_url $returnurl URL to return after shown the policy docs.*/protected function redirect_to_policies($userid, $returnurl = null) {// Make a list of all policies that the user has not answered yet.$allpolicies = $this->policies;if ($this->isexistinguser) {$acceptances = api::get_user_acceptances($userid);foreach ($allpolicies as $ix => $policy) {$isaccepted = api::is_user_version_accepted($userid, $policy->id, $acceptances);if ($isaccepted) {// The user has accepted this policy, do not show it again.unset($allpolicies[$ix]);} else if ($isaccepted === false && $policy->optional == policy_version::AGREEMENT_OPTIONAL) {// The user declined this policy but the agreement was optional, do not show it.unset($allpolicies[$ix]);} else {// The user has not answered the policy yet, or the agreement is compulsory. Show it.continue;}}} else {$presignupcache = \cache::make('core', 'presignup');$acceptances = $presignupcache->get('tool_policy_policyversionidsagreed');if ($acceptances) {foreach ($allpolicies as $ix => $policy) {if (in_array($policy->id, $acceptances)) {unset($allpolicies[$ix]);}}}}if (!empty($allpolicies)) {// Check if some of the to-be-accepted policies should be agreed on their own page.foreach ($allpolicies as $policy) {if ($policy->agreementstyle == policy_version::AGREEMENTSTYLE_OWNPAGE) {if (empty($returnurl)) {$returnurl = (new moodle_url('/admin/tool/policy/index.php'))->out_as_local_url(false);}$urlparams = ['versionid' => $policy->id, 'returnurl' => $returnurl];redirect(new moodle_url('/admin/tool/policy/view.php', $urlparams));}}$currentpolicyversionids = [];foreach ($allpolicies as $policy) {$currentpolicyversionids[] = $policy->id;}$cache = \cache::make('core', 'presignup');$cachekey = 'tool_policy_viewedpolicies';$viewedpolicies = $cache->get($cachekey) ?: [];if (!empty($viewedpolicies)) {// Get the list of the policies docs which the user haven't viewed during this session.$pendingpolicies = array_diff($currentpolicyversionids, $viewedpolicies);} else {$pendingpolicies = $currentpolicyversionids;}if (count($pendingpolicies) > 0) {// Still is needed to show some policies docs. Save in the session and redirect.$policyversionid = array_shift($pendingpolicies);$viewedpolicies[] = $policyversionid;$cache->set($cachekey, $viewedpolicies);if (empty($returnurl)) {$returnurl = new moodle_url('/admin/tool/policy/index.php');}$urlparams = ['versionid' => $policyversionid,'returnurl' => $returnurl,'numpolicy' => count($currentpolicyversionids) - count($pendingpolicies),'totalpolicies' => count($currentpolicyversionids),];redirect(new moodle_url('/admin/tool/policy/view.php', $urlparams));}} else {// Update the policyagreed for the user to avoid infinite loop because there are no policies to-be-accepted.api::update_policyagreed($userid);$this->redirect_to_previous_url();}}/*** Redirect to signup page if defined or to $CFG->wwwroot if not.*/protected function redirect_to_previous_url() {global $SESSION;if ($this->isexistinguser) {// Existing user.if (!empty($SESSION->wantsurl)) {$returnurl = $SESSION->wantsurl;unset($SESSION->wantsurl);} else {$returnurl = new moodle_url('/admin/tool/policy/user.php');}} else {// Non-authenticated user.$issignup = \cache::make('core', 'presignup')->get('tool_policy_issignup');if ($issignup) {// User came here from signup page - redirect back there.$returnurl = new moodle_url('/login/signup.php');\cache::make('core', 'presignup')->set('tool_policy_issignup', false);} else {// Guests should not be on this page unless it's part of signup - redirect home.$returnurl = new moodle_url('/');}}redirect($returnurl);}/*** Sets up the global $PAGE and performs the access checks.** @param int $userid*/protected function prepare_global_page_access($userid) {global $PAGE, $SITE, $USER;// Guest users or not logged users (but the users during the signup process) are not allowed to access to this page.$newsignupuser = \cache::make('core', 'presignup')->get('tool_policy_issignup');if (!$this->isexistinguser && !$newsignupuser) {$this->redirect_to_previous_url();}// Check for correct user capabilities.if ($this->isexistinguser) {// For existing users, it's needed to check if they have the capability for accepting policies.api::can_accept_policies($this->listdocs, $this->behalfid, true);} else {// For new users, the behalfid parameter is ignored.if ($this->behalfid) {redirect(new moodle_url('/admin/tool/policy/index.php'));}}// If the current user has the $USER->policyagreed = 1 or $userpolicyagreed = 1// redirect to the return page.$hasagreedsignupuser = !$this->isexistinguser && $this->signupuserpolicyagreed;$hasagreedloggeduser = $USER->id == $userid && !empty($USER->policyagreed);if (!is_siteadmin() && ($hasagreedsignupuser || $hasagreedloggeduser)) {$this->redirect_to_previous_url();}$myparams = [];if ($this->isexistinguser && !empty($this->behalfid) && $this->behalfid != $USER->id) {$myparams['userid'] = $this->behalfid;}$myurl = new moodle_url('/admin/tool/policy/index.php', $myparams);// Redirect to policy docs before the consent page.$this->redirect_to_policies($userid, $myurl);// Page setup.$PAGE->set_context(context_system::instance());$PAGE->set_url($myurl);$PAGE->set_heading($SITE->fullname);$PAGE->set_title(get_string('policiesagreements', 'tool_policy'));$PAGE->navbar->add(get_string('policiesagreements', 'tool_policy'), new moodle_url('/admin/tool/policy/index.php'));}/*** Prepare user acceptances.** @param int $userid*/protected function prepare_user_acceptances($userid) {global $USER;// Get all the policy version acceptances for this user.$lang = current_language();foreach ($this->policies as $policy) {// Get a link to display the full policy document.$policy->url = new moodle_url('/admin/tool/policy/view.php',array('policyid' => $policy->policyid, 'returnurl' => qualified_me()));$policyattributes = array('data-action' => 'view','data-versionid' => $policy->id,'data-behalfid' => $this->behalfid);$policymodal = html_writer::link($policy->url, $policy->name, $policyattributes);// Check if this policy version has been agreed or not.if ($this->isexistinguser) {// Existing user.$versionagreed = false;$versiondeclined = false;$acceptances = api::get_user_acceptances($userid);$policy->versionacceptance = api::get_user_version_acceptance($userid, $policy->id, $acceptances);if (!empty($policy->versionacceptance)) {// The policy version has ever been replied to before. Check if status = 1 to know if still is accepted.if ($policy->versionacceptance->status) {$versionagreed = true;} else {$versiondeclined = true;}if ($versionagreed) {if ($policy->versionacceptance->lang != $lang) {// Add a message because this version has been accepted in a different language than the current one.$policy->versionlangsagreed = get_string('policyversionacceptedinotherlang', 'tool_policy');}$usermodified = $policy->versionacceptance->usermodified;if ($usermodified && $usermodified != $userid && $USER->id == $userid) {// Add a message because this version has been accepted on behalf of current user.$policy->versionbehalfsagreed = get_string('policyversionacceptedinbehalf', 'tool_policy');}}}} else {// New user.$versionagreed = in_array($policy->id, $this->agreedocs);$versiondeclined = false;}$policy->versionagreed = $versionagreed;$policy->versiondeclined = $versiondeclined;$policy->policylink = html_writer::link($policy->url, $policy->name);$policy->policymodal = $policymodal;}}/*** Export the page data for the mustache template.** @param renderer_base $output renderer to be used to render the page elements.* @return \stdClass*/public function export_for_template(renderer_base $output) {global $USER;$myparams = [];if ($this->isexistinguser && !empty($this->behalfid) && $this->behalfid != $USER->id) {$myparams['userid'] = $this->behalfid;}$data = (object) ['pluginbaseurl' => (new moodle_url('/admin/tool/policy'))->out(false),'myurl' => (new moodle_url('/admin/tool/policy/index.php', $myparams))->out(false),'sesskey' => sesskey(),];if (!empty($this->messages)) {foreach ($this->messages as $message) {switch ($message->type) {case 'error':$data->messages[] = $output->notification($message->text, notification::NOTIFY_ERROR);break;case 'success':$data->messages[] = $output->notification($message->text, notification::NOTIFY_SUCCESS);break;default:$data->messages[] = $output->notification($message->text, notification::NOTIFY_INFO);break;}}}// Filter out policies already shown on their own page, keep just policies to be shown here on the consent page.$data->policies = array_values(array_filter($this->policies, function ($policy) {return $policy->agreementstyle == policy_version::AGREEMENTSTYLE_CONSENTPAGE;}));// If viewing docs in behalf of other user, get his/her full name and profile link.if (!empty($this->behalfuser)) {$userfullname = fullname($this->behalfuser, has_capability('moodle/site:viewfullnames', \context_system::instance()) ||has_capability('moodle/site:viewfullnames', \context_user::instance($this->behalfid)));$data->behalfuser = html_writer::link(\context_user::instance($this->behalfid)->get_url(), $userfullname);}// User can cancel accepting policies only if it is a part of signup.$data->cancancel = !isloggedin() || isguestuser();return $data;}}