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 * Plugin version and other meta-data are defined here.
19 *
20 * @package     tool_policy
21 * @copyright   2018 David Mudrák <david@moodle.com>
22 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die();
26
27use core_user\output\myprofile\tree;
28use tool_policy\api;
29use tool_policy\policy_version;
30
31/**
32 * Add nodes to myprofile page.
33 *
34 * @param tree $tree Tree object
35 * @param stdClass $user User object
36 * @param bool $iscurrentuser
37 * @param stdClass $course Course object
38 * @return bool
39 * @throws coding_exception
40 * @throws dml_exception
41 * @throws moodle_exception
42 */
43function tool_policy_myprofile_navigation(tree $tree, $user, $iscurrentuser, $course) {
44    global $CFG;
45
46    // Do nothing if we are not set as the site policies handler.
47    if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
48        return;
49    }
50
51    // Get the Privacy and policies category.
52    if (!array_key_exists('privacyandpolicies', $tree->__get('categories'))) {
53        // Create the category.
54        $categoryname = get_string('privacyandpolicies', 'admin');
55        $category = new core_user\output\myprofile\category('privacyandpolicies', $categoryname, 'contact');
56        $tree->add_category($category);
57    } else {
58        // Get the existing category.
59        $category = $tree->__get('categories')['privacyandpolicies'];
60    }
61
62    // Add "Policies and agreements" node only for current user or users who can accept on behalf of current user.
63    $usercontext = \context_user::instance($user->id);
64    if ($iscurrentuser || has_capability('tool/policy:acceptbehalf', $usercontext)) {
65        $url = new moodle_url('/admin/tool/policy/user.php', ['userid' => $user->id]);
66        $node = new core_user\output\myprofile\node('privacyandpolicies', 'tool_policy',
67            get_string('policiesagreements', 'tool_policy'), null, $url);
68        $category->add_node($node);
69    }
70
71    return true;
72}
73
74/**
75 * Load policy message for guests.
76 *
77 * @return string The HTML code to insert before the head.
78 */
79function tool_policy_before_standard_html_head() {
80    global $CFG, $PAGE, $USER;
81
82    $message = null;
83    if (!empty($CFG->sitepolicyhandler)
84            && $CFG->sitepolicyhandler == 'tool_policy'
85            && empty($USER->policyagreed)
86            && (isguestuser() || !isloggedin())) {
87        $output = $PAGE->get_renderer('tool_policy');
88        try {
89            $page = new \tool_policy\output\guestconsent();
90            $message = $output->render($page);
91        } catch (dml_read_exception $e) {
92            // During upgrades, the new plugin code with new SQL could be in place but the DB not upgraded yet.
93            $message = null;
94        }
95    }
96
97    return $message;
98}
99
100/**
101 * Callback to add footer elements.
102 *
103 * @return string HTML footer content
104 */
105function tool_policy_standard_footer_html() {
106    global $CFG, $PAGE;
107
108    $output = '';
109    if (!empty($CFG->sitepolicyhandler)
110            && $CFG->sitepolicyhandler == 'tool_policy') {
111        $policies = api::get_current_versions_ids();
112        if (!empty($policies)) {
113            $url = new moodle_url('/admin/tool/policy/viewall.php', ['returnurl' => $PAGE->url]);
114            $output .= html_writer::link($url, get_string('userpolicysettings', 'tool_policy'));
115            $output = html_writer::div($output, 'policiesfooter');
116        }
117    }
118
119    return $output;
120}
121
122/**
123 * Hooks redirection to policy acceptance pages before sign up.
124 */
125function tool_policy_pre_signup_requests() {
126    global $CFG;
127
128    // Do nothing if we are not set as the site policies handler.
129    if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
130        return;
131    }
132
133    $policies = api::get_current_versions_ids(policy_version::AUDIENCE_LOGGEDIN);
134    $userpolicyagreed = cache::make('core', 'presignup')->get('tool_policy_userpolicyagreed');
135    if (!empty($policies) && !$userpolicyagreed) {
136        // Redirect to "Policy" pages for consenting before creating the user.
137        cache::make('core', 'presignup')->set('tool_policy_issignup', 1);
138        redirect(new \moodle_url('/admin/tool/policy/index.php'));
139    }
140}
141
142/**
143 * Serve the embedded files.
144 *
145 * @param stdClass $course the course object
146 * @param stdClass $cm the course module object
147 * @param stdClass $context the context
148 * @param string $filearea the name of the file area
149 * @param array $args extra arguments (itemid, path)
150 * @param bool $forcedownload whether or not force download
151 * @param array $options additional options affecting the file serving
152 * @return bool false if the file not found, just send the file otherwise and do not return anything
153 */
154function tool_policy_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
155    global $CFG, $PAGE;
156
157    // Do not allow access to files if we are not set as the site policy handler.
158    if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
159        return false;
160    }
161
162    if ($context->contextlevel != CONTEXT_SYSTEM) {
163        return false;
164    }
165
166    $PAGE->set_context($context);
167
168    if ($filearea !== 'policydocumentsummary' && $filearea !== 'policydocumentcontent') {
169        return false;
170    }
171
172    $itemid = array_shift($args);
173
174    $policy = api::get_policy_version($itemid);
175
176    if ($policy->status != policy_version::STATUS_ACTIVE) {
177        require_login();
178    }
179
180    if (!api::can_user_view_policy_version($policy)) {
181        return false;
182    }
183
184    $filename = array_pop($args);
185
186    if (!$args) {
187        $filepath = '/';
188    } else {
189        $filepath = '/'.implode('/', $args).'/';
190    }
191
192    $fs = get_file_storage();
193    $file = $fs->get_file($context->id, 'tool_policy', $filearea, $itemid, $filepath, $filename);
194
195    if (!$file) {
196        return false;
197    }
198
199    send_stored_file($file, null, 0, $forcedownload, $options);
200}
201
202/**
203 * Map icons for font-awesome themes.
204 */
205function tool_policy_get_fontawesome_icon_map() {
206    return [
207        'tool_policy:agreed' => 'fa-check text-success',
208        'tool_policy:declined' => 'fa-times text-danger',
209        'tool_policy:pending' => 'fa-clock-o text-warning',
210        'tool_policy:partial' => 'fa-exclamation-triangle text-warning',
211        'tool_policy:level' => 'fa-level-up fa-rotate-90 text-muted',
212    ];
213}
214
215/**
216 * Serve the new group form as a fragment.
217 *
218 * @param array $args List of named arguments for the fragment loader.
219 * @return string
220 */
221function tool_policy_output_fragment_accept_on_behalf($args) {
222    $args = (object) $args;
223
224    $data = [];
225    if (!empty($args->jsonformdata)) {
226        $serialiseddata = json_decode($args->jsonformdata);
227        parse_str($serialiseddata, $data);
228    }
229
230    $mform = new \tool_policy\form\accept_policy(null, $data);
231
232    if (!empty($args->jsonformdata)) {
233        // If we were passed non-empty form data we want the mform to call validation functions and show errors.
234        $mform->is_validated();
235    }
236
237    return $mform->render();
238}