63 |
{{{name}}}
64 |
65 |
66 | {{{summary}}}
67 |
68 |
69 | {{# str }}refertofullpolicytext, tool_policy, {{{policymodal}}} {{/ str }}
70 |
71 |
90 |
91 |
92 | {{/policies}}
93 |
94 | {{#privacyofficer}}
95 |
96 | {{{.}}}
97 |
98 | {{/privacyofficer}}
99 |
100 | {{# str }}somefieldsrequired, form,
{{/ str }}
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | {{#js}}
109 | // Initialise the JS for the modal window which displays the policy versions.
110 | require(['tool_policy/policyactions'], function(ActionsMod) {
111 | var policyActions = new ActionsMod();
112 | });
113 | {{/js}}
114 |
--------------------------------------------------------------------------------
/classes/event/acceptance_created.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\event\acceptance_created} class.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy\event;
26 |
27 | use core\event\base;
28 |
29 | defined('MOODLE_INTERNAL') || die();
30 |
31 | /**
32 | * Event acceptance_created
33 | *
34 | * @package tool_policy
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class acceptance_created extends base {
39 |
40 | /**
41 | * Initialise the event.
42 | */
43 | protected function init() {
44 | $this->data['objecttable'] = 'tool_policy_acceptances';
45 | $this->data['crud'] = 'c';
46 | $this->data['edulevel'] = self::LEVEL_OTHER;
47 | }
48 |
49 | /**
50 | * Create event from record.
51 | *
52 | * @param stdClass $record
53 | * @return tool_policy\event\acceptance_created
54 | */
55 | public static function create_from_record($record) {
56 | $event = static::create([
57 | 'objectid' => $record->id,
58 | 'relateduserid' => $record->userid,
59 | 'context' => \context_user::instance($record->userid), // TODO or system?
60 | 'other' => [
61 | 'policyversionid' => $record->policyversionid,
62 | 'note' => $record->note,
63 | 'status' => $record->status,
64 | ],
65 | ]);
66 | $event->add_record_snapshot($event->objecttable, $record);
67 | return $event;
68 | }
69 |
70 | /**
71 | * Returns event name.
72 | *
73 | * @return string
74 | */
75 | public static function get_name() {
76 | return get_string('event_acceptance_created', 'tool_policy');
77 | }
78 |
79 | /**
80 | * Get the event description.
81 | *
82 | * @return string
83 | */
84 | public function get_description() {
85 | if ($this->other['status'] == 1) {
86 | $action = 'added consent to';
87 | } else if ($this->other['status'] == -1) {
88 | $action = 'revoked consent to';
89 | } else {
90 | $action = 'created an empty consent record for';
91 | }
92 | return "The user with id '{$this->userid}' $action the policy with revision {$this->other['policyversionid']} ".
93 | "for the user with id '{$this->relateduserid}'";
94 | }
95 |
96 | /**
97 | * Get URL related to the action
98 | *
99 | * @return \moodle_url
100 | */
101 | public function get_url() {
102 | return new \moodle_url('/admin/tool/policy/acceptance.php', array('userid' => $this->relateduserid,
103 | 'versionid' => $this->other['policyversionid']));
104 | }
105 |
106 | /**
107 | * Get the object ID mapping.
108 | *
109 | * @return array
110 | */
111 | public static function get_objectid_mapping() {
112 | return array('db' => 'tool_policy', 'restore' => \core\event\base::NOT_MAPPED);
113 | }
114 |
115 | /**
116 | * Custom validation.
117 | *
118 | * @throws \coding_exception
119 | */
120 | protected function validate_data() {
121 | parent::validate_data();
122 |
123 | if (empty($this->other['policyversionid'])) {
124 | throw new \coding_exception('The \'policyversionid\' value must be set');
125 | }
126 |
127 | if (!isset($this->other['status'])) {
128 | throw new \coding_exception('The \'status\' value must be set');
129 | }
130 |
131 | if (empty($this->relateduserid)) {
132 | throw new \coding_exception('The \'relateduserid\' must be set.');
133 | }
134 | }
135 |
136 | /**
137 | * No mapping required for this event because this event is not backed up.
138 | *
139 | * @return bool
140 | */
141 | public static function get_other_mapping() {
142 | return false;
143 | }
144 | }
--------------------------------------------------------------------------------
/classes/policy_version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides the {@link tool_policy\policy_version} persistent.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 Sara Arjona (sara@moodle.com)
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use core\persistent;
30 |
31 | /**
32 | * Persistent model representing a single policy document version.
33 | *
34 | * @copyright 2018 Sara Arjona (sara@moodle.com)
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 | */
37 | class policy_version extends persistent {
38 |
39 | /** @var string Table name this persistent is mapped to. */
40 | const TABLE = 'tool_policy_versions';
41 |
42 | /** @var int Site policy document. */
43 | const TYPE_SITE = 0;
44 |
45 | /** @var int Privacy policy document. */
46 | const TYPE_PRIVACY = 1;
47 |
48 | /** @var int Third party policy document. */
49 | const TYPE_THIRD_PARTY = 2;
50 |
51 | /** @var int Other policy document. */
52 | const TYPE_OTHER = 99;
53 |
54 | /** @var int Policy applies to all users. */
55 | const AUDIENCE_ALL = 0;
56 |
57 | /** @var int Policy applies to logged in users only. */
58 | const AUDIENCE_LOGGEDIN = 1;
59 |
60 | /** @var int Policy applies to guests only. */
61 | const AUDIENCE_GUESTS = 2;
62 |
63 | /** @var int Policy version is a draft. */
64 | const STATUS_DRAFT = 0;
65 |
66 | /** @var int Policy version is the active one. */
67 | const STATUS_ACTIVE = 1;
68 |
69 | /** @var int Policy version has been archived. */
70 | const STATUS_ARCHIVED = 2;
71 |
72 | /**
73 | * Return the definition of the properties of this model.
74 | *
75 | * @return array
76 | */
77 | protected static function define_properties() {
78 | return [
79 | 'name' => [
80 | 'type' => PARAM_TEXT,
81 | 'default' => '',
82 | ],
83 | 'type' => [
84 | 'type' => PARAM_INT,
85 | 'choices' => [
86 | self::TYPE_SITE,
87 | self::TYPE_PRIVACY,
88 | self::TYPE_THIRD_PARTY,
89 | self::TYPE_OTHER,
90 | ],
91 | 'default' => self::TYPE_SITE,
92 | ],
93 | 'audience' => [
94 | 'type' => PARAM_INT,
95 | 'choices' => [
96 | self::AUDIENCE_ALL,
97 | self::AUDIENCE_LOGGEDIN,
98 | self::AUDIENCE_GUESTS,
99 | ],
100 | 'default' => self::AUDIENCE_ALL,
101 | ],
102 | 'archived' => [
103 | 'type' => PARAM_BOOL,
104 | 'default' => false,
105 | ],
106 | 'policyid' => [
107 | 'type' => PARAM_INT,
108 | ],
109 | 'revision' => [
110 | 'type' => PARAM_TEXT,
111 | 'default' => '',
112 | ],
113 | 'summary' => [
114 | 'type' => PARAM_RAW,
115 | 'default' => '',
116 | ],
117 | 'summaryformat' => [
118 | 'type' => PARAM_INT,
119 | 'default' => FORMAT_HTML,
120 | 'choices' => [
121 | FORMAT_PLAIN,
122 | FORMAT_HTML,
123 | FORMAT_MOODLE,
124 | FORMAT_MARKDOWN,
125 | ],
126 | ],
127 | 'content' => [
128 | 'type' => PARAM_RAW,
129 | 'default' => '',
130 | ],
131 | 'contentformat' => [
132 | 'type' => PARAM_INT,
133 | 'default' => FORMAT_HTML,
134 | 'choices' => [
135 | FORMAT_PLAIN,
136 | FORMAT_HTML,
137 | FORMAT_MOODLE,
138 | FORMAT_MARKDOWN,
139 | ],
140 | ],
141 | ];
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/templates/acceptances.mustache:
--------------------------------------------------------------------------------
1 | {{!
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
.
16 | }}
17 | {{!
18 | @template tool_policy/acceptances
19 |
20 | Template for the user acceptances page.
21 |
22 | Classes required for JS:
23 | -
24 |
25 | Data attributes required for JS:
26 | -
27 |
28 | Context variables required for this template:
29 | * policies
30 |
31 | Example context (json):
32 | {
33 | "policies": [
34 | {
35 | "versions": [
36 | {
37 | "isfirst": true,
38 | "policyid": 1,
39 | "viewurl": "/",
40 | "name": "Terms & conditions",
41 | "revision": "1.0-beta",
42 | "hasonbehalfagreements": true,
43 | "acceptedby": "
John Smith ",
44 | "note": "Based on parent's agreement via email",
45 | "hasarchived": false
46 | }
47 | ]
48 | }
49 | ]
50 | }
51 | }}
52 |
53 |
54 |
55 | {{#str}} policydocname, tool_policy {{/str}}
56 | {{#str}} policydocrevision, tool_policy {{/str}}
57 | {{#str}} agreed, tool_policy {{/str}}
58 | {{#str}} agreedon, tool_policy {{/str}}
59 | {{#hasonbehalfagreements}}
60 | {{#str}} agreedby, tool_policy {{/str}}
61 | {{#str}} acceptancenote, tool_policy {{/str}}
62 | {{/hasonbehalfagreements}}
63 |
64 |
65 |
66 |
67 | {{#policies}}
68 | {{#versions}}
69 |
70 |
71 | {{^isfirst}}
72 |
73 | {{#pix}} level, tool_policy {{/pix}}
74 |
75 | {{/isfirst}}
76 |
79 |
80 |
81 | {{{revision}}}
82 | {{#iscurrent}}{{#pix}} t/check, core {{/pix}}{{/iscurrent}}
83 |
84 |
85 | {{#agreement}}
86 | {{>tool_policy/user_agreement}}
87 | {{/agreement}}
88 |
89 |
90 | {{timeaccepted}}
91 | {{#hasonbehalfagreements}}
92 | {{{acceptedby}}}
93 | {{{note}}}
94 | {{/hasonbehalfagreements}}
95 |
96 | {{#hasarchived}}
97 | {{#pix}}t/less, moodle, {{#str}}detailedless, moodle{{/str}}{{/pix}}
98 | {{#pix}}t/more, moodle, {{#str}}detailedmore, moodle{{/str}}{{/pix}}
99 | {{/hasarchived}}
100 |
101 |
102 | {{/versions}}
103 | {{/policies}}
104 |
105 |
106 | {{#js}}
107 | require(['jquery'], function($) {
108 | $('body').on('click', '.showarchived', function(e) {
109 | e.preventDefault();
110 | var target = $(this).attr('data-target'),
111 | status = $(this).attr('data-status');
112 | if (status === 'hidden') {
113 | $(target).show();
114 | $(this).attr('data-status', 'shown')
115 | $(this).find('.toggleoff').show();
116 | $(this).find('.toggleon').hide();
117 | } else {
118 | $(target).hide();
119 | $(this).attr('data-status', 'hidden');
120 | $(this).find('.toggleon').show();
121 | $(this).find('.toggleoff').hide();
122 | }
123 | });
124 | });
125 | {{/js}}
126 |
--------------------------------------------------------------------------------
/classes/event/acceptance_updated.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\event\acceptance_updated} class.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy\event;
26 |
27 | use core\event\base;
28 |
29 | defined('MOODLE_INTERNAL') || die();
30 |
31 | /**
32 | * Event acceptance_updated
33 | *
34 | * @package tool_policy
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class acceptance_updated extends base {
39 |
40 | /**
41 | * Initialise the event.
42 | */
43 | protected function init() {
44 | $this->data['objecttable'] = 'tool_policy_acceptances';
45 | $this->data['crud'] = 'u';
46 | $this->data['edulevel'] = self::LEVEL_OTHER;
47 | }
48 |
49 | /**
50 | * Create event from record.
51 | *
52 | * @param stdClass $record
53 | * @return tool_policy\event\acceptance_updated
54 | */
55 | public static function create_from_record($record) {
56 | $event = static::create([
57 | 'objectid' => $record->id,
58 | 'relateduserid' => $record->userid,
59 | 'context' => \context_user::instance($record->userid), // TODO or system?
60 | 'other' => [
61 | 'policyversionid' => $record->policyversionid,
62 | 'note' => $record->note,
63 | 'status' => $record->status,
64 | ],
65 | ]);
66 | $event->add_record_snapshot($event->objecttable, $record);
67 | return $event;
68 | }
69 |
70 | /**
71 | * Returns event name.
72 | *
73 | * @return string
74 | */
75 | public static function get_name() {
76 | return get_string('event_acceptance_updated', 'tool_policy');
77 | }
78 |
79 | /**
80 | * Get the event description.
81 | *
82 | * @return string
83 | */
84 | public function get_description() {
85 | if ($this->other['status'] == 1) {
86 | $action = 'added consent to';
87 | } else if ($this->other['status'] == -1) {
88 | $action = 'revoked consent to';
89 | } else {
90 | $action = 'updated consent to';
91 | }
92 | return "The user with id '{$this->userid}' $action the policy with revision {$this->other['policyversionid']} ".
93 | "for the user with id '{$this->relateduserid}'";
94 | }
95 |
96 | /**
97 | * Get URL related to the action
98 | *
99 | * @return \moodle_url
100 | */
101 | public function get_url() {
102 | return new \moodle_url('/admin/tool/policy/acceptance.php', array('userid' => $this->relateduserid,
103 | 'versionid' => $this->other['policyversionid']));
104 | }
105 |
106 | /**
107 | * Get the object ID mapping.
108 | *
109 | * @return array
110 | */
111 | public static function get_objectid_mapping() {
112 | return array('db' => 'tool_policy', 'restore' => \core\event\base::NOT_MAPPED);
113 | }
114 |
115 | /**
116 | * Custom validation.
117 | *
118 | * @throws \coding_exception
119 | */
120 | protected function validate_data() {
121 | parent::validate_data();
122 |
123 | if (empty($this->other['policyversionid'])) {
124 | throw new \coding_exception('The \'policyversionid\' value must be set');
125 | }
126 |
127 | if (!isset($this->other['status'])) {
128 | throw new \coding_exception('The \'status\' value must be set');
129 | }
130 |
131 | if (empty($this->relateduserid)) {
132 | throw new \coding_exception('The \'relateduserid\' must be set.');
133 | }
134 | }
135 |
136 | /**
137 | * No mapping required for this event because this event is not backed up.
138 | *
139 | * @return bool
140 | */
141 | public static function get_other_mapping() {
142 | // No mapping required for this event because this event is not backed up.
143 | return false;
144 | }
145 | }
--------------------------------------------------------------------------------
/classes/privacy/local/sitepolicy/handler.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Site policy handler class.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 Sara Arjona
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy\privacy\local\sitepolicy;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use tool_policy\api;
30 | use tool_policy\policy_version;
31 |
32 | /**
33 | * Class implementation for a site policy handler.
34 | *
35 | * @package tool_policy
36 | * @copyright 2018 Sara Arjona
37 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 | */
39 | class handler extends \core_privacy\local\sitepolicy\handler {
40 |
41 | /**
42 | * Returns URL to redirect user to when user needs to agree to site policy
43 | *
44 | * This is a regular interactive page for web users. It should have normal Moodle header/footers, it should
45 | * allow user to view policies and accept them.
46 | *
47 | * @param bool $forguests
48 | * @return moodle_url|null (returns null if site policy is not defined)
49 | */
50 | public static function get_redirect_url($forguests = false) {
51 | // There is no redirect for guests, policies are shown in the popup, only return redirect url for the logged in users.
52 | if (!$forguests && api::get_current_versions_ids(policy_version::AUDIENCE_LOGGEDIN)) {
53 | return new \moodle_url('/admin/tool/policy/index.php');
54 | }
55 | return null;
56 | }
57 |
58 | /**
59 | * Returns URL of the site policy that needs to be displayed to the user (inside iframe or to use in WS such as mobile app)
60 | *
61 | * This page should not have any header/footer, it does not also have any buttons/checkboxes. The caller needs to implement
62 | * the "Accept" button and call {@link self::accept()} on completion.
63 | *
64 | * @param bool $forguests
65 | * @return moodle_url|null
66 | */
67 | public static function get_embed_url($forguests = false) {
68 | if (api::get_current_versions_ids($forguests ? policy_version::AUDIENCE_GUESTS : policy_version::AUDIENCE_LOGGEDIN)) {
69 | return new \moodle_url('/admin/tool/policy/viewall.php');
70 | }
71 | return null;
72 | }
73 |
74 | /**
75 | * Accept site policy for the current user
76 | *
77 | * @return bool - false if sitepolicy not defined, user is not logged in or user has already agreed to site policy;
78 | * true - if we have successfully marked the user as agreed to the site policy
79 | */
80 | public static function accept() {
81 | global $USER, $DB;
82 | if (!isloggedin()) {
83 | return false;
84 | }
85 | if ($USER->policyagreed) {
86 | return false;
87 | }
88 |
89 | if (!isguestuser()) {
90 | // Accepts all policies with a current version for logged users on behalf of the current user.
91 | if (!$versions = api::get_current_versions_ids(policy_version::AUDIENCE_LOGGEDIN)) {
92 | return false;
93 | }
94 | api::accept_policies(array_values($versions));
95 | }
96 |
97 | if (!isguestuser()) {
98 | // For the guests agreement in stored in session only, for other users - in DB.
99 | $DB->set_field('user', 'policyagreed', 1, array('id' => $USER->id));
100 | }
101 | $USER->policyagreed = 1;
102 | return true;
103 | }
104 |
105 | /**
106 | * Adds "Agree to site policy" checkbox to the signup form.
107 | *
108 | * @param \MoodleQuickForm $mform
109 | */
110 | public static function signup_form($mform) {
111 | if (static::is_defined()) {
112 | // This plugin displays policies to the user who is signing up before the signup form is shown.
113 | // By the time user has access to signup form they have already agreed to the policies.
114 | $mform->addElement('hidden', 'policyagreed', 1);
115 | $mform->setType('policyagreed', PARAM_INT);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/tests/behat/behat_tool_policy.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Step definition for tool_policy
19 | *
20 | * @package tool_policy
21 | * @category test
22 | * @copyright 2018 Marina Glancy
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
27 |
28 | use Behat\Gherkin\Node\TableNode as TableNode;
29 |
30 | /**
31 | * Step definition for tool_policy
32 | *
33 | * @package tool_policy
34 | * @category test
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class behat_tool_policy extends behat_base {
39 |
40 | /**
41 | * Click on an entry in the edit menu.
42 | *
43 | * @Given /^the following policies exist:$/
44 | *
45 | * @param TableNode $data
46 | */
47 | public function the_following_policies_exist(TableNode $data) {
48 | global $CFG;
49 | if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
50 | throw new Exception('Site policy handler is not set to "tool_policy"');
51 | }
52 |
53 | $fields = [
54 | 'name', // Policy name (required).
55 | 'revision', // Revision name.
56 | 'policy', // Any policy identifier, can be used to generate multiple versions of the same policy.
57 | 'status', // Version status: 'draft', 'active', 'archived'. By default 'active'.
58 | 'audience', // Audience: 'guest', 'all', 'loggedin' (by default 'all').
59 | 'type', // 0 (default) - Site policy, 1 - Privacy policy, 2 - Third party policy, 99 - Other .
60 | 'content',
61 | 'summary',
62 | ];
63 |
64 | // Associative array "policy identifier" => id in the database .
65 | $policies = [];
66 |
67 | foreach ($data->getHash() as $elementdata) {
68 | $data = (object)[
69 | 'audience' => \tool_policy\policy_version::AUDIENCE_ALL,
70 | 'archived' => 0,
71 | 'type' => 0
72 | ];
73 | $policyidentifier = null;
74 | $elementdata = array_change_key_case($elementdata, CASE_LOWER);
75 | foreach ($elementdata as $key => $value) {
76 | if ($key === 'policy') {
77 | if (array_key_exists($value, $policies)) {
78 | $data->policyid = $policies[$value];
79 | }
80 | } else if ($key === 'status') {
81 | $data->archived = ($value === 'archived');
82 | } else if ($key === 'audience') {
83 | if ($value === 'guest') {
84 | $data->audience = \tool_policy\policy_version::AUDIENCE_GUESTS;
85 | } else if ($value === 'loggedin') {
86 | $data->audience = \tool_policy\policy_version::AUDIENCE_LOGGEDIN;
87 | }
88 | } else if (($key === 'summary' || $key === 'content') && !empty($value)) {
89 | $data->{$key.'_editor'} = ['text' => $value, 'format' => FORMAT_MOODLE];
90 | } else if (in_array($key, $fields) && $value !== '') {
91 | $data->$key = $value;
92 | }
93 | }
94 | if (empty($data->name) || empty($data->content_editor) || empty($data->summary_editor)) {
95 | throw new Exception('Policy is missing at least one of the required fields: name, content, summary');
96 | }
97 |
98 | if (!empty($data->policyid)) {
99 | $version = tool_policy\api::form_policydoc_update_new($data);
100 | } else {
101 | $version = \tool_policy\api::form_policydoc_add($data);
102 | }
103 |
104 | if (!empty($elementdata['policy'])) {
105 | $policies[$elementdata['policy']] = $version->get('policyid');
106 | }
107 | if (empty($elementdata['status']) || $elementdata['status'] === 'active') {
108 | \tool_policy\api::make_current($version->get('id'));
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/classes/output/acceptances.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\output\acceptances} class.
19 | *
20 | * @package tool_policy
21 | * @category output
22 | * @copyright 2018 Marina Glancy
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace tool_policy\output;
27 |
28 | use tool_policy\api;
29 |
30 | defined('MOODLE_INTERNAL') || die();
31 |
32 | use moodle_url;
33 | use renderable;
34 | use renderer_base;
35 | use single_button;
36 | use templatable;
37 | use tool_policy\policy_version;
38 |
39 | /**
40 | * List of users and their acceptances
41 | *
42 | * @copyright 2018 Marina Glancy
43 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 | */
45 | class acceptances implements renderable, templatable {
46 |
47 | /** @var id */
48 | protected $userid;
49 |
50 | /**
51 | * Contructor.
52 | *
53 | * @param int $userid
54 | */
55 | public function __construct($userid) {
56 | $this->userid = $userid;
57 | }
58 |
59 | /**
60 | * Export the page data for the mustache template.
61 | *
62 | * @param renderer_base $output renderer to be used to render the page elements.
63 | * @return stdClass
64 | */
65 | public function export_for_template(renderer_base $output) {
66 | global $USER;
67 |
68 | $data = (object)[];
69 | $data->hasonbehalfagreements = false;
70 | $data->pluginbaseurl = (new moodle_url('/admin/tool/policy'))->out(false);
71 |
72 | // Get the list of policies and versions that current user is able to see
73 | // and the respective acceptance records for the selected user.
74 | $policies = api::get_policies_with_acceptances($this->userid);
75 |
76 | $canviewfullnames = has_capability('moodle/site:viewfullnames', \context_system::instance());
77 | foreach ($policies as $policy) {
78 |
79 | foreach ($policy->versions as $version) {
80 | unset($version->summary);
81 | unset($version->content);
82 | $version->iscurrent = ($version->status == policy_version::STATUS_ACTIVE);
83 | $version->name = format_string($version->name);
84 | $version->revision = format_string($version->revision);
85 | $returnurl = new moodle_url('/admin/tool/policy/user.php', ['userid' => $this->userid]);
86 | $version->viewurl = (new moodle_url('/admin/tool/policy/view.php', [
87 | 'policyid' => $policy->id,
88 | 'versionid' => $version->id,
89 | 'returnurl' => $returnurl->out(false),
90 | ]))->out(false);
91 |
92 | if (!empty($version->acceptance->status)) {
93 | $acceptance = $version->acceptance;
94 | $version->timeaccepted = userdate($acceptance->timemodified, get_string('strftimedatetime'));
95 | $onbehalf = $acceptance->usermodified && $acceptance->usermodified != $this->userid;
96 | $version->agreement = new user_agreement($this->userid, 1, $returnurl, $version->id, $onbehalf);
97 | if ($onbehalf) {
98 | $usermodified = (object)['id' => $acceptance->usermodified];
99 | username_load_fields_from_object($usermodified, $acceptance, 'mod');
100 | $profileurl = new \moodle_url('/user/profile.php', array('id' => $usermodified->id));
101 | $version->acceptedby = \html_writer::link($profileurl, fullname($usermodified, $canviewfullnames ||
102 | has_capability('moodle/site:viewfullnames', \context_user::instance($acceptance->usermodified))));
103 | $data->hasonbehalfagreements = true;
104 | }
105 | $version->note = format_text($acceptance->note);
106 | } else if ($version->iscurrent) {
107 | $version->agreement = new user_agreement($this->userid, 0, $returnurl, $version->id);
108 | }
109 | if (isset($version->agreement)) {
110 | $version->agreement = $version->agreement->export_for_template($output);
111 | }
112 | }
113 |
114 | if ($policy->versions[0]->status != policy_version::STATUS_ACTIVE) {
115 | // Add an empty "currentversion" on top.
116 | $policy->versions = [0 => (object)[]] + $policy->versions;
117 | }
118 |
119 | $policy->versioncount = count($policy->versions);
120 | $policy->versions = array_values($policy->versions);
121 | $policy->versions[0]->isfirst = 1;
122 | $policy->versions[0]->hasarchived = (count($policy->versions) > 1);
123 | }
124 |
125 | $data->policies = array_values($policies);
126 | return $data;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/db/install.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/classes/policy_version_exporter.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides the {@link tool_policy\policy_version_exporter} class.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 David Mudrak
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use core\external\exporter;
30 | use renderer_base;
31 | use tool_policy\api;
32 |
33 | /**
34 | * Exporter of a single policy document version.
35 | *
36 | * Note we cannot use the persistent_exporter as our super class because we want to add some properties not present in
37 | * the persistent (e.g. acceptancescount).
38 | *
39 | * @copyright 2018 David Mudrak
40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 | */
42 | class policy_version_exporter extends exporter {
43 |
44 | /**
45 | * Return the list of properties.
46 | *
47 | * @return array
48 | */
49 | protected static function define_properties() {
50 |
51 | return policy_version::properties_definition() + [
52 | 'acceptancescount' => [
53 | 'type' => PARAM_INT,
54 | 'default' => 0,
55 | ],
56 | 'status' => [
57 | 'type' => PARAM_INT,
58 | ],
59 | ];
60 | }
61 |
62 | /**
63 | * Returns a list of objects that are related.
64 | *
65 | * @return array
66 | */
67 | protected static function define_related() {
68 | return [
69 | 'context' => 'context',
70 | ];
71 | }
72 |
73 | /**
74 | * Return the list of additional (calculated and readonly) properties.
75 | *
76 | * @return array
77 | */
78 | protected static function define_other_properties() {
79 | return [
80 | // Human readable type of the policy document version.
81 | 'typetext' => [
82 | 'type' => PARAM_TEXT,
83 | ],
84 | // Human readable audience of the policy document audience.
85 | 'audiencetext' => [
86 | 'type' => PARAM_TEXT,
87 | ],
88 | // Detailed information about the number of policy acceptances.
89 | 'acceptancescounttext' => [
90 | 'type' => PARAM_TEXT,
91 | ],
92 | // Link to view acceptances.
93 | 'acceptancescounturl' => [
94 | 'type' => PARAM_LOCALURL,
95 | ],
96 | ];
97 | }
98 |
99 | /**
100 | * Get the additional values to inject while exporting.
101 | *
102 | * @param renderer_base $output The renderer.
103 | * @return array Keys are the property names, values are their values.
104 | */
105 | protected function get_other_values(renderer_base $output) {
106 |
107 | $othervalues = [
108 | 'typetext' => get_string('policydoctype'.$this->data->type, 'tool_policy'),
109 | 'audiencetext' => get_string('policydocaudience'.$this->data->audience, 'tool_policy'),
110 | ];
111 |
112 | if (!isset($this->data->acceptancescount) || $this->data->status == policy_version::STATUS_DRAFT) {
113 | // Return "N/A" for acceptances count.
114 | $othervalues['acceptancescounttext'] = get_string('useracceptancecountna', 'tool_policy');
115 | $othervalues['acceptancescounturl'] = null;
116 | return $othervalues;
117 | }
118 |
119 | $acceptancescount = empty($this->data->acceptancescount) ? 0 : $this->data->acceptancescount;
120 | $acceptancesexpected = api::count_total_users();
121 |
122 | $a = [
123 | 'agreedcount' => $acceptancescount,
124 | 'userscount' => $acceptancesexpected,
125 | 'percent' => min(100, round($acceptancescount * 100 / max($acceptancesexpected, 1))),
126 | ];
127 |
128 | $othervalues['acceptancescounttext'] = get_string('useracceptancecount', 'tool_policy', $a);
129 | $acceptancesurl = new \moodle_url('/admin/tool/policy/acceptances.php', ['policyid' => $this->data->policyid]);
130 | if ($this->data->status != policy_version::STATUS_ACTIVE) {
131 | $acceptancesurl->param('versionid', $this->data->id);
132 | }
133 | $othervalues['acceptancescounturl'] = $acceptancesurl->out(false);
134 |
135 | return $othervalues;
136 | }
137 |
138 | /**
139 | * Get the formatting parameters for the summary field.
140 | *
141 | * @return array
142 | */
143 | protected function get_format_parameters_for_summary() {
144 | return [
145 | 'component' => 'tool_policy',
146 | 'filearea' => 'policydocumentsummary',
147 | 'itemid' => $this->data->id
148 | ];
149 | }
150 |
151 | /**
152 | * Get the formatting parameters for the content field.
153 | *
154 | * @return array
155 | */
156 | protected function get_format_parameters_for_content() {
157 | return [
158 | 'component' => 'tool_policy',
159 | 'filearea' => 'policydocumentcontent',
160 | 'itemid' => $this->data->id
161 | ];
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/classes/external.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class containing the external API functions functions for the Policy tool.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 Sara Arjona (sara@moodle.com)
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_policy;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use coding_exception;
30 | use context_system;
31 | use context_user;
32 | use core\invalid_persistent_exception;
33 | use dml_exception;
34 | use external_api;
35 | use external_description;
36 | use external_function_parameters;
37 | use external_single_structure;
38 | use external_value;
39 | use external_warnings;
40 | use invalid_parameter_exception;
41 | use moodle_exception;
42 | use restricted_context_exception;
43 | use tool_policy\api;
44 |
45 | /**
46 | * Class external.
47 | *
48 | * The external API for the Policy tool.
49 | *
50 | * @copyright 2018 Sara Arjona (sara@moodle.com)
51 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
52 | */
53 | class external extends external_api {
54 |
55 | /**
56 | * Parameter description for get_policy_version_parameters().
57 | *
58 | * @return external_function_parameters
59 | */
60 | public static function get_policy_version_parameters() {
61 | return new external_function_parameters([
62 | 'versionid' => new external_value(PARAM_INT, 'The policy version ID', VALUE_REQUIRED),
63 | 'behalfid' => new external_value(PARAM_INT, 'The id of user on whose behalf the user is viewing the policy',
64 | VALUE_DEFAULT, 0)
65 | ]);
66 | }
67 |
68 | /**
69 | * Fetch the details of a policy version.
70 | *
71 | * @param int $versionid The policy version ID.
72 | * @param int $behalfid The id of user on whose behalf the user is viewing the policy.
73 | * @return array
74 | * @throws coding_exception
75 | * @throws dml_exception
76 | * @throws invalid_parameter_exception
77 | * @throws restricted_context_exception
78 | * @throws moodle_exception
79 | */
80 | public static function get_policy_version($versionid, $behalfid = null) {
81 | global $PAGE;
82 |
83 | $result = [];
84 | $warnings = [];
85 | $params = external_api::validate_parameters(self::get_policy_version_parameters(), [
86 | 'versionid' => $versionid,
87 | 'behalfid' => $behalfid
88 | ]);
89 | $versionid = $params['versionid'];
90 | $behalfid = $params['behalfid'];
91 |
92 | $context = context_system::instance();
93 | $PAGE->set_context($context);
94 |
95 | try {
96 | // Validate if the user has access to the policy version.
97 | $version = api::get_policy_version($versionid);
98 | if (!api::can_user_view_policy_version($version, $behalfid)) {
99 | $warnings[] = [
100 | 'item' => $versionid,
101 | 'warningcode' => 'errorusercantviewpolicyversion',
102 | 'message' => get_string('errorusercantviewpolicyversion', 'tool_policy')
103 | ];
104 | } else if (!empty($version)) {
105 | $version = api::get_policy_version($versionid);
106 | $policy['name'] = $version->name;
107 | $policy['versionid'] = $versionid;
108 | list($policy['content'], $notusedformat) = external_format_text(
109 | $version->content,
110 | $version->contentformat,
111 | SYSCONTEXTID,
112 | 'tool_policy',
113 | 'policydocumentcontent',
114 | $version->id
115 | );
116 | $result['policy'] = $policy;
117 | }
118 | } catch (coding_exception $e) {
119 | $warnings[] = [
120 | 'item' => $versionid,
121 | 'warningcode' => 'errorpolicyversionnotfound',
122 | 'message' => get_string('errorpolicyversionnotfound', 'tool_policy')
123 | ];
124 | }
125 |
126 | return [
127 | 'result' => $result,
128 | 'warnings' => $warnings
129 | ];
130 | }
131 |
132 | /**
133 | * Parameter description for get_policy_version().
134 | *
135 | * @return external_description
136 | */
137 | public static function get_policy_version_returns() {
138 | return new external_single_structure([
139 | 'result' => new external_single_structure([
140 | 'policy' => new external_single_structure([
141 | 'name' => new external_value(PARAM_RAW, 'The policy version name', VALUE_OPTIONAL),
142 | 'versionid' => new external_value(PARAM_INT, 'The policy version id', VALUE_OPTIONAL),
143 | 'content' => new external_value(PARAM_RAW, 'The policy version content', VALUE_OPTIONAL)
144 | ], 'Policy information', VALUE_OPTIONAL)
145 | ]),
146 | 'warnings' => new external_warnings()
147 | ]);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/amd/src/acceptances_filter.js:
--------------------------------------------------------------------------------
1 | // This file is part of Moodle - http://moodle.org/
2 | //
3 | // Moodle is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // Moodle is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Moodle. If not, see .
15 |
16 | /**
17 | * Unified filter page JS module for the course participants page.
18 | *
19 | * @module tool_policy/acceptances_filter
20 | * @package tool_policy
21 | * @copyright 2017 Jun Pataleta
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 | define(['jquery', 'core/form-autocomplete', 'core/str', 'core/notification'],
25 | function($, Autocomplete, Str, Notification) {
26 |
27 | /**
28 | * Selectors.
29 | *
30 | * @access private
31 | * @type {{UNIFIED_FILTERS: string}}
32 | */
33 | var SELECTORS = {
34 | UNIFIED_FILTERS: '#unified-filters'
35 | };
36 |
37 | /**
38 | * Init function.
39 | *
40 | * @method init
41 | * @private
42 | */
43 | var init = function() {
44 | var stringkeys = [{
45 | key: 'filterplaceholder',
46 | component: 'tool_policy'
47 | }, {
48 | key: 'nofiltersapplied',
49 | component: 'tool_policy'
50 | }];
51 |
52 | M.util.js_pending('acceptances_filter_datasource');
53 | Str.get_strings(stringkeys).done(function(langstrings) {
54 | var placeholder = langstrings[0];
55 | var noSelectionString = langstrings[1];
56 | Autocomplete.enhance(SELECTORS.UNIFIED_FILTERS, true, 'tool_policy/acceptances_filter_datasource', placeholder,
57 | false, true, noSelectionString, true)
58 | .then(function() {
59 | M.util.js_complete('acceptances_filter_datasource');
60 |
61 | return;
62 | })
63 | .fail(Notification.exception);
64 | }).fail(Notification.exception);
65 |
66 | var last = $(SELECTORS.UNIFIED_FILTERS).val();
67 | $(SELECTORS.UNIFIED_FILTERS).on('change', function() {
68 | var current = $(this).val();
69 | var listoffilters = [];
70 | var textfilters = [];
71 | var updatedselectedfilters = false;
72 |
73 | $.each(current, function(index, catoption) {
74 | var catandoption = catoption.split(':', 2);
75 | if (catandoption.length !== 2) {
76 | textfilters.push(catoption);
77 | return true; // Text search filter.
78 | }
79 |
80 | var category = catandoption[0];
81 | var option = catandoption[1];
82 |
83 | // The last option (eg. 'Teacher') out of a category (eg. 'Role') in this loop is the one that was last
84 | // selected, so we want to use that if there are multiple options from the same category. Eg. The user
85 | // may have chosen to filter by the 'Student' role, then wanted to filter by the 'Teacher' role - the
86 | // last option in the category to be selected (in this case 'Teacher') will come last, so will overwrite
87 | // 'Student' (after this if). We want to let the JS know that the filters have been updated.
88 | if (typeof listoffilters[category] !== 'undefined') {
89 | updatedselectedfilters = true;
90 | }
91 |
92 | listoffilters[category] = option;
93 | return true;
94 | });
95 |
96 | // Check if we have something to remove from the list of filters.
97 | if (updatedselectedfilters) {
98 | // Go through and put the list into something we can use to update the list of filters.
99 | var updatefilters = [];
100 | for (var category in listoffilters) {
101 | updatefilters.push(category + ":" + listoffilters[category]);
102 | }
103 | updatefilters = updatefilters.concat(textfilters);
104 | $(this).val(updatefilters);
105 | }
106 |
107 | // Prevent form from submitting unnecessarily, eg. on blur when no filter is selected.
108 | if (last.join(',') != current.join(',')) {
109 | this.form.submit();
110 | }
111 | });
112 | };
113 |
114 | /**
115 | * Return the unified user filter form.
116 | *
117 | * @method getForm
118 | * @return {DOMElement}
119 | */
120 | var getForm = function() {
121 | return $(SELECTORS.UNIFIED_FILTERS).closest('form');
122 | };
123 |
124 | return /** @alias module:core/form-autocomplete */ {
125 | /**
126 | * Initialise the unified user filter.
127 | *
128 | * @method init
129 | */
130 | init: function() {
131 | init();
132 | },
133 |
134 | /**
135 | * Return the unified user filter form.
136 | *
137 | * @method getForm
138 | * @return {DOMElement}
139 | */
140 | getForm: function() {
141 | return getForm();
142 | }
143 | };
144 | });
145 |
--------------------------------------------------------------------------------
/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 David Mudrák
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | use core_user\output\myprofile\tree;
28 | use tool_policy\api;
29 | use 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 | */
43 | function 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.
63 | $url = new moodle_url('/admin/tool/policy/user.php', ['userid' => $user->id]);
64 | $node = new core_user\output\myprofile\node('privacyandpolicies', 'tool_policy',
65 | get_string('policiesagreements', 'tool_policy'), null, $url);
66 | $category->add_node($node);
67 |
68 | return true;
69 | }
70 |
71 | /**
72 | * Load policy message for guests.
73 | *
74 | * @return string The HTML code to insert before the head.
75 | */
76 | function tool_policy_before_standard_html_head() {
77 | global $CFG, $PAGE, $USER;
78 |
79 | $message = null;
80 | if (!empty($CFG->sitepolicyhandler)
81 | && $CFG->sitepolicyhandler == 'tool_policy'
82 | && empty($USER->policyagreed)
83 | && isguestuser()) {
84 | $output = $PAGE->get_renderer('tool_policy');
85 | $page = new \tool_policy\output\guestconsent();
86 |
87 | $message = $output->render($page);
88 | }
89 |
90 | return $message;
91 | }
92 |
93 | /**
94 | * Hooks redirection to policy acceptance pages before sign up.
95 | */
96 | function tool_policy_pre_signup_requests() {
97 | global $CFG, $SESSION;
98 |
99 | // Do nothing if we are not set as the site policies handler.
100 | if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
101 | return;
102 | }
103 |
104 | $policies = api::get_current_versions_ids(policy_version::AUDIENCE_LOGGEDIN);
105 | $userpolicyagreed = cache::make('core', 'presignup')->get('tool_policy_userpolicyagreed');
106 | if (!empty($policies) && !$userpolicyagreed) {
107 | // Redirect to "Policy" pages for consenting before creating the user.
108 | $SESSION->wantsurl = (new \moodle_url('/login/signup.php'))->out();
109 | redirect(new \moodle_url('/admin/tool/policy/index.php'));
110 | }
111 | }
112 |
113 | /**
114 | * Serve the embedded files.
115 | *
116 | * @param stdClass $course the course object
117 | * @param stdClass $cm the course module object
118 | * @param stdClass $context the context
119 | * @param string $filearea the name of the file area
120 | * @param array $args extra arguments (itemid, path)
121 | * @param bool $forcedownload whether or not force download
122 | * @param array $options additional options affecting the file serving
123 | * @return bool false if the file not found, just send the file otherwise and do not return anything
124 | */
125 | function tool_policy_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
126 | global $CFG, $PAGE;
127 |
128 | // Do not allow access to files if we are not set as the site policy handler.
129 | if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
130 | return false;
131 | }
132 |
133 | if ($context->contextlevel != CONTEXT_SYSTEM) {
134 | return false;
135 | }
136 |
137 | $PAGE->set_context($context);
138 |
139 | if ($filearea !== 'policydocumentsummary' && $filearea !== 'policydocumentcontent') {
140 | return false;
141 | }
142 |
143 | $itemid = array_shift($args);
144 |
145 | $policy = api::get_policy_version($itemid);
146 |
147 | if ($policy->status != policy_version::STATUS_ACTIVE) {
148 | require_login();
149 | }
150 |
151 | if (!api::can_user_view_policy_version($policy)) {
152 | return false;
153 | }
154 |
155 | $filename = array_pop($args);
156 |
157 | if (!$args) {
158 | $filepath = '/';
159 | } else {
160 | $filepath = '/'.implode('/', $args).'/';
161 | }
162 |
163 | $fs = get_file_storage();
164 | $file = $fs->get_file($context->id, 'tool_policy', $filearea, $itemid, $filepath, $filename);
165 |
166 | if (!$file) {
167 | return false;
168 | }
169 |
170 | send_stored_file($file, null, 0, $forcedownload, $options);
171 | }
172 |
173 | /**
174 | * Map icons for font-awesome themes.
175 | */
176 | function tool_policy_get_fontawesome_icon_map() {
177 | return [
178 | 'tool_policy:agreedno' => 'fa-times text-danger',
179 | 'tool_policy:agreedyes' => 'fa-check text-success',
180 | 'tool_policy:agreedyesonbehalf' => 'fa-check text-info',
181 | 'tool_policy:level' => 'fa-level-up fa-rotate-90 text-muted',
182 | ];
183 | }
184 |
--------------------------------------------------------------------------------
/editpolicydoc.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Edit/create a policy document version.
19 | *
20 | * @package tool_policy
21 | * @copyright 2018 David Mudrák
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | use tool_policy\api;
26 | use tool_policy\policy_version;
27 |
28 | require(__DIR__.'/../../../config.php');
29 | require_once($CFG->libdir.'/adminlib.php');
30 |
31 | $policyid = optional_param('policyid', null, PARAM_INT);
32 | $versionid = optional_param('versionid', null, PARAM_INT);
33 | $makecurrent = optional_param('makecurrent', null, PARAM_INT);
34 | $inactivate = optional_param('inactivate', null, PARAM_INT);
35 | $delete = optional_param('delete', null, PARAM_INT);
36 | $confirm = optional_param('confirm', false, PARAM_BOOL);
37 | $moveup = optional_param('moveup', null, PARAM_INT);
38 | $movedown = optional_param('movedown', null, PARAM_INT);
39 |
40 | admin_externalpage_setup('tool_policy_managedocs', '', ['policyid' => $policyid, 'versionid' => $versionid],
41 | new moodle_url('/admin/tool/policy/editpolicydoc.php'));
42 | require_capability('tool/policy:managedocs', context_system::instance());
43 |
44 | $output = $PAGE->get_renderer('tool_policy');
45 | $PAGE->navbar->add(get_string('editingpolicydocument', 'tool_policy'));
46 |
47 | if ($makecurrent) {
48 | $version = api::get_policy_version($makecurrent);
49 |
50 | if ($confirm) {
51 | require_sesskey();
52 | api::make_current($makecurrent);
53 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
54 | }
55 |
56 | echo $output->header();
57 | echo $output->heading(get_string('activating', 'tool_policy'));
58 | echo $output->confirm(
59 | get_string('activateconfirm', 'tool_policy', [
60 | 'name' => format_string($version->name),
61 | 'revision' => format_string($version->revision),
62 | ]),
63 | new moodle_url($PAGE->url, ['makecurrent' => $makecurrent, 'confirm' => 1]),
64 | new moodle_url('/admin/tool/policy/managedocs.php')
65 | );
66 | echo $output->footer();
67 | die();
68 | }
69 |
70 | if ($inactivate) {
71 | $policies = api::list_policies([$inactivate]);
72 |
73 | if (empty($policies[0]->currentversionid)) {
74 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
75 | }
76 |
77 | if ($confirm) {
78 | require_sesskey();
79 | api::inactivate($inactivate);
80 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
81 | }
82 |
83 | echo $output->header();
84 | echo $output->heading(get_string('inactivating', 'tool_policy'));
85 | echo $output->confirm(
86 | get_string('inactivatingconfirm', 'tool_policy', [
87 | 'name' => format_string($policies[0]->currentversion->name),
88 | 'revision' => format_string($policies[0]->currentversion->revision),
89 | ]),
90 | new moodle_url($PAGE->url, ['inactivate' => $inactivate, 'confirm' => 1]),
91 | new moodle_url('/admin/tool/policy/managedocs.php')
92 | );
93 | echo $output->footer();
94 | die();
95 | }
96 |
97 | if ($delete) {
98 | $version = api::get_policy_version($delete);
99 |
100 | if ($confirm) {
101 | require_sesskey();
102 | api::delete($delete);
103 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
104 | }
105 |
106 | echo $output->header();
107 | echo $output->heading(get_string('deleting', 'tool_policy'));
108 | echo $output->confirm(
109 | get_string('deleteconfirm', 'tool_policy', [
110 | 'name' => format_string($version->name),
111 | 'revision' => format_string($version->revision),
112 | ]),
113 | new moodle_url($PAGE->url, ['delete' => $delete, 'confirm' => 1]),
114 | new moodle_url('/admin/tool/policy/managedocs.php')
115 | );
116 | echo $output->footer();
117 | die();
118 | }
119 |
120 | if ($moveup || $movedown) {
121 | require_sesskey();
122 |
123 | if ($moveup) {
124 | api::move_up($moveup);
125 | } else {
126 | api::move_down($movedown);
127 | }
128 |
129 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
130 | }
131 |
132 | if (!$versionid && $policyid) {
133 | if (($policies = api::list_policies([$policyid])) && !empty($policies[0]->currentversionid)) {
134 | $policy = $policies[0];
135 | $policyversion = new policy_version($policy->currentversionid);
136 | } else {
137 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
138 | }
139 | } else {
140 | $policyversion = new policy_version($versionid);
141 | if ($policyversion->get('policyid')) {
142 | $policy = api::list_policies([$policyversion->get('policyid')])[0];
143 | } else {
144 | $policy = null;
145 | }
146 | }
147 | if ($policyversion->get('archived')) {
148 | // Can not edit archived version.
149 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
150 | }
151 |
152 | $formdata = api::form_policydoc_data($policyversion);
153 |
154 | if ($policy && $formdata->id && $policy->currentversionid == $formdata->id) {
155 | $formdata->status = policy_version::STATUS_ACTIVE;
156 | } else {
157 | $formdata->status = policy_version::STATUS_DRAFT;
158 | }
159 |
160 | $form = new \tool_policy\form\policydoc($PAGE->url, ['formdata' => $formdata]);
161 |
162 | if ($form->is_cancelled()) {
163 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
164 |
165 | } else if ($data = $form->get_data()) {
166 |
167 | if (! $policyversion->get('id')) {
168 | $policyversion = api::form_policydoc_add($data);
169 |
170 | } else if (empty($data->minorchange)) {
171 | $data->policyid = $policyversion->get('policyid');
172 | $policyversion = api::form_policydoc_update_new($data);
173 |
174 | } else {
175 | $data->id = $policyversion->get('id');
176 | $policyversion = api::form_policydoc_update_overwrite($data);
177 | }
178 |
179 | if ($data->status == policy_version::STATUS_ACTIVE) {
180 | api::make_current($policyversion->get('id'));
181 | }
182 |
183 | redirect(new moodle_url('/admin/tool/policy/managedocs.php'));
184 |
185 | } else {
186 | echo $output->header();
187 | echo $output->heading(get_string('editingpolicydocument', 'tool_policy'));
188 | echo $form->render();
189 | echo $output->footer();
190 | }
191 |
--------------------------------------------------------------------------------
/classes/output/page_viewdoc.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\output\renderer} class.
19 | *
20 | * @package tool_policy
21 | * @category output
22 | * @copyright 2018 Sara Arjona
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace tool_policy\output;
27 |
28 | use moodle_exception;
29 |
30 | defined('MOODLE_INTERNAL') || die();
31 |
32 | use context_system;
33 | use moodle_url;
34 | use renderable;
35 | use renderer_base;
36 | use single_button;
37 | use templatable;
38 | use tool_policy\api;
39 | use tool_policy\policy_version;
40 |
41 | /**
42 | * Represents a page for showing the given policy document version.
43 | *
44 | * @copyright 2018 Sara Arjona
45 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 | */
47 | class page_viewdoc implements renderable, templatable {
48 |
49 | /** @var stdClass Exported {@link \tool_policy\policy_version_exporter} to display on this page. */
50 | protected $policy;
51 |
52 | /** @var string Return URL. */
53 | protected $returnurl = null;
54 |
55 | /** @var int User id who wants to view this page. */
56 | protected $behalfid = null;
57 |
58 | /**
59 | * Prepare the page for rendering.
60 | *
61 | * @param int $policyid The policy id for this page.
62 | * @param int $versionid The version id to show. Empty tries to load the current one.
63 | * @param string $returnurl URL of a page to continue after reading the policy text.
64 | * @param int $behalfid The userid to view this policy version as (such as child's id).
65 | * @param bool $manage View the policy as a part of the management UI.
66 | * @param int $numpolicy Position of the current policy with respect to the total of policy docs to display.
67 | * @param int $totalpolicies Total number of policy documents which the user has to agree to.
68 | */
69 | public function __construct($policyid, $versionid, $returnurl, $behalfid, $manage, $numpolicy = 0, $totalpolicies = 0) {
70 |
71 | $this->returnurl = $returnurl;
72 | $this->behalfid = $behalfid;
73 | $this->manage = $manage;
74 | $this->numpolicy = $numpolicy;
75 | $this->totalpolicies = $totalpolicies;
76 |
77 | $this->prepare_policy($policyid, $versionid);
78 | $this->prepare_global_page_access();
79 | }
80 |
81 | /**
82 | * Loads the policy version to display on the page.
83 | *
84 | * @param int $policyid The policy id for this page.
85 | * @param int $versionid The version id to show. Empty tries to load the current one.
86 | */
87 | protected function prepare_policy($policyid, $versionid) {
88 |
89 | if ($versionid) {
90 | $this->policy = api::get_policy_version($versionid);
91 |
92 | } else {
93 | $this->policy = array_reduce(api::list_current_versions(), function ($carry, $current) use ($policyid) {
94 | if ($current->policyid == $policyid) {
95 | return $current;
96 | }
97 | return $carry;
98 | });
99 | }
100 |
101 | if (empty($this->policy)) {
102 | // TODO Make this nicer error message.
103 | throw new \moodle_exception('err_no_active_version', 'tool_policy');
104 | }
105 | }
106 |
107 | /**
108 | * Sets up the global $PAGE and performs the access checks.
109 | */
110 | protected function prepare_global_page_access() {
111 | global $CFG, $PAGE, $SITE, $USER;
112 |
113 | $myurl = new moodle_url('/admin/tool/policy/view.php', [
114 | 'policyid' => $this->policy->policyid,
115 | 'versionid' => $this->policy->id,
116 | 'returnurl' => $this->returnurl,
117 | 'behalfid' => $this->behalfid,
118 | 'manage' => $this->manage,
119 | 'numpolicy' => $this->numpolicy,
120 | 'totalpolicies' => $this->totalpolicies,
121 | ]);
122 |
123 | if ($this->manage) {
124 | require_once($CFG->libdir.'/adminlib.php');
125 | admin_externalpage_setup('tool_policy_managedocs', '', null, $myurl);
126 | require_capability('tool/policy:managedocs', context_system::instance());
127 | $PAGE->navbar->add(format_string($this->policy->name),
128 | new moodle_url('/admin/tool/policy/managedocs.php', ['id' => $this->policy->policyid]));
129 | } else {
130 | if ($this->policy->status != policy_version::STATUS_ACTIVE) {
131 | require_login();
132 | } else if (isguestuser() || empty($USER->id) || !$USER->policyagreed) {
133 | // Disable notifications for new users, guests or users who haven't agreed to the policies.
134 | $PAGE->set_popup_notification_allowed(false);
135 | }
136 | $PAGE->set_url($myurl);
137 | $PAGE->set_heading($SITE->fullname);
138 | $PAGE->set_title(get_string('policiesagreements', 'tool_policy'));
139 | $PAGE->navbar->add(get_string('policiesagreements', 'tool_policy'), new moodle_url('/admin/tool/policy/index.php'));
140 | $PAGE->navbar->add(format_string($this->policy->name));
141 | }
142 |
143 | if (!api::can_user_view_policy_version($this->policy, $this->behalfid)) {
144 | throw new moodle_exception('accessdenied', 'tool_policy');
145 | }
146 | }
147 |
148 | /**
149 | * Export the page data for the mustache template.
150 | *
151 | * @param renderer_base $output renderer to be used to render the page elements.
152 | * @return stdClass
153 | */
154 | public function export_for_template(renderer_base $output) {
155 |
156 | $data = (object) [
157 | 'pluginbaseurl' => (new moodle_url('/admin/tool/policy'))->out(false),
158 | 'returnurl' => $this->returnurl ? (new moodle_url($this->returnurl))->out(false) : null,
159 | 'editurl' => $this->manage ? (new moodle_url('/admin/tool/policy/editpolicydoc.php',
160 | ['policyid' => $this->policy->policyid, 'versionid' => $this->policy->id]))->out(false) : null,
161 | 'numpolicy' => $this->numpolicy ? : null,
162 | 'totalpolicies' => $this->totalpolicies ? : null,
163 | ];
164 |
165 | $data->policy = clone($this->policy);
166 |
167 | return $data;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/classes/form/policydoc.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\form\policydoc} class.
19 | *
20 | * @package tool_policy
21 | * @category output
22 | * @copyright 2018 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace tool_policy\form;
27 |
28 | use context_system;
29 | use html_writer;
30 | use moodleform;
31 | use tool_policy\api;
32 | use tool_policy\policy_version;
33 |
34 | defined('MOODLE_INTERNAL') || die();
35 |
36 | /**
37 | * Defines the form for editing a policy document version.
38 | *
39 | * @copyright 2018 David Mudrak
40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 | */
42 | class policydoc extends moodleform {
43 |
44 | /**
45 | * Defines the form fields.
46 | */
47 | public function definition() {
48 |
49 | $mform = $this->_form;
50 | $formdata = $this->_customdata['formdata'];
51 |
52 | $mform->addElement('text', 'name', get_string('policydocname', 'tool_policy'), ['maxlength' => 1333]);
53 | $mform->settype('name', PARAM_TEXT);
54 | $mform->addRule('name', null, 'required', null, 'client');
55 | $mform->addRule('name', get_string('maximumchars', '', 1333), 'maxlength', 1333, 'client');
56 |
57 | $options = [];
58 | foreach ([policy_version::TYPE_SITE,
59 | policy_version::TYPE_PRIVACY,
60 | policy_version::TYPE_THIRD_PARTY,
61 | policy_version::TYPE_OTHER] as $type) {
62 | $options[$type] = get_string('policydoctype'.$type, 'tool_policy');
63 | }
64 | $mform->addElement('select', 'type', get_string('policydoctype', 'tool_policy'), $options);
65 |
66 | $options = [];
67 | foreach ([policy_version::AUDIENCE_ALL,
68 | policy_version::AUDIENCE_LOGGEDIN,
69 | policy_version::AUDIENCE_GUESTS] as $audience) {
70 | $options[$audience] = get_string('policydocaudience'.$audience, 'tool_policy');
71 | }
72 | $mform->addElement('select', 'audience', get_string('policydocaudience', 'tool_policy'), $options);
73 |
74 | if (empty($formdata->id)) {
75 | $default = userdate(time(), get_string('strftimedate', 'core_langconfig'));
76 | } else {
77 | $default = userdate($formdata->timecreated, get_string('strftimedate', 'core_langconfig'));
78 | }
79 | $mform->addElement('text', 'revision', get_string('policydocrevision', 'tool_policy'),
80 | ['maxlength' => 1333, 'placeholder' => $default]);
81 | $mform->settype('revision', PARAM_TEXT);
82 | $mform->addRule('revision', get_string('maximumchars', '', 1333), 'maxlength', 1333, 'client');
83 |
84 | $mform->addElement('editor', 'summary_editor', get_string('policydocsummary', 'tool_policy'), ['rows' => 7],
85 | api::policy_summary_field_options());
86 | $mform->addRule('summary_editor', null, 'required', null, 'client');
87 |
88 | $mform->addElement('editor', 'content_editor', get_string('policydoccontent', 'tool_policy'), null,
89 | api::policy_content_field_options());
90 | $mform->addRule('content_editor', null, 'required', null, 'client');
91 |
92 | if (!$formdata->id || $formdata->status == policy_version::STATUS_DRAFT) {
93 | // Creating a new version or editing a draft.
94 | $mform->addElement('hidden', 'minorchange', 1);
95 | $mform->setType('minorchange', PARAM_INT);
96 |
97 | $statusgrp = [
98 | $mform->createElement('radio', 'status', '', get_string('status'.policy_version::STATUS_ACTIVE, 'tool_policy'),
99 | policy_version::STATUS_ACTIVE),
100 | $mform->createElement('radio', 'status', '', get_string('status'.policy_version::STATUS_DRAFT, 'tool_policy'),
101 | policy_version::STATUS_DRAFT),
102 | $mform->createElement('static', 'statusinfo', '', html_writer::div(get_string('statusinfo', 'tool_policy'),
103 | 'muted text-muted')),
104 | ];
105 | $mform->addGroup($statusgrp, null, get_string('status', 'tool_policy'), [' '], false);
106 |
107 | } else {
108 | // Editing an active version.
109 | $mform->addElement('hidden', 'status', policy_version::STATUS_ACTIVE);
110 | $mform->setType('status', PARAM_INT);
111 |
112 | $statusgrp = [
113 | $mform->createElement('checkbox', 'minorchange', '', get_string('minorchange', 'tool_policy')),
114 | $mform->createElement('static', 'minorchangeinfo', '',
115 | html_writer::div(get_string('minorchangeinfo', 'tool_policy'), 'muted text-muted')),
116 | ];
117 | $mform->addGroup($statusgrp, null, get_string('status', 'tool_policy'), [' '], false);
118 | }
119 |
120 | // Add "Save" button and, optionally, "Save as draft".
121 | $buttonarray = [];
122 | $buttonarray[] = $mform->createElement('submit', 'save', get_string('save', 'tool_policy'));
123 | if ($formdata->id && $formdata->status == policy_version::STATUS_ACTIVE) {
124 | $buttonarray[] = $mform->createElement('submit', 'saveasdraft', get_string('saveasdraft', 'tool_policy'));
125 | }
126 | $buttonarray[] = $mform->createElement('cancel');
127 | $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
128 | $mform->closeHeaderBefore('buttonar');
129 |
130 | $this->set_data($formdata);
131 | }
132 |
133 | /**
134 | * Form validation
135 | *
136 | * @param array $data array of ("fieldname"=>value) of submitted data
137 | * @param array $files array of uploaded files "element_name"=>tmp_file_path
138 | * @return array of "element_name"=>"error_description" if there are errors,
139 | * or an empty array if everything is OK (true allowed for backwards compatibility too).
140 | */
141 | public function validation($data, $files) {
142 | $errors = parent::validation($data, $files);
143 | if (!empty($data['minorchange']) && !empty($data['saveasdraft'])) {
144 | // If minorchange is checked and "save as draft" is pressed - return error.
145 | $errors['minorchange'] = get_string('errorsaveasdraft', 'tool_policy');
146 | }
147 | return $errors;
148 | }
149 |
150 | /**
151 | * Return submitted data if properly submitted or returns NULL if validation fails or
152 | * if there is no submitted data.
153 | *
154 | * @return object submitted data; NULL if not valid or not submitted or cancelled
155 | */
156 | public function get_data() {
157 | if ($data = parent::get_data()) {
158 | if (!empty($data->saveasdraft)) {
159 | $data->status = policy_version::STATUS_DRAFT;
160 | }
161 | }
162 | return $data;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/classes/output/page_nopermission.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\output\renderer} class.
19 | *
20 | * @package tool_policy
21 | * @category output
22 | * @copyright 2018 Sara Arjona
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace tool_policy\output;
27 |
28 | use moodle_exception;
29 |
30 | defined('MOODLE_INTERNAL') || die();
31 |
32 | use context_system;
33 | use core_user;
34 | use html_writer;
35 | use moodle_url;
36 | use renderable;
37 | use renderer_base;
38 | use templatable;
39 | use tool_policy\api;
40 | use tool_policy\policy_version;
41 |
42 | /**
43 | * Represents a page for showing the error messages.
44 | *
45 | * This is used when a user has no permission to agree to policies or accept policies on behalf of defined behalfid.
46 | *
47 | * @copyright 2018 Sara Arjona
48 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
49 | */
50 | class page_nopermission implements renderable, templatable {
51 |
52 | /** @var int User id who wants to view this page. */
53 | protected $behalfid = null;
54 |
55 | /** @var object User who wants to accept this page. */
56 | protected $behalfuser = null;
57 |
58 | /** @var bool True if user has permission to accept policy documents; false otherwise. */
59 | protected $haspermissionagreedocs = true;
60 |
61 | /** @var array $policies List of public policies objects. */
62 | protected $policies = null;
63 |
64 | /**
65 | * Prepare the page for rendering.
66 | *
67 | * @param int $behalfid The userid to consent policies as (such as child's id).
68 | */
69 | public function __construct($behalfid) {
70 | global $USER;
71 |
72 | $this->behalfid = $behalfid;
73 | if (!empty($this->behalfid) && $USER->id != $this->behalfid) {
74 | $this->behalfuser = core_user::get_user($this->behalfid, '*');
75 | // If behalf user doesn't exist, behalfid parameter will be ignored.
76 | if ($this->behalfuser === false) {
77 | $this->behalfid = 0;
78 | }
79 | }
80 |
81 | if (!empty($USER->id)) {
82 | // For existing users, it's needed to check if they have the capability for accepting policies.
83 | if (empty($this->behalfid) || $this->behalfid == $USER->id) {
84 | $this->haspermissionagreedocs = has_capability('tool/policy:accept', context_system::instance());
85 | } else {
86 | $usercontext = \context_user::instance($this->behalfid);
87 | $this->haspermissionagreedocs = has_capability('tool/policy:acceptbehalf', $usercontext);
88 | }
89 | }
90 |
91 | $this->policies = api::list_current_versions(policy_version::AUDIENCE_LOGGEDIN);
92 |
93 | if (empty($this->policies) && !empty($USER->id)) {
94 | // Existing user without policies to agree to.
95 | $currentuser = (!empty($this->behalfuser)) ? $behalfuser : $USER;
96 | if (!$currentuser->policyagreed) {
97 | // If there are no policies to agreed, change $user->policyagreed to true.
98 | api::update_policyagreed($currentuser);
99 | }
100 | }
101 |
102 | $this->prepare_global_page_access();
103 | }
104 |
105 | /**
106 | * Sets up the global $PAGE and performs the access checks.
107 | */
108 | protected function prepare_global_page_access() {
109 | global $CFG, $PAGE, $SITE, $USER;
110 |
111 | $myurl = new moodle_url('/admin/tool/policy/index.php', [
112 | 'behalfid' => $this->behalfid,
113 | ]);
114 |
115 | if (isguestuser() || empty($USER->id) || !$USER->policyagreed) {
116 | // Disable notifications for new users, guests or users who haven't agreed to the policies.
117 | $PAGE->set_popup_notification_allowed(false);
118 | }
119 | $PAGE->set_context(context_system::instance());
120 | $PAGE->set_pagelayout('standard');
121 | $PAGE->set_url($myurl);
122 | $PAGE->set_heading($SITE->fullname);
123 | $PAGE->set_title(get_string('policiesagreements', 'tool_policy'));
124 | $PAGE->navbar->add(get_string('policiesagreements', 'tool_policy'), new moodle_url('/admin/tool/policy/index.php'));
125 | }
126 |
127 | /**
128 | * Export the page data for the mustache template.
129 | *
130 | * @param renderer_base $output renderer to be used to render the page elements.
131 | * @return stdClass
132 | */
133 | public function export_for_template(renderer_base $output) {
134 | global $CFG, $PAGE;
135 |
136 | $data = (object) [
137 | 'pluginbaseurl' => (new moodle_url('/admin/tool/policy'))->out(false),
138 | 'haspermissionagreedocs' => $this->haspermissionagreedocs,
139 | 'supportname' => $CFG->supportname,
140 | 'supportemail' => $CFG->supportemail,
141 | ];
142 |
143 | // Get the messages to display.
144 | $messagetitle = null;
145 | $messagedesc = null;
146 | if (!$this->haspermissionagreedocs) {
147 | if (!empty($this->behalfuser)) {
148 | // If viewing docs in behalf of other user, get his/her full name and profile link.
149 | $userfullname = fullname($this->behalfuser, has_capability('moodle/site:viewfullnames', \context_system::instance())
150 | || has_capability('moodle/site:viewfullnames', \context_user::instance($this->behalfid)));
151 | $data->behalfuser = html_writer::link(\context_user::instance($this->behalfid)->get_url(), $userfullname);
152 |
153 | $messagetitle = get_string('nopermissiontoagreedocsbehalf', 'tool_policy');
154 | $messagedesc = get_string('nopermissiontoagreedocsbehalf_desc', 'tool_policy', $data->behalfuser);
155 | } else {
156 | $messagetitle = get_string('nopermissiontoagreedocs', 'tool_policy');
157 | $messagedesc = get_string('nopermissiontoagreedocs_desc', 'tool_policy');
158 | }
159 | }
160 | $data->messagetitle = $messagetitle;
161 | $data->messagedesc = $messagedesc;
162 |
163 | // Add policies list.
164 | $policieslinks = array();
165 | foreach ($this->policies as $policyversion) {
166 | // Get a link to display the full policy document.
167 | $policyurl = new moodle_url('/admin/tool/policy/view.php',
168 | array('policyid' => $policyversion->policyid, 'returnurl' => qualified_me()));
169 | $policyattributes = array('data-action' => 'view',
170 | 'data-versionid' => $policyversion->id,
171 | 'data-behalfid' => $this->behalfid);
172 | $policieslinks[] = html_writer::link($policyurl, $policyversion->name, $policyattributes);
173 | }
174 | $data->policies = $policieslinks;
175 |
176 | return $data;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/lang/en/tool_policy.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin strings are defined here.
19 | *
20 | * @package tool_policy
21 | * @category string
22 | * @copyright 2018 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $string['acceptanceacknowledgement'] = 'I acknowledge that consents to these policies have been acquired';
29 | $string['acceptancecount'] = '{$a->agreedcount} of {$a->policiescount}';
30 | $string['acceptancenote'] = 'Remarks';
31 | $string['acceptancepolicies'] = 'Policies';
32 | $string['acceptancessavedsucessfully'] = 'The agreements has been saved successfully.';
33 | $string['acceptancestatusoverall'] = 'Overall';
34 | $string['acceptanceusers'] = 'Users';
35 | $string['actions'] = 'Actions';
36 | $string['activate'] = 'Set status to "Active"';
37 | $string['activating'] = 'Activating a policy';
38 | $string['activateconfirm'] = 'You are about to activate policy \'{$a->name}\' and make the version \'{$a->revision}\' the current one.
All users will be required to accept this new policy version to be able to use the site.
';
39 | $string['agreed'] = 'Agreed';
40 | $string['agreedby'] = 'Agreed by';
41 | $string['agreedon'] = 'Agreed on';
42 | $string['agreepolicies'] = 'Please agree to the following policies';
43 | $string['backtotop'] = 'Back to top';
44 | $string['consentdetails'] = 'Consent details';
45 | $string['consentpagetitle'] = 'Consent';
46 | $string['dataproc'] = 'Personal data processing';
47 | $string['deleting'] = 'Deleting a version';
48 | $string['deleteconfirm'] = 'Are you sure you want to delete policy \'{$a->name}\' ?
This operation can not be undone.
';
49 | $string['editingpolicydocument'] = 'Editing policy';
50 | $string['errorpolicyversionnotfound'] = 'There isn\'t any policy version with this identifier.';
51 | $string['errorsaveasdraft'] = 'Minor change can not be saved as draft';
52 | $string['errorusercantviewpolicyversion'] = 'The user hasn\'t access to this policy version.';
53 | $string['event_acceptance_created'] = 'User policy agreement created';
54 | $string['event_acceptance_updated'] = 'User policy agreement updated';
55 | $string['filtercapabilityno'] = 'Permission: Can not agree';
56 | $string['filtercapabilityyes'] = 'Permission: Can agree';
57 | $string['filterrevision'] = 'Version: {$a}';
58 | $string['filterrevisionstatus'] = 'Version: {$a->name} ({$a->status})';
59 | $string['filterrole'] = 'Role: {$a}';
60 | $string['filters'] = 'Filters';
61 | $string['filterstatusno'] = 'Status: Not agreed';
62 | $string['filterstatusyes'] = 'Status: Agreed';
63 | $string['filterplaceholder'] = 'Search keyword or select filter';
64 | $string['filterpolicy'] = 'Policy: {$a}';
65 | $string['guestconsent:continue'] = 'Continue';
66 | $string['guestconsentmessage'] = 'If you continue browsing this website, you agree to our policies:';
67 | $string['iagree'] = 'I agree to the {$a}';
68 | $string['iagreetothepolicy'] = 'I agree to the policy';
69 | $string['inactivate'] = 'Set status to "Inactive"';
70 | $string['inactivating'] = 'Inactivating a policy';
71 | $string['inactivatingconfirm'] = 'You are about to inactivate policy \'{$a->name}\' version \'{$a->revision}\' .
The policy will not apply until some version is made the current one.
';
72 | $string['invalidversionid'] = 'There is no policy with this identifier!';
73 | $string['minorchange'] = 'Minor change';
74 | $string['minorchangeinfo'] = 'Minor changes do not amend the meaning of the policy text, terms or conditions. Users do not need to reconfirm their consent.';
75 | $string['managepolicies'] = 'Manage policies';
76 | $string['movedown'] = 'Move down';
77 | $string['moveup'] = 'Move up';
78 | $string['mustagreetocontinue'] = 'Before continuing you must agree to all these policies.';
79 | $string['newpolicy'] = 'New policy';
80 | $string['newversion'] = 'New version';
81 | $string['nofiltersapplied'] = 'No filters applied';
82 | $string['nopermissiontoagreedocs'] = 'No permission to agree to the policies';
83 | $string['nopermissiontoagreedocs_desc'] = 'Sorry, you do not have the required permissions to agree to the policies. You will not be able to use this site until the following policies are agreed:';
84 | $string['nopermissiontoagreedocsbehalf'] = 'No permission to agree to the policies on behalf of this user';
85 | $string['nopermissiontoagreedocsbehalf_desc'] = 'Sorry, you do not have the required permission to agree to the following policies on behalf of {$a}:';
86 | $string['nopermissiontoagreedocscontact'] = 'For further assistance, please contact the following person:';
87 | $string['nopermissiontoviewpolicyversion'] = 'You do not have permissions to view this policy version.';
88 | $string['nopolicies'] = 'There are no policies for registered users with an active version.';
89 | $string['selectpolicyandversion'] = 'Use the filter above to select policy and/or version';
90 | $string['steppolicies'] = 'Policy {$a->numpolicy} out of {$a->totalpolicies}';
91 | $string['pluginname'] = 'Policies';
92 | $string['policiesagreements'] = 'Policies and agreements';
93 | $string['policy:accept'] = 'Agree to the policies';
94 | $string['policy:acceptbehalf'] = 'Agree to the policies on someone else\'s behalf';
95 | $string['policy:managedocs'] = 'Manage policies';
96 | $string['policy:manageprivacy'] = 'Manage privacy settings';
97 | $string['policy:viewacceptances'] = 'View user agreement reports';
98 | $string['policydocaudience'] = 'User consent';
99 | $string['policydocaudience0'] = 'All users';
100 | $string['policydocaudience1'] = 'Authenticated users';
101 | $string['policydocaudience2'] = 'Guests';
102 | $string['policydoccontent'] = 'Full policy';
103 | $string['policydochdrpolicy'] = 'Policy';
104 | $string['policydochdrversion'] = 'Document version';
105 | $string['policydocname'] = 'Name';
106 | $string['policydocrevision'] = 'Version';
107 | $string['policydocsummary'] = 'Summary';
108 | $string['policydocsummary_help'] = 'This text should provide a summary of the policy, potentially in a simplified and easily accessible form, using clear and plain language.';
109 | $string['policydoctype'] = 'Type';
110 | $string['policydoctype0'] = 'Site policy';
111 | $string['policydoctype1'] = 'Privacy policy';
112 | $string['policydoctype2'] = 'Third parties policy';
113 | $string['policydoctype99'] = 'Other policy';
114 | $string['policyversionacceptedinbehalf'] = 'This policy version has been agreed to by another user on behalf of you.';
115 | $string['policyversionacceptedinotherlang'] = 'This policy version has been agreed to in a different language.';
116 | $string['previousversions'] = '{$a} previous versions';
117 | $string['privacyofficer'] = 'Privacy officer';
118 | // TODO: Review the list of places where the privacyofficer will be shown.
119 | $string['privacyofficer_desc'] = 'Information and contact details of the privacy officer, such as the address, email and phone number. This information will be shown to the users on the consent page.';
120 | $string['privacysettings'] = 'Privacy settings';
121 | $string['readpolicy'] = 'Please read our {$a}';
122 | $string['refertofullpolicytext'] = 'Please refer to the full {$a} text if you would like to review.';
123 | $string['save'] = 'Save';
124 | $string['saveasdraft'] = 'Save as draft';
125 | $string['status'] = 'Policy status';
126 | $string['statusinfo'] = 'An active policy will require consent from new users. Existing users will need to consent to this policy on their next logged in session.';
127 | $string['status0'] = 'Draft';
128 | $string['status1'] = 'Active';
129 | $string['status2'] = 'Inactive';
130 | $string['useracceptancecount'] = '{$a->agreedcount} of {$a->userscount} ({$a->percent}%)';
131 | $string['useracceptancecountna'] = 'N/A';
132 | $string['useracceptances'] = 'User agreements';
133 | $string['userpolicysettings'] = 'Policies';
134 | $string['usersaccepted'] = 'Agreements';
135 | $string['viewarchived'] = 'View previous versions';
136 | $string['viewconsentpageforuser'] = 'Viewing this page on behalf of {$a}';
137 | $string['agreedno'] = 'Not agreed';
138 | $string['agreedyes'] = 'Agreed';
139 | $string['agreedyesonbehalf'] = 'Agreed on behalf of';
140 |
--------------------------------------------------------------------------------
/tests/behat/signup.feature:
--------------------------------------------------------------------------------
1 | @tool @tool_policy
2 | Feature: User must accept policy managed by this plugin when logging in and signing up
3 | In order to record user agreement to use the site
4 | As a user
5 | I need to be able to accept site policy during sign up
6 |
7 | Scenario: Accept policy on sign up, no site policy
8 | Given the following config values are set as admin:
9 | | registerauth | email |
10 | | passwordpolicy | 0 |
11 | | sitepolicyhandler | tool_policy |
12 | And I am on site homepage
13 | And I follow "Log in"
14 | When I press "Create new account"
15 | Then I should not see "I understand and agree"
16 | And I set the following fields to these values:
17 | | Username | user1 |
18 | | Password | user1 |
19 | | Email address | user1@address.invalid |
20 | | Email (again) | user1@address.invalid |
21 | | First name | User1 |
22 | | Surname | L1 |
23 | And I press "Create my new account"
24 | And I should see "Confirm your account"
25 | And I should see "An email should have been sent to your address at user1@address.invalid"
26 | And I confirm email for "user1"
27 | And I should see "Thanks, User1 L1"
28 | And I should see "Your registration has been confirmed"
29 | And I open my profile in edit mode
30 | And the field "First name" matches value "User1"
31 | And I log out
32 | # Confirm that user can login and browse the site (edit their profile).
33 | And I log in as "user1"
34 | And I open my profile in edit mode
35 | And the field "First name" matches value "User1"
36 |
37 | Scenario: Accept policy on sign up, one policy
38 | Given the following config values are set as admin:
39 | | registerauth | email |
40 | | passwordpolicy | 0 |
41 | | sitepolicyhandler | tool_policy |
42 | Given the following policies exist:
43 | | Policy | Name | Revision | Content | Summary | Status |
44 | | P1 | This site policy | | full text1 | short text1 | archived |
45 | | P1 | This site policy | | full text2 | short text2 | active |
46 | | P1 | This site policy | | full text3 | short text3 | draft |
47 | And I am on site homepage
48 | And I follow "Log in"
49 | When I press "Create new account"
50 | Then I should see "This site policy"
51 | And I should see "short text2"
52 | And I should see "full text2"
53 | And I press "Next"
54 | And I should see "Please agree to the following policies"
55 | And I should see "This site policy"
56 | And I should see "short text2"
57 | And I should not see "full text2"
58 | And I set the field "I agree to the This site policy" to "1"
59 | And I press "Next"
60 | And I should not see "I understand and agree"
61 | And I set the following fields to these values:
62 | | Username | user1 |
63 | | Password | user1 |
64 | | Email address | user1@address.invalid |
65 | | Email (again) | user1@address.invalid |
66 | | First name | User1 |
67 | | Surname | L1 |
68 | And I press "Create my new account"
69 | And I should see "Confirm your account"
70 | And I should see "An email should have been sent to your address at user1@address.invalid"
71 | And I confirm email for "user1"
72 | And I should see "Thanks, User1 L1"
73 | And I should see "Your registration has been confirmed"
74 | And I open my profile in edit mode
75 | And the field "First name" matches value "User1"
76 | And I log out
77 | # Confirm that user can login and browse the site.
78 | And I log in as "user1"
79 | And I follow "Profile" in the user menu
80 | # User can see his own agreements in the profile.
81 | And I follow "Policies and agreements"
82 | And "Agreed" "icon" should exist in the "This site policy" "table_row"
83 | And I log out
84 |
85 | Scenario: Accept policy on sign up, multiple policies
86 | Given the following config values are set as admin:
87 | | registerauth | email |
88 | | passwordpolicy | 0 |
89 | | sitepolicyhandler | tool_policy |
90 | Given the following policies exist:
91 | | Name | Type | Revision | Content | Summary | Status | Audience |
92 | | This site policy | 0 | | full text2 | short text2 | active | all |
93 | | This privacy policy | 1 | | full text3 | short text3 | active | loggedin |
94 | | This guests policy | 0 | | full text4 | short text4 | active | guest |
95 | And I am on site homepage
96 | And I follow "Log in"
97 | When I press "Create new account"
98 | Then I should see "This site policy"
99 | And I should see "short text2"
100 | And I should see "full text2"
101 | And I press "Next"
102 | And I should see "This privacy policy"
103 | And I should see "short text3"
104 | And I should see "full text3"
105 | And I press "Next"
106 | And I should see "Please agree to the following policies"
107 | And I should see "This site policy"
108 | And I should see "short text2"
109 | And I should not see "full text2"
110 | And I should see "This privacy policy"
111 | And I should see "short text3"
112 | And I should not see "full text3"
113 | And I should not see "This guests policy"
114 | And I should not see "short text4"
115 | And I should not see "full text4"
116 | And I set the field "I agree to the This site policy" to "1"
117 | And I set the field "I agree to the This privacy policy" to "1"
118 | And I press "Next"
119 | And I should not see "I understand and agree"
120 | And I set the following fields to these values:
121 | | Username | user1 |
122 | | Password | user1 |
123 | | Email address | user1@address.invalid |
124 | | Email (again) | user1@address.invalid |
125 | | First name | User1 |
126 | | Surname | L1 |
127 | And I press "Create my new account"
128 | And I should see "Confirm your account"
129 | And I should see "An email should have been sent to your address at user1@address.invalid"
130 | And I confirm email for "user1"
131 | And I should see "Thanks, User1 L1"
132 | And I should see "Your registration has been confirmed"
133 | And I open my profile in edit mode
134 | And the field "First name" matches value "User1"
135 | And I log out
136 | # Confirm that user can login and browse the site.
137 | And I log in as "user1"
138 | And I follow "Profile" in the user menu
139 | # User can see his own agreements in the profile.
140 | And I follow "Policies and agreements"
141 | And "Agreed" "icon" should exist in the "This site policy" "table_row"
142 | And "Agreed" "icon" should exist in the "This privacy policy" "table_row"
143 | And I should not see "This guests policy"
144 | And I log out
145 |
146 | Scenario: Accept policy on sign up and age verification
147 | Given the following config values are set as admin:
148 | | registerauth | email |
149 | | passwordpolicy | 0 |
150 | | sitepolicyhandler | tool_policy |
151 | | agedigitalconsentverification | 1 |
152 | Given the following policies exist:
153 | | Name | Revision | Content | Summary | Status |
154 | | This site policy | | full text2 | short text2 | active |
155 | And I am on site homepage
156 | And I follow "Log in"
157 | When I press "Create new account"
158 | Then I should see "Age and location verification"
159 | And I set the field "What is your age?" to "16"
160 | And I set the field "In which country do you live?" to "DZ"
161 | And I press "Proceed"
162 | And I should see "This site policy"
163 | And I should see "short text2"
164 | And I should see "full text2"
165 | And I press "Next"
166 | And I should see "Please agree to the following policies"
167 | And I should see "This site policy"
168 | And I should see "short text2"
169 | And I should not see "full text2"
170 | And I set the field "I agree to the This site policy" to "1"
171 | And I press "Next"
172 | And I should not see "I understand and agree"
173 | And I set the following fields to these values:
174 | | Username | user1 |
175 | | Password | user1 |
176 | | Email address | user1@address.invalid |
177 | | Email (again) | user1@address.invalid |
178 | | First name | User1 |
179 | | Surname | L1 |
180 | And I press "Create my new account"
181 | And I should see "Confirm your account"
182 | And I should see "An email should have been sent to your address at user1@address.invalid"
183 | And I confirm email for "user1"
184 | And I should see "Thanks, User1 L1"
185 | And I should see "Your registration has been confirmed"
186 | And I open my profile in edit mode
187 | And the field "First name" matches value "User1"
188 | And I log out
189 | # Confirm that user can login and browse the site.
190 | And I log in as "user1"
191 | And I follow "Profile" in the user menu
192 | # User can see his own agreements in the profile.
193 | And I follow "Policies and agreements"
194 | And "Agreed" "icon" should exist in the "This site policy" "table_row"
195 | And I log out
196 |
--------------------------------------------------------------------------------
/amd/src/jquery-eu-cookie-law-popup.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * JQUERY EU COOKIE LAW POPUPS
4 | * version 1.0.1
5 | *
6 | * Code on Github:
7 | * https://github.com/wimagguc/jquery-eu-cookie-law-popup
8 | *
9 | * To see a live demo, go to:
10 | * http://www.wimagguc.com/2015/03/jquery-eu-cookie-law-popup/
11 | *
12 | * by Richard Dancsi
13 | * http://www.wimagguc.com/
14 | *
15 | */
16 |
17 | define(
18 | ['jquery'],
19 | function($) {
20 |
21 | // for ie9 doesn't support debug console >>>
22 | if (!window.console) {
23 | window.console = {};
24 | }
25 | if (!window.console.log) {
26 | window.console.log = function () {
27 | };
28 | }
29 | // ^^^
30 |
31 | $.fn.euCookieLawPopup = (function() {
32 |
33 | var _self = this;
34 |
35 | ///////////////////////////////////////////////////////////////////////////////////////////////
36 | // PARAMETERS (MODIFY THIS PART) //////////////////////////////////////////////////////////////
37 | _self.params = {
38 | cookiePolicyUrl : 'http://www.wimagguc.com/?cookie-policy',
39 | popupPosition : 'top',
40 | colorStyle : 'default',
41 | compactStyle : false,
42 | popupTitle : 'This website is using cookies',
43 | popupText : 'We use cookies to ensure that we give you the best experience on our website. ' +
44 | 'If you continue without changing your settings, we\'ll assume that you are happy to ' +
45 | 'receive all cookies on this website.',
46 | buttonContinueTitle : 'Continue',
47 | buttonLearnmoreTitle : 'Learn more',
48 | buttonLearnmoreOpenInNewWindow : true,
49 | agreementExpiresInDays : 30,
50 | autoAcceptCookiePolicy : false,
51 | htmlMarkup : null
52 | };
53 |
54 | ///////////////////////////////////////////////////////////////////////////////////////////////
55 | // VARIABLES USED BY THE FUNCTION (DON'T MODIFY THIS PART) ////////////////////////////////////
56 | _self.vars = {
57 | INITIALISED : false,
58 | HTML_MARKUP : null,
59 | COOKIE_NAME : 'EU_COOKIE_LAW_CONSENT'
60 | };
61 |
62 | ///////////////////////////////////////////////////////////////////////////////////////////////
63 | // PRIVATE FUNCTIONS FOR MANIPULATING DATA ////////////////////////////////////////////////////
64 |
65 | // Overwrite default parameters if any of those is present
66 | var parseParameters = function(object, markup, settings) {
67 |
68 | if (object) {
69 | var className = $(object).attr('class') ? $(object).attr('class') : '';
70 | if (className.indexOf('eupopup-top') > -1) {
71 | _self.params.popupPosition = 'top';
72 | }
73 | else if (className.indexOf('eupopup-fixedtop') > -1) {
74 | _self.params.popupPosition = 'fixedtop';
75 | }
76 | else if (className.indexOf('eupopup-bottomright') > -1) {
77 | _self.params.popupPosition = 'bottomright';
78 | }
79 | else if (className.indexOf('eupopup-bottomleft') > -1) {
80 | _self.params.popupPosition = 'bottomleft';
81 | }
82 | else if (className.indexOf('eupopup-bottom') > -1) {
83 | _self.params.popupPosition = 'bottom';
84 | }
85 | else if (className.indexOf('eupopup-block') > -1) {
86 | _self.params.popupPosition = 'block';
87 | }
88 | if (className.indexOf('eupopup-color-default') > -1) {
89 | _self.params.colorStyle = 'default';
90 | }
91 | else if (className.indexOf('eupopup-color-inverse') > -1) {
92 | _self.params.colorStyle = 'inverse';
93 | }
94 | if (className.indexOf('eupopup-style-compact') > -1) {
95 | _self.params.compactStyle = true;
96 | }
97 | }
98 |
99 | if (markup) {
100 | _self.params.htmlMarkup = markup;
101 | }
102 |
103 | if (settings) {
104 | if (typeof settings.cookiePolicyUrl !== 'undefined') {
105 | _self.params.cookiePolicyUrl = settings.cookiePolicyUrl;
106 | }
107 | if (typeof settings.popupPosition !== 'undefined') {
108 | _self.params.popupPosition = settings.popupPosition;
109 | }
110 | if (typeof settings.colorStyle !== 'undefined') {
111 | _self.params.colorStyle = settings.colorStyle;
112 | }
113 | if (typeof settings.popupTitle !== 'undefined') {
114 | _self.params.popupTitle = settings.popupTitle;
115 | }
116 | if (typeof settings.popupText !== 'undefined') {
117 | _self.params.popupText = settings.popupText;
118 | }
119 | if (typeof settings.buttonContinueTitle !== 'undefined') {
120 | _self.params.buttonContinueTitle = settings.buttonContinueTitle;
121 | }
122 | if (typeof settings.buttonLearnmoreTitle !== 'undefined') {
123 | _self.params.buttonLearnmoreTitle = settings.buttonLearnmoreTitle;
124 | }
125 | if (typeof settings.buttonLearnmoreOpenInNewWindow !== 'undefined') {
126 | _self.params.buttonLearnmoreOpenInNewWindow = settings.buttonLearnmoreOpenInNewWindow;
127 | }
128 | if (typeof settings.agreementExpiresInDays !== 'undefined') {
129 | _self.params.agreementExpiresInDays = settings.agreementExpiresInDays;
130 | }
131 | if (typeof settings.autoAcceptCookiePolicy !== 'undefined') {
132 | _self.params.autoAcceptCookiePolicy = settings.autoAcceptCookiePolicy;
133 | }
134 | if (typeof settings.htmlMarkup !== 'undefined') {
135 | _self.params.htmlMarkup = settings.htmlMarkup;
136 | }
137 | }
138 |
139 | };
140 |
141 | var createHtmlMarkup = function() {
142 |
143 | if (_self.params.htmlMarkup) {
144 | return _self.params.htmlMarkup;
145 | }
146 |
147 | var html =
148 | '';
163 |
164 | return html;
165 | };
166 |
167 | // Storing the consent in a cookie
168 | var setUserAcceptsCookies = function(consent) {
169 | var d = new Date();
170 | var expiresInDays = _self.params.agreementExpiresInDays * 24 * 60 * 60 * 1000;
171 | d.setTime( d.getTime() + expiresInDays );
172 | var expires = "expires=" + d.toGMTString();
173 | document.cookie = _self.vars.COOKIE_NAME + '=' + consent + "; " + expires + ";path=/";
174 |
175 | $(document).trigger("user_cookie_consent_changed", {'consent' : consent});
176 | };
177 |
178 | // Let's see if we have a consent cookie already
179 | var userAlreadyAcceptedCookies = function() {
180 | var userAcceptedCookies = false;
181 | var cookies = document.cookie.split(";");
182 | for (var i = 0; i < cookies.length; i++) {
183 | var c = cookies[i].trim();
184 | if (c.indexOf(_self.vars.COOKIE_NAME) == 0) {
185 | userAcceptedCookies = c.substring(_self.vars.COOKIE_NAME.length + 1, c.length);
186 | }
187 | }
188 |
189 | return userAcceptedCookies;
190 | };
191 |
192 | var hideContainer = function() {
193 | // $('.eupopup-container').slideUp(200);
194 | $('.eupopup-container').animate({
195 | opacity: 0,
196 | height: 0
197 | }, 200, function() {
198 | $('.eupopup-container').hide(0);
199 | });
200 | };
201 |
202 | ///////////////////////////////////////////////////////////////////////////////////////////////
203 | // PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////
204 | var publicfunc = {
205 |
206 | // INITIALIZE EU COOKIE LAW POPUP /////////////////////////////////////////////////////////
207 | init : function(settings) {
208 |
209 | parseParameters(
210 | $(".eupopup").first(),
211 | $(".eupopup-markup").html(),
212 | settings);
213 |
214 | // No need to display this if user already accepted the policy
215 | if (userAlreadyAcceptedCookies()) {
216 | return;
217 | }
218 |
219 | // We should initialise only once
220 | if (_self.vars.INITIALISED) {
221 | return;
222 | }
223 | _self.vars.INITIALISED = true;
224 |
225 | // Markup and event listeners >>>
226 | _self.vars.HTML_MARKUP = createHtmlMarkup();
227 |
228 | if ($('.eupopup-block').length > 0) {
229 | $('.eupopup-block').append(_self.vars.HTML_MARKUP);
230 | } else {
231 | $('BODY').append(_self.vars.HTML_MARKUP);
232 | }
233 |
234 | $('.eupopup-button_1').click(function() {
235 | setUserAcceptsCookies(true);
236 | hideContainer();
237 | return false;
238 | });
239 | $('.eupopup-closebutton').click(function() {
240 | setUserAcceptsCookies(true);
241 | hideContainer();
242 | return false;
243 | });
244 | // ^^^ Markup and event listeners
245 |
246 | // Ready to start!
247 | $('.eupopup-container').show();
248 |
249 | // In case it's alright to just display the message once
250 | if (_self.params.autoAcceptCookiePolicy) {
251 | setUserAcceptsCookies(true);
252 | }
253 |
254 | }
255 |
256 | };
257 |
258 | return publicfunc;
259 | });
260 |
261 | });
262 |
--------------------------------------------------------------------------------
/classes/output/page_managedocs_list.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link tool_policy\output\page_managedocs_list} class.
19 | *
20 | * @package tool_policy
21 | * @category output
22 | * @copyright 2018 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace tool_policy\output;
27 |
28 | use html_writer;
29 | use tool_policy\api;
30 |
31 | defined('MOODLE_INTERNAL') || die();
32 |
33 | use action_menu;
34 | use action_menu_link;
35 | use moodle_url;
36 | use pix_icon;
37 | use renderable;
38 | use renderer_base;
39 | use single_button;
40 | use templatable;
41 | use tool_policy\policy_version;
42 |
43 | /**
44 | * Represents a management page with the list of policy documents.
45 | *
46 | * The page displays all policy documents in their sort order, together with draft future versions.
47 | *
48 | * @copyright 2018 David Mudrak
49 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
50 | */
51 | class page_managedocs_list implements renderable, templatable {
52 |
53 | /** @var int */
54 | protected $policyid = null;
55 | /** @var moodle_url */
56 | protected $returnurl = null;
57 |
58 | /**
59 | * page_managedocs_list constructor.
60 | * @param int $policyid when specified only archived versions of this policy will be displayed.
61 | */
62 | public function __construct($policyid = null) {
63 | $this->policyid = $policyid;
64 | $this->returnurl = new moodle_url('/admin/tool/policy/managedocs.php');
65 | if ($this->policyid) {
66 | $this->returnurl->param('archived', $this->policyid);
67 | }
68 | }
69 |
70 | /**
71 | * Export the page data for the mustache template.
72 | *
73 | * @param renderer_base $output renderer to be used to render the page elements.
74 | * @return stdClass
75 | */
76 | public function export_for_template(renderer_base $output) {
77 |
78 | $data = (object) [];
79 | $data->pluginbaseurl = (new moodle_url('/admin/tool/policy'))->out(false);
80 | $data->canmanage = has_capability('tool/policy:managedocs', \context_system::instance());
81 | $data->canaddnew = $data->canmanage && !$this->policyid;
82 | $data->canviewacceptances = has_capability('tool/policy:viewacceptances', \context_system::instance());
83 | $data->title = get_string('policiesagreements', 'tool_policy');
84 | $data->policies = [];
85 |
86 | if ($this->policyid) {
87 | // We are only interested in the archived versions of the given policy.
88 | $data->backurl = (new moodle_url('/admin/tool/policy/managedocs.php'))->out(false);
89 | $policy = api::list_policies([$this->policyid], true)[0];
90 | if ($firstversion = $policy->currentversion ?: (reset($policy->draftversions) ?: reset($policy->archivedversions))) {
91 | $data->title = get_string('previousversions', 'tool_policy', format_string($firstversion->name));
92 | }
93 |
94 | foreach ($policy->archivedversions as $i => $version) {
95 | $data->versions[] = $this->export_version_for_template($output, $policy, $version,
96 | policy_version::STATUS_ARCHIVED, false, false, false);
97 | }
98 | return $data;
99 | }
100 |
101 | // List all policies. Display current and all draft versions of each policy in this list.
102 | // If none found, then show only one archived version.
103 | $policies = api::list_policies(null, true);
104 | foreach ($policies as $i => $policy) {
105 |
106 | if (empty($policy->currentversion) && empty($policy->draftversions)) {
107 | // There is no current and no draft versions, display the first archived version.
108 | $firstpolicy = array_shift($policy->archivedversions);
109 | $data->versions[] = $this->export_version_for_template($output, $policy, $firstpolicy,
110 | policy_version::STATUS_ARCHIVED, false, $i > 0, $i < count($policies) - 1);
111 | }
112 |
113 | if (!empty($policy->currentversion)) {
114 |
115 | // Current version of the policy.
116 | $data->versions[] = $this->export_version_for_template($output, $policy, $policy->currentversion,
117 | policy_version::STATUS_ACTIVE, false, $i > 0, $i < count($policies) - 1);
118 |
119 | } else if ($policy->draftversions) {
120 |
121 | // There is no current version, display the first draft version as the current.
122 | $firstpolicy = array_shift($policy->draftversions);
123 | $data->versions[] = $this->export_version_for_template($output, $policy, $firstpolicy,
124 | policy_version::STATUS_DRAFT, false, $i > 0, $i < count($policies) - 1);
125 | }
126 |
127 | foreach ($policy->draftversions as $draft) {
128 | // Show all [other] draft policies indented.
129 | $data->versions[] = $this->export_version_for_template($output, $policy, $draft,
130 | policy_version::STATUS_DRAFT, true, false, false);
131 | }
132 |
133 | }
134 |
135 | return $data;
136 | }
137 |
138 | /**
139 | * Exports one version for the list of policies
140 | *
141 | * @param \renderer_base $output
142 | * @param \stdClass $policy
143 | * @param \stdClass $version
144 | * @param int $status
145 | * @param bool $isindented display indented (normally drafts of the current version)
146 | * @param bool $moveup can move up
147 | * @param bool $movedown can move down
148 | * @return \stdClass
149 | */
150 | protected function export_version_for_template($output, $policy, $version, $status, $isindented, $moveup, $movedown) {
151 |
152 | $version->statustext = get_string('status' . $status, 'tool_policy');
153 |
154 | if ($status == policy_version::STATUS_ACTIVE) {
155 | $version->statustext = html_writer::span($version->statustext, 'label label-success');
156 | } else if ($status == policy_version::STATUS_DRAFT) {
157 | $version->statustext = html_writer::span($version->statustext, 'label label-warning');
158 | } else {
159 | $version->statustext = html_writer::span($version->statustext, 'label');
160 | }
161 |
162 | $version->indented = $isindented;
163 |
164 | $editbaseurl = new moodle_url('/admin/tool/policy/editpolicydoc.php', [
165 | 'sesskey' => sesskey(),
166 | 'policyid' => $policy->id,
167 | 'returnurl' => $this->returnurl->out_as_local_url(false),
168 | ]);
169 |
170 | $viewurl = new moodle_url('/admin/tool/policy/view.php', [
171 | 'policyid' => $policy->id,
172 | 'versionid' => $version->id,
173 | 'manage' => 1,
174 | 'returnurl' => $this->returnurl->out_as_local_url(false),
175 | ]);
176 |
177 | $actionmenu = new action_menu();
178 | $actionmenu->set_menu_trigger(get_string('actions', 'tool_policy'));
179 | $actionmenu->set_alignment(action_menu::TL, action_menu::BL);
180 | $actionmenu->prioritise = true;
181 | if ($moveup) {
182 | $actionmenu->add(new action_menu_link(
183 | new moodle_url($editbaseurl, ['moveup' => $policy->id]),
184 | new pix_icon('t/up', get_string('moveup', 'tool_policy')),
185 | get_string('moveup', 'tool_policy'),
186 | true
187 | ));
188 | }
189 | if ($movedown) {
190 | $actionmenu->add(new action_menu_link(
191 | new moodle_url($editbaseurl, ['movedown' => $policy->id]),
192 | new pix_icon('t/down', get_string('movedown', 'tool_policy')),
193 | get_string('movedown', 'tool_policy'),
194 | true
195 | ));
196 | }
197 | $actionmenu->add(new action_menu_link(
198 | $viewurl,
199 | null,
200 | get_string('view'),
201 | false
202 | ));
203 | if ($status != policy_version::STATUS_ARCHIVED) {
204 | $actionmenu->add(new action_menu_link(
205 | new moodle_url($editbaseurl, ['versionid' => $version->id]),
206 | null,
207 | get_string('edit'),
208 | false
209 | ));
210 | }
211 | if ($status == policy_version::STATUS_ACTIVE) {
212 | $actionmenu->add(new action_menu_link(
213 | new moodle_url($editbaseurl, ['inactivate' => $policy->id]),
214 | null,
215 | get_string('inactivate', 'tool_policy'),
216 | false
217 | ));
218 | }
219 | if ($status == policy_version::STATUS_DRAFT) {
220 | $actionmenu->add(new action_menu_link(
221 | new moodle_url($editbaseurl, ['makecurrent' => $version->id]),
222 | null,
223 | get_string('activate', 'tool_policy'),
224 | false
225 | ));
226 | }
227 | if ($status == policy_version::STATUS_DRAFT) {
228 | // TODO can we also delete non-draft version that is guest only or has no acceptances?
229 | $actionmenu->add(new action_menu_link(
230 | new moodle_url($editbaseurl, ['delete' => $version->id]),
231 | null,
232 | get_string('delete'),
233 | false
234 | ));
235 | }
236 | if (!$this->policyid && !$isindented && $policy->archivedversions &&
237 | ($status != policy_version::STATUS_ARCHIVED || count($policy->archivedversions) > 1)) {
238 | $actionmenu->add(new action_menu_link(
239 | new moodle_url('/admin/tool/policy/managedocs.php', ['archived' => $policy->id]),
240 | null,
241 | get_string('viewarchived', 'tool_policy'),
242 | false
243 | ));
244 | }
245 |
246 | $version->actionmenu = $actionmenu->export_for_template($output);
247 | return $version;
248 | }
249 | }
250 |
--------------------------------------------------------------------------------