├── pix ├── level.png ├── agreedno.png ├── agreedyes.png ├── agreedyesonbehalf.png ├── agreedyes.svg ├── agreedyesonbehalf.svg ├── agreedno.svg └── level.svg ├── thirdpartylibs.xml ├── amd ├── build │ ├── acceptances_filter_datasource.min.js │ ├── policyactions.min.js │ ├── acceptances_filter.min.js │ └── jquery-eu-cookie-law-popup.min.js └── src │ ├── acceptances_filter_datasource.js │ ├── policyactions.js │ ├── acceptances_filter.js │ └── jquery-eu-cookie-law-popup.js ├── README.md ├── .travis.yml ├── version.php ├── db ├── events.php ├── caches.php ├── services.php ├── access.php └── install.xml ├── templates ├── page_viewalldoc.mustache ├── user_agreement.mustache ├── acceptances_filter.mustache ├── page_nopermission.mustache ├── page_viewdoc.mustache ├── guestconsent.mustache ├── page_managedocs_list.mustache ├── page_agreedocs.mustache └── acceptances.mustache ├── managedocs.php ├── viewall.php ├── styles.css ├── settings.php ├── classes ├── output │ ├── renderer.php │ ├── guestconsent.php │ ├── user_agreement.php │ ├── page_viewalldoc.php │ ├── acceptances.php │ ├── page_viewdoc.php │ ├── page_nopermission.php │ └── page_managedocs_list.php ├── form │ ├── accept_policy.php │ └── policydoc.php ├── policy_exporter.php ├── event │ ├── acceptance_created.php │ └── acceptance_updated.php ├── policy_version.php ├── privacy │ └── local │ │ └── sitepolicy │ │ └── handler.php ├── policy_version_exporter.php └── external.php ├── view.php ├── index.php ├── acceptances.php ├── user.php ├── tests └── behat │ ├── behat_tool_policy.php │ └── signup.feature ├── lib.php ├── editpolicydoc.php └── lang └── en └── tool_policy.php /pix/level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_policy/MOODLE_33_STABLE/pix/level.png -------------------------------------------------------------------------------- /pix/agreedno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_policy/MOODLE_33_STABLE/pix/agreedno.png -------------------------------------------------------------------------------- /pix/agreedyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_policy/MOODLE_33_STABLE/pix/agreedyes.png -------------------------------------------------------------------------------- /pix/agreedyesonbehalf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_policy/MOODLE_33_STABLE/pix/agreedyesonbehalf.png -------------------------------------------------------------------------------- /thirdpartylibs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | amd/src/jquery-eu-cookie-law-popup.js 5 | jQuery EU Cookie Law popups 6 | MIT 7 | 1.0.1 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pix/agreedyes.svg: -------------------------------------------------------------------------------- 1 | 3 | ]> -------------------------------------------------------------------------------- /pix/agreedyesonbehalf.svg: -------------------------------------------------------------------------------- 1 | 3 | ]> -------------------------------------------------------------------------------- /pix/agreedno.svg: -------------------------------------------------------------------------------- 1 | 3 | ]> -------------------------------------------------------------------------------- /amd/build/acceptances_filter_datasource.min.js: -------------------------------------------------------------------------------- 1 | define(["jquery","core/ajax","core/notification"],function(a,b,c){return{list:function(b,c){var d=[],e=a(b),f=a(b).data("originaloptionsjson"),g=e.val();a.each(f,function(b,e){return""!==a.trim(c)&&e.label.toLocaleLowerCase().indexOf(c.toLocaleLowerCase())===-1||(a.inArray(e.value,g)>-1||(d.push(e),!0))});var h=new a.Deferred;return h.resolve(d),h.promise()},processResults:function(b,c){var d=[];return a.each(c,function(a,b){d.push({value:b.value,label:b.label})}),d},transport:function(a,b,d){this.list(a,b).then(d)["catch"](c.exception)}}}); -------------------------------------------------------------------------------- /amd/build/policyactions.min.js: -------------------------------------------------------------------------------- 1 | define(["jquery","core/ajax","core/notification","core/modal_factory","core/modal_events"],function(a,b,c,d,e){var f={VIEW_POLICY:'[data-action="view"]'},g=function(){this.registerEvents()};return g.prototype.registerEvents=function(){a(f.VIEW_POLICY).click(function(f){f.preventDefault();var g=a(this).data("versionid"),h=a(this).data("behalfid"),i={versionid:g,behalfid:h},j={methodname:"tool_policy_get_policy_version",args:i},k=b.call([j]),l="",m=d.types.DEFAULT;a.when(k[0]).then(function(a){return a.result.policy?(l=a.result.policy.name,a.result.policy.content):(c.addNotification({message:a.warnings[0].message,type:"error"}),!1)}).then(function(a){if(0!=a)return d.create({title:l,body:a,type:m,large:!0}).then(function(a){return a.getRoot().on(e.hidden,function(){a.destroy()}),a})}).done(function(a){a.show()}).fail(c.exception)})},g}); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Policies # 2 | 3 | Moodle plugin allowing to define various policy documents - site policy, privacy 4 | policy, intellectual property policy, late assignments policy and others as needed. It 5 | keeps the history of document revisions, tracks user agreements with them and forces 6 | users to accept them prior to using the site. 7 | 8 | ## License ## 9 | 10 | This program is free software: you can redistribute it and/or modify it under 11 | the terms of the GNU General Public License as published by the Free Software 12 | Foundation, either version 3 of the License, or (at your option) any later 13 | version. 14 | 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along with 20 | this program. If not, see . 21 | -------------------------------------------------------------------------------- /amd/build/acceptances_filter.min.js: -------------------------------------------------------------------------------- 1 | define(["jquery","core/form-autocomplete","core/str","core/notification"],function(a,b,c,d){var e={UNIFIED_FILTERS:"#unified-filters"},f=function(){var f=[{key:"filterplaceholder",component:"tool_policy"},{key:"nofiltersapplied",component:"tool_policy"}];M.util.js_pending("acceptances_filter_datasource"),c.get_strings(f).done(function(a){var c=a[0],f=a[1];b.enhance(e.UNIFIED_FILTERS,!0,"tool_policy/acceptances_filter_datasource",c,!1,!0,f,!0).then(function(){M.util.js_complete("acceptances_filter_datasource")}).fail(d.exception)}).fail(d.exception);var g=a(e.UNIFIED_FILTERS).val();a(e.UNIFIED_FILTERS).on("change",function(){var b=a(this).val(),c=[],d=[],e=!1;if(a.each(b,function(a,b){var f=b.split(":",2);if(2!==f.length)return d.push(b),!0;var g=f[0],h=f[1];return"undefined"!=typeof c[g]&&(e=!0),c[g]=h,!0}),e){var f=[];for(var h in c)f.push(h+":"+c[h]);f=f.concat(d),a(this).val(f)}g.join(",")!=b.join(",")&&this.form.submit()})},g=function(){return a(e.UNIFIED_FILTERS).closest("form")};return{init:function(){f()},getForm:function(){return g()}}}); -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | addons: 6 | firefox: "47.0.1" 7 | postgresql: "9.3" 8 | apt: 9 | packages: 10 | - oracle-java8-installer 11 | - oracle-java8-set-default 12 | 13 | cache: 14 | directories: 15 | - $HOME/.composer/cache 16 | - $HOME/.npm 17 | 18 | php: 19 | - 5.6 20 | - 7.1 21 | 22 | env: 23 | global: 24 | - MOODLE_BRANCH=MOODLE_33_STABLE 25 | matrix: 26 | - DB=pgsql 27 | - DB=mysqli 28 | 29 | before_install: 30 | - phpenv config-rm xdebug.ini 31 | - nvm install 8.9 32 | - nvm use 8.9 33 | - cd ../.. 34 | - composer create-project -n --no-dev --prefer-dist moodlerooms/moodle-plugin-ci ci ^2 35 | - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" 36 | 37 | install: 38 | - moodle-plugin-ci install 39 | 40 | script: 41 | - moodle-plugin-ci phplint 42 | - moodle-plugin-ci phpcpd 43 | - moodle-plugin-ci phpmd 44 | - moodle-plugin-ci codechecker 45 | - moodle-plugin-ci validate 46 | - moodle-plugin-ci savepoints 47 | - moodle-plugin-ci mustache 48 | - moodle-plugin-ci grunt 49 | - moodle-plugin-ci phpunit 50 | - moodle-plugin-ci behat 51 | -------------------------------------------------------------------------------- /version.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 | $plugin->component = 'tool_policy'; 28 | $plugin->release = '33.0.0'; 29 | $plugin->version = 2017051509; 30 | $plugin->requires = 2017051505; 31 | $plugin->maturity = MATURITY_BETA; 32 | -------------------------------------------------------------------------------- /db/events.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file defines observers needed by the plugin. 19 | * 20 | * @package tool_policy 21 | * @copyright 2018 Mihail Geshoski 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $observers = [ 28 | [ 29 | 'eventname' => '\core\event\user_created', 30 | 'callback' => '\tool_policy\api::create_acceptances_user_created', 31 | ], 32 | ]; 33 | -------------------------------------------------------------------------------- /db/caches.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Cache definitions. 19 | * 20 | * @package tool_policy 21 | * @copyright 2018 Mihail Geshoski 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $definitions = array( 28 | // This is user's tool policy session cache. 29 | // This cache is used to store policy user data such as 30 | // viewed policy documents, etc. 31 | 'toolpolicy' => array( 32 | 'mode' => cache_store::MODE_SESSION, 33 | 'simplekeys' => true, 34 | 'simpledata' => true, 35 | 'ttl' => 1800, 36 | ), 37 | ); 38 | -------------------------------------------------------------------------------- /templates/page_viewalldoc.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 for viewing all policy versions, one under another. 19 | 20 | Classes required for JS: 21 | - 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * policies - policy array 28 | }} 29 | 30 | {{#policies }} 31 |
32 |
33 |

{{{name}}}

34 |
35 |
36 | {{{summary}}} 37 |
38 |
39 | {{{content}}} 40 |
41 |
42 |
43 | 44 | {{/policies }} 45 | -------------------------------------------------------------------------------- /db/services.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Tool policy external functions and service definitions. 19 | * 20 | * @package tool_policy 21 | * @category external 22 | * @copyright 2018 Sara Arjona (sara@moodle.com) 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die; 27 | 28 | $functions = [ 29 | 'tool_policy_get_policy_version' => [ 30 | 'classname' => 'tool_policy\external', 31 | 'methodname' => 'get_policy_version', 32 | 'classpath' => '', 33 | 'description' => 'Fetch the details of a policy version', 34 | 'type' => 'read', 35 | 'capabilities' => '', 36 | 'ajax' => true, 37 | 'loginrequired' => false, 38 | ], 39 | ]; 40 | -------------------------------------------------------------------------------- /managedocs.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage policy documents used on the site. 19 | * 20 | * Script arguments: 21 | * - archived= Show only archived versions of the given policy document 22 | * 23 | * @package tool_policy 24 | * @copyright 2018 David Mudrák 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | require(__DIR__.'/../../../config.php'); 29 | require_once($CFG->libdir.'/adminlib.php'); 30 | 31 | $archived = optional_param('archived', 0, PARAM_INT); 32 | 33 | admin_externalpage_setup('tool_policy_managedocs', '', ['archived' => $archived]); 34 | 35 | $output = $PAGE->get_renderer('tool_policy'); 36 | 37 | $manpage = new \tool_policy\output\page_managedocs_list($archived); 38 | 39 | echo $output->header(); 40 | echo $output->render($manpage); 41 | echo $output->footer(); 42 | -------------------------------------------------------------------------------- /viewall.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * View all document policy with a version, one under another. 19 | * 20 | * Script parameters: 21 | * - 22 | * 23 | * @package tool_policy 24 | * @copyright 2018 Sara Arjona (sara@moodle.com) 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | use tool_policy\api; 29 | use tool_policy\output\page_viewalldoc; 30 | 31 | // Do not check for the site policies in require_login() to avoid the redirect loop. 32 | define('NO_SITEPOLICY_CHECK', true); 33 | 34 | // @codingStandardsIgnoreLine See the {@link page_viewalldoc} for the access control checks. 35 | require(__DIR__.'/../../../config.php'); 36 | 37 | $viewallpage = new page_viewalldoc(); 38 | 39 | $output = $PAGE->get_renderer('tool_policy'); 40 | 41 | echo $output->header(); 42 | echo $output->render($viewallpage); 43 | echo $output->footer(); 44 | -------------------------------------------------------------------------------- /templates/user_agreement.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 for the user agreement icon. 19 | 20 | Classes required for JS: 21 | - 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * status 28 | * onbehalf 29 | * canaccept 30 | * acceptlink 31 | }} 32 | {{#status}} 33 | 34 | {{#onbehalf}} 35 | {{#pix}}agreedyesonbehalf, tool_policy, {{#str}} agreedyesonbehalf, tool_policy {{/str}}{{/pix}} 36 | {{/onbehalf}} 37 | {{^onbehalf}} 38 | {{#pix}}agreedyes, tool_policy, {{#str}} agreedyes, tool_policy {{/str}}{{/pix}} 39 | {{/onbehalf}} 40 | {{/status}} 41 | {{^status}} 42 | {{#canaccept}} 43 | {{#pix}}agreedno, tool_policy, {{#str}} agreedno, tool_policy {{/str}}{{/pix}} 44 | {{/canaccept}} 45 | {{^canaccept}} 46 | {{#pix}}agreedno, tool_policy, {{#str}} agreedno, tool_policy {{/str}}{{/pix}} 47 | {{/canaccept}} 48 | {{/status}} 49 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* eupopup styles */ 2 | .eupopup-body li { 3 | display: inline; 4 | } 5 | 6 | .eupopup-body li:before { 7 | content: ", "; 8 | } 9 | 10 | .eupopup-body li:first-child:before { 11 | content: ""; 12 | } 13 | 14 | .eupopup-container { 15 | background-color: rgba(25, 25, 25, 0.9); 16 | color: #efefef; 17 | padding: 5px 20px; 18 | font-size: 12px; 19 | line-height: 1.2em; 20 | text-align: center; 21 | display: none; 22 | z-index: 9999999; 23 | } 24 | 25 | .eupopup-container-bottom { 26 | position: fixed; 27 | bottom: 0; 28 | left: 0; 29 | right: 0; 30 | } 31 | 32 | .eupopup-closebutton { 33 | font-size: 16px; 34 | font-weight: 100; 35 | line-height: 1; 36 | color: #a2a2a2; 37 | filter: alpha(opacity=20); 38 | position: absolute; 39 | font-family: helvetica, arial, verdana, sans-serif; 40 | top: 0; 41 | right: 0; 42 | padding: 5px 10px; 43 | } 44 | 45 | .eupopup-closebutton:hover, 46 | .eupopup-closebutton:active { 47 | text-decoration: none; 48 | } 49 | 50 | .eupopup-head { 51 | font-size: 1.2em; 52 | font-weight: bold; 53 | padding: 7px; 54 | } 55 | 56 | .eupopup-body ul { 57 | padding: 0; 58 | margin: 0 0 3px; 59 | } 60 | 61 | .eupopup-buttons { 62 | padding: 7px 0 5px 0; 63 | } 64 | 65 | .eupopup-button_1 { 66 | font-weight: bold; 67 | font-size: 14px; 68 | } 69 | 70 | .eupopup-button_2 { 71 | display: none; 72 | } 73 | 74 | .eupopup-button { 75 | margin: 0 10px; 76 | color: #f6a21d; 77 | } 78 | 79 | .eupopup-button:hover, 80 | .eupopup-button:focus { 81 | text-decoration: underline; 82 | color: #f6a21d; 83 | } 84 | 85 | 86 | .policy-heading .policy-viewdoc-buttons { 87 | text-align: center; 88 | margin: 15px; 89 | } 90 | 91 | /* TODO https://github.com/moodle/moodle/commit/bd6f87ed82519fb0d2e0c6877fbbe7c7fa155376 */ -------------------------------------------------------------------------------- /db/access.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin capabilities are defined here. 19 | * 20 | * @package tool_policy 21 | * @category access 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 | $capabilities = [ 29 | 30 | 'tool/policy:accept' => [ 31 | 'captype' => 'write', 32 | 'contextlevel' => CONTEXT_SYSTEM, 33 | 'archetypes' => [ 34 | 'user' => CAP_ALLOW, 35 | ], 36 | ], 37 | 38 | 'tool/policy:acceptbehalf' => [ 39 | 'riskbitmask' => RISK_PERSONAL, 40 | 'captype' => 'write', 41 | 'contextlevel' => CONTEXT_USER, 42 | 'archetypes' => [ 43 | ], 44 | ], 45 | 46 | 'tool/policy:manageprivacy' => [ 47 | 'captype' => 'write', 48 | 'contextlevel' => CONTEXT_SYSTEM, 49 | 'archetypes' => [ 50 | 'manager' => CAP_ALLOW, 51 | ], 52 | ], 53 | 54 | 'tool/policy:managedocs' => [ 55 | 'captype' => 'write', 56 | 'contextlevel' => CONTEXT_SYSTEM, 57 | 'archetypes' => [ 58 | 'manager' => CAP_ALLOW, 59 | ], 60 | ], 61 | 62 | 'tool/policy:viewacceptances' => [ 63 | 'captype' => 'read', 64 | 'contextlevel' => CONTEXT_SYSTEM, 65 | 'archetypes' => [ 66 | 'manager' => CAP_ALLOW, 67 | ], 68 | ], 69 | ]; 70 | -------------------------------------------------------------------------------- /settings.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin administration pages 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 | // Do nothing if we are not set as the site policies handler. 28 | if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') { 29 | return; 30 | } 31 | 32 | $managecaps = [ 33 | 'tool/policy:managedocs', 34 | 'tool/policy:manageprivacy', 35 | 'tool/policy:viewacceptances', 36 | ]; 37 | 38 | if ($hassiteconfig || has_any_capability($managecaps, context_system::instance())) { 39 | 40 | $ADMIN->add('privacy', new admin_externalpage( 41 | 'tool_policy_managedocs', 42 | new lang_string('managepolicies', 'tool_policy'), 43 | new moodle_url('/admin/tool/policy/managedocs.php'), 44 | ['tool/policy:managedocs', 'tool/policy:viewacceptances'] 45 | )); 46 | $ADMIN->add('privacy', new admin_externalpage( 47 | 'tool_policy_acceptances', 48 | new lang_string('useracceptances', 'tool_policy'), 49 | new moodle_url('/admin/tool/policy/acceptances.php'), 50 | ['tool/policy:viewacceptances'] 51 | )); 52 | 53 | if ($ADMIN->fulltree) { 54 | // TODO: Decide whether to maintain or not this field for displaying information about the officer in the consent page. 55 | $temp = $ADMIN->locate('privacysettings'); 56 | $temp->add(new admin_setting_configtextarea( 57 | 'tool_policy/privacyofficer', 58 | new lang_string('privacyofficer', 'tool_policy'), 59 | new lang_string('privacyofficer_desc', 'tool_policy'), 60 | '', 61 | PARAM_RAW 62 | )); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pix/level.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 55 | 60 | 61 | -------------------------------------------------------------------------------- /classes/output/renderer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Provides {@link tool_policy\output\renderer} 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 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | use core\output\mustache_template_finder; 31 | use plugin_renderer_base; 32 | use renderable; 33 | use Exception; 34 | 35 | /** 36 | * Renderer for the policies plugin. 37 | * 38 | * @copyright 2018 David Mudrak 39 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 | */ 41 | class renderer extends plugin_renderer_base { 42 | 43 | /** 44 | * Overrides the parent so that templatable widgets are handled even without their explicit render method. 45 | * 46 | * @param renderable $widget 47 | * @return string 48 | */ 49 | public function render(renderable $widget) { 50 | 51 | $namespacedclassname = get_class($widget); 52 | $plainclassname = preg_replace('/^.*\\\/', '', $namespacedclassname); 53 | $rendermethod = 'render_'.$plainclassname; 54 | 55 | if (method_exists($this, $rendermethod)) { 56 | // Explicit rendering method exists, fall back to the default behaviour. 57 | return parent::render($widget); 58 | } 59 | 60 | $interfaces = class_implements($namespacedclassname); 61 | 62 | if (isset($interfaces['templatable'])) { 63 | // Default implementation of template-based rendering. 64 | $data = $widget->export_for_template($this); 65 | return parent::render_from_template('tool_policy/'.$plainclassname, $data); 66 | 67 | } else { 68 | return parent::render($widget); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /view.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * View current document policy version. 19 | * 20 | * Script parameters: 21 | * versionid= Policy version id, defaults to the current one. 22 | * policyid= Policy document id, defaults to the one matching the version. 23 | * returnurl= URL to continue to after reading the policy document. 24 | * behalfid= The user id to view the policy version as (such as child's id). 25 | * manage= View the policy as a part of the management UI (managedocs.php). 26 | * 27 | * @package tool_policy 28 | * @copyright 2018 Sara Arjona (sara@moodle.com) 29 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 | */ 31 | 32 | use tool_policy\api; 33 | use tool_policy\output\page_viewdoc; 34 | 35 | // Do not check for the site policies in require_login() to avoid the redirect loop. 36 | define('NO_SITEPOLICY_CHECK', true); 37 | 38 | // @codingStandardsIgnoreLine See the {@link page_viewdoc} for the access control checks. 39 | require(__DIR__.'/../../../config.php'); 40 | 41 | $versionid = optional_param('versionid', null, PARAM_INT); 42 | $policyid = $versionid ? optional_param('policyid', null, PARAM_INT) : required_param('policyid', PARAM_INT); 43 | $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); 44 | $behalfid = optional_param('behalfid', null, PARAM_INT); 45 | $manage = optional_param('manage', false, PARAM_BOOL); 46 | $numpolicy = optional_param('numpolicy', null, PARAM_INT); 47 | $totalpolicies = optional_param('totalpolicies', null, PARAM_INT); 48 | 49 | $PAGE->set_context(context_system::instance()); 50 | $PAGE->set_pagelayout('standard'); 51 | 52 | $viewpage = new page_viewdoc($policyid, $versionid, $returnurl, $behalfid, $manage, $numpolicy, $totalpolicies); 53 | 54 | $output = $PAGE->get_renderer('tool_policy'); 55 | 56 | echo $output->header(); 57 | echo $output->render($viewpage); 58 | echo $output->footer(); 59 | -------------------------------------------------------------------------------- /templates/acceptances_filter.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_filter 19 | 20 | Template for the unified filter element. 21 | 22 | Context variables required for this template: 23 | * action string - The action URL for the form. 24 | * filteroptions - Array of filter options. 25 | * value string - The option value. 26 | * label string - The option label. 27 | * selected boolean - Whether the option is selected 28 | 29 | Example context (json): 30 | { 31 | "action": "/admin/tool/policy/acceptances.php", 32 | "filteroptions": [ 33 | { 34 | "value": "1", 35 | "label": "Option 1" 36 | }, 37 | { 38 | "value": "2", 39 | "label": "Option 2", 40 | "selected": true 41 | }, 42 | { 43 | "value": "3", 44 | "label": "Option 3", 45 | "selected": true 46 | }, 47 | { 48 | "value": "4", 49 | "label": "Option 4" 50 | } 51 | ] 52 | } 53 | }} 54 | 63 | {{#js}} 64 | require(['tool_policy/acceptances_filter'], function(Filter) { 65 | Filter.init(); 66 | }); 67 | {{/js}} 68 | -------------------------------------------------------------------------------- /templates/page_nopermission.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 for showing to the user the policy docs to agree. 19 | 20 | Classes required for JS: 21 | * policyactions 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * pluginbaseurl 28 | * haspermissionagreedocs - status of the capability of the user to accept policy documents 29 | * messagetitle - Message title to display, with the error. 30 | * messagedesc - Message description to display, with the error. 31 | * supportname - name of the support contact; displayed when the user does not have permission to accept policy documents 32 | * supportemail - email of the support contact; displayed when the user does not have permission to accept policy documents 33 | * behalfuser - If behalfid is defined and valid, full name of the behalf user with a link to his/her profile; null otherwise 34 | * policies - Array with all the links to current policies (for showing them if needed). 35 | }} 36 | 37 | {{^haspermissionagreedocs}} 38 |

{{{messagetitle}}}

39 |

{{{messagedesc}}}

40 | 41 |
42 |
    43 | {{# policies }} 44 |
  • {{{.}}}
  • 45 | {{/ policies }} 46 |
47 |
48 | 49 |

{{#str}}nopermissiontoagreedocscontact, tool_policy{{/str}}

50 |
51 |
52 |

{{{supportname}}}

53 |

{{supportemail}}

54 |
55 |
56 | {{/haspermissionagreedocs}} 57 | 58 | {{#js}} 59 | // Initialise the JS for the modal window which displays the policy versions. 60 | require(['tool_policy/policyactions'], function(ActionsMod) { 61 | var policyActions = new ActionsMod(); 62 | }); 63 | {{/js}} 64 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Show a user the policy documents to be agreed to. 19 | * 20 | * Script parameters: 21 | * agreedoc= Policy version id which have been accepted by the user. 22 | * behalfid= The user id to view the policy version as (such as child's id). 23 | * 24 | * @package tool_policy 25 | * @copyright 2018 Sara Arjona (sara@moodle.com) 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | use tool_policy\api; 30 | use tool_policy\output\page_agreedocs; 31 | 32 | // Do not check for the site policies in require_login() to avoid the redirect loop. 33 | define('NO_SITEPOLICY_CHECK', true); 34 | 35 | // @codingStandardsIgnoreLine See the {@link page_agreedocs} for the access control checks. 36 | require(__DIR__.'/../../../config.php'); 37 | 38 | $agreedocs = optional_param_array('agreedoc', null, PARAM_INT); 39 | $behalfid = optional_param('userid', null, PARAM_INT); 40 | 41 | $PAGE->set_context(context_system::instance()); 42 | $PAGE->set_url('/admin/tool/policy/index.php'); 43 | $PAGE->set_popup_notification_allowed(false); 44 | 45 | $haspermissionagreedocs = false; 46 | if (!empty($USER->id)) { 47 | // Existing user. 48 | if (empty($behalfid) || $behalfid == $USER->id) { 49 | $haspermissionagreedocs = has_capability('tool/policy:accept', context_system::instance()); 50 | } else { 51 | $usercontext = \context_user::instance($behalfid); 52 | $haspermissionagreedocs = has_capability('tool/policy:acceptbehalf', $usercontext); 53 | } 54 | } else { 55 | // New user. 56 | $haspermissionagreedocs = true; 57 | } 58 | 59 | if (!$haspermissionagreedocs) { 60 | $outputpage = new \tool_policy\output\page_nopermission($behalfid); 61 | } else { 62 | $outputpage = new \tool_policy\output\page_agreedocs($agreedocs, $behalfid); 63 | } 64 | 65 | $output = $PAGE->get_renderer('tool_policy'); 66 | 67 | echo $output->header(); 68 | echo $output->render($outputpage); 69 | echo $output->footer(); 70 | -------------------------------------------------------------------------------- /classes/output/guestconsent.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 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | use moodle_url; 31 | use renderable; 32 | use renderer_base; 33 | use templatable; 34 | use tool_policy\api; 35 | use tool_policy\policy_version; 36 | 37 | /** 38 | * Renderer for the policies plugin. 39 | * 40 | * @copyright 2018 Sara Arjona 41 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 42 | */ 43 | class guestconsent implements renderable, templatable { 44 | 45 | /** 46 | * Export the page data for the mustache template. 47 | * 48 | * @param renderer_base $output renderer to be used to render the page elements. 49 | * @return stdClass 50 | */ 51 | public function export_for_template(renderer_base $output) { 52 | global $PAGE; 53 | 54 | $data = (object) []; 55 | $data->pluginbaseurl = (new moodle_url('/admin/tool/policy'))->out(true); 56 | if (strpos(qualified_me(), '/tool/policy/view.php') === false) { 57 | // Current page is not a policy doc, so returnurl parameter will be it. 58 | $data->returnurl = qualified_me(); 59 | } else { 60 | // If current page is also a policy doc to view, get previous returnurl parameter to avoid error. 61 | $returnurl = $PAGE->url->get_param('returnurl'); 62 | if (isset($returnurl)) { 63 | $data->returnurl = $returnurl; 64 | } 65 | } 66 | $data->returnurl = urlencode($data->returnurl); 67 | 68 | $policies = api::list_current_versions(policy_version::AUDIENCE_GUESTS); 69 | $data->policies = array_values($policies); 70 | 71 | return $data; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /templates/page_viewdoc.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 for viewing a policy version document. 19 | 20 | Classes required for JS: 21 | - 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * policy - version document object. 28 | }} 29 | 30 | 31 |
32 |
33 |

{{policy.name}}

34 |
35 | {{# numpolicy }} 36 |
37 | {{# str }} steppolicies, tool_policy, 38 | { "numpolicy": {{# quote }}{{numpolicy}}{{/quote }}, "totalpolicies": {{# quote }}{{totalpolicies}}{{/ quote }} } 39 | {{/ str }} 40 |
41 | {{/ numpolicy }} 42 |
43 | 44 | 45 | {{# numpolicy }} 46 |
47 |

{{# str }}readpolicy, tool_policy, {{policy.name}} {{/ str }}

48 |
49 | {{/ numpolicy }} 50 | 51 |
52 | 53 |
54 |
55 | {{{policy.summary}}} 56 |
57 |
58 | {{{policy.content}}} 59 |
60 |
61 | 62 |
63 | 64 |
65 | {{#returnurl}} 66 | {{# numpolicy }} 67 | {{#str}} next {{/str}} 68 | {{/ numpolicy }} 69 | {{^ numpolicy }} 70 | {{#str}} continue {{/str}} 71 | {{/ numpolicy }} 72 | {{/returnurl}} 73 | {{#editurl}} 74 | {{#str}} edit {{/str}} 75 | {{/editurl}} 76 | 77 | 83 |
84 | -------------------------------------------------------------------------------- /acceptances.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * View user acceptances to the policies 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 | require(__DIR__.'/../../../config.php'); 26 | require_once($CFG->libdir.'/adminlib.php'); 27 | 28 | use core\output\notification; 29 | 30 | $policyid = optional_param('policyid', null, PARAM_INT); 31 | $versionid = optional_param('versionid', null, PARAM_INT); 32 | $versionid = optional_param('versionid', null, PARAM_INT); 33 | $filtersapplied = optional_param_array('unified-filters', [], PARAM_NOTAGS); 34 | 35 | $acceptancesfilter = new \tool_policy\output\acceptances_filter($policyid, $versionid, $filtersapplied); 36 | $policyid = $acceptancesfilter->get_policy_id_filter(); 37 | $versionid = $acceptancesfilter->get_version_id_filter(); 38 | 39 | // Set up the page as an admin page 'tool_policy_managedocs'. 40 | $urlparams = ($policyid ? ['policyid' => $policyid] : []) + ($versionid ? ['versionid' => $versionid] : []); 41 | admin_externalpage_setup('tool_policy_acceptances', '', $urlparams, 42 | new moodle_url('/admin/tool/policy/acceptances.php')); 43 | 44 | $acceptancesfilter->validate_ids(); 45 | $output = $PAGE->get_renderer('tool_policy'); 46 | if ($acceptancesfilter->get_versions()) { 47 | $acceptances = new \tool_policy\acceptances_table('tool_policy_user_acceptances', $acceptancesfilter, $output); 48 | if ($acceptances->is_downloading()) { 49 | $acceptances->download(); 50 | } 51 | } 52 | 53 | echo $output->header(); 54 | echo $output->heading(get_string('useracceptances', 'tool_policy')); 55 | echo $output->render($acceptancesfilter); 56 | if (!empty($acceptances)) { 57 | $acceptances->display(); 58 | } else if ($acceptancesfilter->get_avaliable_policies()) { 59 | // There are no non-guest policies. 60 | echo $output->notification(get_string('selectpolicyandversion', 'tool_policy'), notification::NOTIFY_INFO); 61 | } else { 62 | // There are no non-guest policies. 63 | echo $output->notification(get_string('nopolicies', 'tool_policy'), notification::NOTIFY_INFO); 64 | } 65 | echo $output->footer(); 66 | -------------------------------------------------------------------------------- /classes/output/user_agreement.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Provides {@link tool_policy\output\user_agreement} 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 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | use moodle_url; 31 | use renderable; 32 | use renderer_base; 33 | use single_button; 34 | use templatable; 35 | 36 | /** 37 | * List of users and their acceptances 38 | * 39 | * @copyright 2018 Marina Glancy 40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 | */ 42 | class user_agreement implements \templatable, \renderable { 43 | 44 | /** @var array */ 45 | protected $data; 46 | 47 | /** 48 | * user_agreement constructor 49 | * 50 | * @param int $userid 51 | * @param bool $status 52 | * @param moodle_url $pageurl 53 | * @param int $versionid 54 | * @param bool $onbehalf whether accepted on behalf of the user 55 | */ 56 | public function __construct($userid, $status, moodle_url $pageurl, $versionid, $onbehalf = false) { 57 | $this->data = [ 58 | 'userid' => $userid, 59 | 'status' => (int)(bool)$status, 60 | 'versionid' => $versionid, 61 | 'onbehalf' => $onbehalf, 62 | 'pageurl' => $pageurl 63 | ]; 64 | } 65 | 66 | /** 67 | * Export data to be rendered. 68 | * 69 | * @param renderer_base $output 70 | * @return stdClass 71 | */ 72 | public function export_for_template(\renderer_base $output) { 73 | $data = [ 74 | 'status' => $this->data['status'], 75 | 'onbehalf' => $this->data['onbehalf'], 76 | ]; 77 | if ($this->data['versionid'] && !$this->data['status'] && 78 | has_capability('tool/policy:acceptbehalf', \context_user::instance($this->data['userid']))) { 79 | $link = new \moodle_url('/admin/tool/policy/user.php', 80 | ['acceptforversion' => $this->data['versionid'], 'userid' => $this->data['userid'], 81 | 'returnurl' => $this->data['pageurl']->out_as_local_url(false)]); 82 | $data['canaccept'] = 1; 83 | $data['acceptlink'] = $link->out(false); 84 | } 85 | return $data; 86 | } 87 | } -------------------------------------------------------------------------------- /templates/guestconsent.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/guestconsent 19 | 20 | Template for the guest consent message. 21 | 22 | Classes required for JS: 23 | * eupopup 24 | * policyactions 25 | 26 | Data attributes required for JS: 27 | - 28 | 29 | Context variables required for this template: 30 | * pluginbaseurl 31 | * returnurl - urlencoded URL to return to 32 | * policies - array of policy documents 33 | 34 | Example context (json): 35 | { 36 | "pluginbaseurl": "https://example.com", 37 | "returnurl": "/", 38 | "policies": [ 39 | { 40 | "id": 1, 41 | "name": "Terms & conditions" 42 | } 43 | ] 44 | } 45 | }} 46 | 47 | {{#js}} 48 | 49 | require(['jquery', 'tool_policy/jquery-eu-cookie-law-popup', 'tool_policy/policyactions'], function($, Popup, ActionsMod) { 50 | // Initialise the guest popup. 51 | $(document).ready(function() { 52 | // Only show message if there is some policy related to guests. 53 | {{#policies.0}} 54 | // Get localised messages. 55 | var textmessage = "{{# str }} guestconsentmessage, tool_policy {{/ str }}" + 56 | ""; 65 | var continuemessage = "{{# str }} guestconsent:continue, tool_policy {{/ str }}"; 66 | 67 | // Initialize popup. 68 | $(document.body).addClass('eupopup'); 69 | if ($(".eupopup").length > 0) { 70 | $(document).euCookieLawPopup().init({ 71 | popupPosition : 'bottom', 72 | popupTitle : '', 73 | popupText : textmessage, 74 | buttonContinueTitle : continuemessage, 75 | buttonLearnmoreTitle : '', 76 | compactStyle : true, 77 | }); 78 | } 79 | {{/policies.0}} 80 | 81 | // Initialise the JS for the modal window which displays the policy versions. 82 | var policyActions = new ActionsMod(); 83 | }); 84 | }); 85 | 86 | {{/js}} 87 | -------------------------------------------------------------------------------- /classes/form/accept_policy.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Provides {@link tool_policy\form\accept_policy} 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\form; 26 | 27 | use tool_policy\policy_version; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | require_once($CFG->dirroot.'/lib/formslib.php'); 32 | 33 | /** 34 | * Represents the form for accepting a policy. 35 | * 36 | * @package tool_policy 37 | * @copyright 2018 Marina Glancy 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | */ 40 | class accept_policy extends \moodleform { 41 | 42 | /** 43 | * Defines the form fields. 44 | */ 45 | public function definition() { 46 | $mform = $this->_form; 47 | 48 | $users = $this->_customdata['users']; 49 | $versions = $this->_customdata['versions']; 50 | $usernames = []; 51 | foreach ($users as $user) { 52 | $usernames[] = fullname($user); 53 | } 54 | $policiesnames = []; 55 | foreach ($versions as $version) { 56 | $url = new \moodle_url('/admin/tool/policy/view.php', ['versionid' => $version->id]); 57 | $policyname = format_string($version->name); 58 | if ($version->status != policy_version::STATUS_ACTIVE) { 59 | $policyname .= ' ' . format_string($version->revision); 60 | } 61 | $policiesnames[] = \html_writer::link($url, $policyname); 62 | } 63 | 64 | $mform->addElement('hidden', 'userid'); 65 | $mform->setType('userid', PARAM_INT); 66 | 67 | $mform->addElement('hidden', 'acceptforversion'); 68 | $mform->setType('acceptforversion', PARAM_INT); 69 | 70 | $mform->addElement('hidden', 'returnurl'); 71 | $mform->setType('returnurl', PARAM_LOCALURL); 72 | 73 | $mform->addElement('static', 'user', get_string('acceptanceusers', 'tool_policy'), join(', ', $usernames)); 74 | $mform->addElement('static', 'policy', get_string('acceptancepolicies', 'tool_policy'), 75 | join(', ', $policiesnames)); 76 | 77 | $mform->addElement('static', 'ack', '', get_string('acceptanceacknowledgement', 'tool_policy')); 78 | 79 | $mform->addElement('textarea', 'note', get_string('acceptancenote', 'tool_policy')); 80 | $mform->setType('note', PARAM_NOTAGS); 81 | 82 | $this->add_action_buttons(true, get_string('iagreetothepolicy', 'tool_policy')); 83 | 84 | $this->set_data(['userid' => $user->id, 'acceptforversion' => $version->id]); 85 | } 86 | } -------------------------------------------------------------------------------- /user.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * View user acceptances to the policies 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 | require(__DIR__.'/../../../config.php'); 26 | require_once($CFG->dirroot.'/user/editlib.php'); 27 | 28 | $userid = optional_param('userid', null, PARAM_INT); 29 | $acceptforversion = optional_param('acceptforversion', null, PARAM_INT); 30 | $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); 31 | 32 | require_login(); 33 | $userid = $userid ?: $USER->id; 34 | if (isguestuser() || isguestuser($userid)) { 35 | print_error('noguest'); 36 | } 37 | $context = context_user::instance($userid); 38 | if ($acceptforversion) { 39 | // Check capability to accept the policy for oneself or on behalf of another user. 40 | if ($userid == $USER->id) { 41 | require_capability('tool/policy:accept', context_system::instance()); 42 | } else { 43 | require_capability('tool/policy:acceptbehalf', $context); 44 | } 45 | } else if ($userid != $USER->id) { 46 | // Check capability to view acceptances. No capability is needed to view your own acceptances. 47 | if (!has_capability('tool/policy:acceptbehalf', $context)) { 48 | require_capability('tool/policy:viewacceptances', $context); 49 | } 50 | } 51 | 52 | $PAGE->set_context($context); 53 | $PAGE->set_url(new moodle_url('/admin/tool/policy/user.php', ['userid' => $userid])); 54 | 55 | if ($acceptforversion) { 56 | $user = $DB->get_record('user', ['id' => $userid], 'id,'.get_all_user_name_fields(true), MUST_EXIST); 57 | $returnurl = $returnurl ? new moodle_url($returnurl) : new moodle_url('/admin/tool/policy/user.php', ['userid' => $user->id]); 58 | $version = tool_policy\api::get_policy_version($acceptforversion); 59 | $form = new \tool_policy\form\accept_policy(null, ['versions' => [$version], 'users' => [$user]]); 60 | $form->set_data(['returnurl' => $returnurl]); 61 | 62 | if ($form->is_cancelled()) { 63 | redirect($returnurl); 64 | } else if ($data = $form->get_data()) { 65 | \tool_policy\api::accept_policies([$acceptforversion], $user->id, $data->note); 66 | redirect($returnurl); 67 | } 68 | } 69 | 70 | $output = $PAGE->get_renderer('tool_policy'); 71 | echo $output->header(); 72 | if ($acceptforversion) { 73 | echo $output->heading(get_string('consentdetails', 'tool_policy')); 74 | $form->display(); 75 | } else { 76 | echo $output->heading(get_string('policiesagreements', 'tool_policy')); 77 | $acceptances = new \tool_policy\output\acceptances($userid); 78 | echo $output->render($acceptances); 79 | } 80 | echo $output->footer(); 81 | -------------------------------------------------------------------------------- /amd/src/acceptances_filter_datasource.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 | * Datasource for the tool_policy/acceptances_filter. 18 | * 19 | * This module is compatible with core/form-autocomplete. 20 | * 21 | * @package tool_policy 22 | * @copyright 2017 Jun Pataleta 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | define(['jquery', 'core/ajax', 'core/notification'], function($, Ajax, Notification) { 27 | 28 | return /** @alias module:tool_policy/acceptances_filter_datasource */ { 29 | /** 30 | * List filter options. 31 | * 32 | * @param {String} selector The select element selector. 33 | * @param {String} query The query string. 34 | * @return {Promise} 35 | */ 36 | list: function(selector, query) { 37 | var filteredOptions = []; 38 | 39 | var el = $(selector); 40 | var originalOptions = $(selector).data('originaloptionsjson'); 41 | var selectedFilters = el.val(); 42 | $.each(originalOptions, function(index, option) { 43 | // Skip option if it does not contain the query string. 44 | if ($.trim(query) !== '' && option.label.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) === -1) { 45 | return true; 46 | } 47 | // Skip filters that have already been selected. 48 | if ($.inArray(option.value, selectedFilters) > -1) { 49 | return true; 50 | } 51 | 52 | filteredOptions.push(option); 53 | return true; 54 | }); 55 | 56 | var deferred = new $.Deferred(); 57 | deferred.resolve(filteredOptions); 58 | 59 | return deferred.promise(); 60 | }, 61 | 62 | /** 63 | * Process the results for auto complete elements. 64 | * 65 | * @param {String} selector The selector of the auto complete element. 66 | * @param {Array} results An array or results. 67 | * @return {Array} New array of results. 68 | */ 69 | processResults: function(selector, results) { 70 | var options = []; 71 | $.each(results, function(index, data) { 72 | options.push({ 73 | value: data.value, 74 | label: data.label 75 | }); 76 | }); 77 | return options; 78 | }, 79 | 80 | /** 81 | * Source of data for Ajax element. 82 | * 83 | * @param {String} selector The selector of the auto complete element. 84 | * @param {String} query The query string. 85 | * @param {Function} callback A callback function receiving an array of results. 86 | */ 87 | /* eslint-disable promise/no-callback-in-promise */ 88 | transport: function(selector, query, callback) { 89 | this.list(selector, query).then(callback).catch(Notification.exception); 90 | } 91 | }; 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /classes/output/page_viewalldoc.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 | require_once("$CFG->libdir/filelib.php"); 33 | 34 | use context_system; 35 | use moodle_url; 36 | use renderable; 37 | use renderer_base; 38 | use single_button; 39 | use templatable; 40 | use tool_policy\api; 41 | use tool_policy\policy_version; 42 | 43 | /** 44 | * Represents a page for showing all the policy documents with a current version. 45 | * 46 | * @copyright 2018 Sara Arjona 47 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 48 | */ 49 | class page_viewalldoc implements renderable, templatable { 50 | 51 | /** 52 | * Prepare the page for rendering. 53 | * 54 | */ 55 | public function __construct() { 56 | 57 | $this->prepare_policies(); 58 | $this->prepare_global_page_access(); 59 | } 60 | 61 | /** 62 | * Loads the policy versions to display on the page. 63 | * 64 | */ 65 | protected function prepare_policies() { 66 | global $USER; 67 | 68 | if (isguestuser() || empty($USER->id)) { 69 | $audience = policy_version::AUDIENCE_GUESTS; 70 | } else { 71 | $audience = policy_version::AUDIENCE_LOGGEDIN; 72 | } 73 | $this->policies = api::list_current_versions($audience); 74 | } 75 | 76 | /** 77 | * Sets up the global $PAGE and performs the access checks. 78 | */ 79 | protected function prepare_global_page_access() { 80 | global $PAGE, $SITE, $USER; 81 | 82 | $myurl = new moodle_url('/admin/tool/policy/viewall.php', []); 83 | 84 | // Disable notifications for new users, guests or users who haven't agreed to the policies. 85 | if (isguestuser() || empty($USER->id) || !$USER->policyagreed) { 86 | $PAGE->set_popup_notification_allowed(false); 87 | } 88 | 89 | $PAGE->set_context(context_system::instance()); 90 | $PAGE->set_pagelayout('popup'); 91 | $PAGE->set_url($myurl); 92 | $PAGE->set_heading($SITE->fullname); 93 | $PAGE->set_title(get_string('policiesagreements', 'tool_policy')); 94 | } 95 | 96 | /** 97 | * Export the page data for the mustache template. 98 | * 99 | * @param renderer_base $output renderer to be used to render the page elements. 100 | * @return stdClass 101 | */ 102 | public function export_for_template(renderer_base $output) { 103 | 104 | $data = (object) [ 105 | 'pluginbaseurl' => (new moodle_url('/admin/tool/policy'))->out(false), 106 | ]; 107 | 108 | $data->policies = array_values($this->policies); 109 | 110 | return $data; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /amd/src/policyactions.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 | * Policy actions. 18 | * 19 | * @module tool_policy/policyactions 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 | define([ 25 | 'jquery', 26 | 'core/ajax', 27 | 'core/notification', 28 | 'core/modal_factory', 29 | 'core/modal_events'], 30 | function($, Ajax, Notification, ModalFactory, ModalEvents) { 31 | 32 | /** 33 | * List of action selectors. 34 | * 35 | * @type {{VIEW_POLICY: string}} 36 | */ 37 | var ACTIONS = { 38 | VIEW_POLICY: '[data-action="view"]' 39 | }; 40 | 41 | /** 42 | * PolicyActions class. 43 | */ 44 | var PolicyActions = function() { 45 | this.registerEvents(); 46 | }; 47 | 48 | /** 49 | * Register event listeners. 50 | */ 51 | PolicyActions.prototype.registerEvents = function() { 52 | $(ACTIONS.VIEW_POLICY).click(function(e) { 53 | e.preventDefault(); 54 | 55 | var versionid = $(this).data('versionid'); 56 | var behalfid = $(this).data('behalfid'); 57 | 58 | var params = { 59 | 'versionid': versionid, 60 | 'behalfid': behalfid 61 | }; 62 | 63 | var request = { 64 | methodname: 'tool_policy_get_policy_version', 65 | args: params 66 | }; 67 | 68 | var promises = Ajax.call([request]); 69 | var modalTitle = ''; 70 | var modalType = ModalFactory.types.DEFAULT; 71 | $.when(promises[0]).then(function(data) { 72 | if (data.result.policy) { 73 | modalTitle = data.result.policy.name; 74 | return data.result.policy.content; 75 | } 76 | // Fail. 77 | Notification.addNotification({ 78 | message: data.warnings[0].message, 79 | type: 'error' 80 | }); 81 | return false; 82 | 83 | }).then(function(html) { 84 | if (html != false) { 85 | return ModalFactory.create({ 86 | title: modalTitle, 87 | body: html, 88 | type: modalType, 89 | large: true 90 | }).then(function(modal) { 91 | // Handle hidden event. 92 | modal.getRoot().on(ModalEvents.hidden, function() { 93 | // Destroy when hidden. 94 | modal.destroy(); 95 | }); 96 | 97 | return modal; 98 | }); 99 | } 100 | }).done(function(modal) { 101 | // Show the modal. 102 | modal.show(); 103 | }).fail(Notification.exception); 104 | }); 105 | 106 | }; 107 | 108 | return PolicyActions; 109 | }); 110 | -------------------------------------------------------------------------------- /templates/page_managedocs_list.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 for the policy documents management page. 19 | 20 | Classes required for JS: 21 | - 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * haspolicies 28 | * policies 29 | }} 30 |

{{{title}}}

31 | {{#backurl}} 32 |
33 | 36 |
37 | {{/backurl}} 38 | {{#canaddnew}} 39 | 44 | {{/canaddnew}} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {{#canviewacceptances}} 54 | 55 | {{/canviewacceptances}} 56 | {{#canmanage}} 57 | 58 | {{/canmanage}} 59 | 60 | 61 | 62 | {{#versions}} 63 | 64 | 75 | 78 | 81 | 84 | {{#canviewacceptances}} 85 | 93 | {{/canviewacceptances}} 94 | {{#canmanage}} 95 | 100 | {{/canmanage}} 101 | 102 | {{/versions}} 103 | 104 |
{{#str}} policydocname, tool_policy {{/str}}{{#str}} status, tool_policy {{/str}}{{#str}} policydocrevision, tool_policy {{/str}}{{#str}} lastmodified, core {{/str}}{{#str}} usersaccepted, tool_policy {{/str}}
65 | {{#indented}} 66 |
67 | {{#pix}} level, tool_policy {{/pix}} 68 |
69 | {{/indented}} 70 |
71 |
{{{name}}}
72 |
{{{typetext}}}, {{{audiencetext}}}
73 |
74 |
76 | {{{statustext}}} 77 | 79 | {{revision}} 80 | 82 | {{#userdate}} {{timemodified}}, {{#str}} strftimedatetime, core_langconfig {{/str}} {{/userdate}} 83 | 86 | {{#acceptancescounturl}} 87 | {{acceptancescounttext}} 88 | {{/acceptancescounturl}} 89 | {{^acceptancescounturl}} 90 | {{acceptancescounttext}} 91 | {{/acceptancescounturl}} 92 | 96 | {{#actionmenu}} 97 | {{>core/action_menu}} 98 | {{/actionmenu}} 99 |
105 | -------------------------------------------------------------------------------- /amd/build/jquery-eu-cookie-law-popup.min.js: -------------------------------------------------------------------------------- 1 | define(["jquery"],function(a){window.console||(window.console={}),window.console.log||(window.console.log=function(){}),a.fn.euCookieLawPopup=function(){var b=this;b.params={cookiePolicyUrl:"http://www.wimagguc.com/?cookie-policy",popupPosition:"top",colorStyle:"default",compactStyle:!1,popupTitle:"This website is using cookies",popupText:"We use cookies to ensure that we give you the best experience on our website. If you continue without changing your settings, we'll assume that you are happy to receive all cookies on this website.",buttonContinueTitle:"Continue",buttonLearnmoreTitle:"Learn more",buttonLearnmoreOpenInNewWindow:!0,agreementExpiresInDays:30,autoAcceptCookiePolicy:!1,htmlMarkup:null},b.vars={INITIALISED:!1,HTML_MARKUP:null,COOKIE_NAME:"EU_COOKIE_LAW_CONSENT"};var c=function(c,d,e){if(c){var f=a(c).attr("class")?a(c).attr("class"):"";f.indexOf("eupopup-top")>-1?b.params.popupPosition="top":f.indexOf("eupopup-fixedtop")>-1?b.params.popupPosition="fixedtop":f.indexOf("eupopup-bottomright")>-1?b.params.popupPosition="bottomright":f.indexOf("eupopup-bottomleft")>-1?b.params.popupPosition="bottomleft":f.indexOf("eupopup-bottom")>-1?b.params.popupPosition="bottom":f.indexOf("eupopup-block")>-1&&(b.params.popupPosition="block"),f.indexOf("eupopup-color-default")>-1?b.params.colorStyle="default":f.indexOf("eupopup-color-inverse")>-1&&(b.params.colorStyle="inverse"),f.indexOf("eupopup-style-compact")>-1&&(b.params.compactStyle=!0)}d&&(b.params.htmlMarkup=d),e&&("undefined"!=typeof e.cookiePolicyUrl&&(b.params.cookiePolicyUrl=e.cookiePolicyUrl),"undefined"!=typeof e.popupPosition&&(b.params.popupPosition=e.popupPosition),"undefined"!=typeof e.colorStyle&&(b.params.colorStyle=e.colorStyle),"undefined"!=typeof e.popupTitle&&(b.params.popupTitle=e.popupTitle),"undefined"!=typeof e.popupText&&(b.params.popupText=e.popupText),"undefined"!=typeof e.buttonContinueTitle&&(b.params.buttonContinueTitle=e.buttonContinueTitle),"undefined"!=typeof e.buttonLearnmoreTitle&&(b.params.buttonLearnmoreTitle=e.buttonLearnmoreTitle),"undefined"!=typeof e.buttonLearnmoreOpenInNewWindow&&(b.params.buttonLearnmoreOpenInNewWindow=e.buttonLearnmoreOpenInNewWindow),"undefined"!=typeof e.agreementExpiresInDays&&(b.params.agreementExpiresInDays=e.agreementExpiresInDays),"undefined"!=typeof e.autoAcceptCookiePolicy&&(b.params.autoAcceptCookiePolicy=e.autoAcceptCookiePolicy),"undefined"!=typeof e.htmlMarkup&&(b.params.htmlMarkup=e.htmlMarkup))},d=function(){if(b.params.htmlMarkup)return b.params.htmlMarkup;var a='
'+b.params.popupTitle+'
'+b.params.popupText+'
x
';return a},e=function(c){var d=new Date,e=24*b.params.agreementExpiresInDays*60*60*1e3;d.setTime(d.getTime()+e);var f="expires="+d.toGMTString();document.cookie=b.vars.COOKIE_NAME+"="+c+"; "+f+";path=/",a(document).trigger("user_cookie_consent_changed",{consent:c})},f=function(){for(var a=!1,c=document.cookie.split(";"),d=0;d0?a(".eupopup-block").append(b.vars.HTML_MARKUP):a("BODY").append(b.vars.HTML_MARKUP),a(".eupopup-button_1").click(function(){return e(!0),g(),!1}),a(".eupopup-closebutton").click(function(){return e(!0),g(),!1}),a(".eupopup-container").show(),b.params.autoAcceptCookiePolicy&&e(!0))}};return h}}); -------------------------------------------------------------------------------- /classes/policy_exporter.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Provides the {@link tool_policy\policy_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 | 32 | /** 33 | * Exporter of a policy document model. 34 | * 35 | * @copyright 2018 David Mudrak 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class policy_exporter extends exporter { 39 | 40 | /** 41 | * Return the list of properties. 42 | * 43 | * @return array 44 | */ 45 | protected static function define_properties() { 46 | return [ 47 | 'id' => [ 48 | 'type' => PARAM_INT, 49 | ], 50 | 'sortorder' => [ 51 | 'type' => PARAM_INT, 52 | 'default' => 999, 53 | ], 54 | 'currentversionid' => [ 55 | 'type' => PARAM_INT, 56 | 'null' => NULL_ALLOWED, 57 | ], 58 | ]; 59 | } 60 | 61 | /** 62 | * Returns a list of objects that are related. 63 | * 64 | * @return array 65 | */ 66 | protected static function define_related() { 67 | return [ 68 | 'versions' => 'tool_policy\policy_version_exporter[]', 69 | ]; 70 | } 71 | 72 | /** 73 | * Return the list of additional, generated dynamically from the given properties. 74 | * 75 | * @return array 76 | */ 77 | protected static function define_other_properties() { 78 | return [ 79 | 'currentversion' => [ 80 | 'type' => policy_version_exporter::read_properties_definition(), 81 | 'null' => NULL_ALLOWED, 82 | ], 83 | 'draftversions' => [ 84 | 'type' => policy_version_exporter::read_properties_definition(), 85 | 'multiple' => true, 86 | ], 87 | 'archivedversions' => [ 88 | 'type' => policy_version_exporter::read_properties_definition(), 89 | 'multiple' => true, 90 | ], 91 | ]; 92 | } 93 | 94 | /** 95 | * Get the additional values to inject while exporting. 96 | * 97 | * @param renderer_base $output The renderer. 98 | * @return array Keys are the property names, values are their values. 99 | */ 100 | protected function get_other_values(renderer_base $output) { 101 | 102 | $othervalues = [ 103 | 'currentversion' => null, 104 | 'draftversions' => [], 105 | 'archivedversions' => [], 106 | ]; 107 | 108 | foreach ($this->related['versions'] as $exporter) { 109 | $data = $exporter->export($output); 110 | 111 | if ($data->id == $this->data->currentversionid) { 112 | $othervalues['currentversion'] = $data; 113 | 114 | } else if ($data->archived) { 115 | $othervalues['archivedversions'][] = $data; 116 | 117 | } else { 118 | $othervalues['draftversions'][] = $data; 119 | } 120 | } 121 | 122 | return $othervalues; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /templates/page_agreedocs.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 for showing to the user the policy docs to agree. 19 | 20 | Classes required for JS: 21 | * policyactions 22 | 23 | Data attributes required for JS: 24 | - 25 | 26 | Context variables required for this template: 27 | * pluginbaseurl 28 | * myurl 29 | * sesskey 30 | * policies - policy array 31 | * privacyofficer - string with the privacy officer information 32 | * behalfuser - If behalfid is defined and valid, full name of the behalf user with a link to his/her profile; null otherwise 33 | }} 34 | 35 | {{#messages}}{{{.}}}{{/messages}} 36 | 37 |
38 | 39 | 40 | {{#behalfuser}} 41 |
42 |
43 | {{# str }} viewconsentpageforuser, tool_policy, {{{ . }}} {{/ str }} 44 |
45 |
46 | {{/behalfuser}} 47 | 48 |
49 |
50 |

{{# str }}consentpagetitle, tool_policy{{/ str }}

51 |
52 |
53 | 54 |
55 |

{{# str }}agreepolicies, tool_policy {{/ str }}

56 |
57 |
58 | 59 | 60 | {{#policies}} 61 | 62 |
63 |

{{{name}}}

64 |
65 |
66 | {{{summary}}} 67 |
68 |
69 | {{# str }}refertofullpolicytext, tool_policy, {{{policymodal}}} {{/ str }} 70 |
71 |
72 |
73 | 78 |
79 | 80 |
    81 | {{#versionlangsagreed}} 82 |
  • {{{.}}}
  • 83 | {{/versionlangsagreed}} 84 | {{#versionbehalfsagreed}} 85 |
  • {{{.}}}
  • 86 | {{/versionbehalfsagreed}} 87 |
88 |
89 |
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 | 56 | 57 | 58 | 59 | {{#hasonbehalfagreements}} 60 | 61 | 62 | {{/hasonbehalfagreements}} 63 | 64 | 65 | 66 | 67 | {{#policies}} 68 | {{#versions}} 69 | 70 | 80 | 84 | 90 | 91 | {{#hasonbehalfagreements}} 92 | 93 | 94 | {{/hasonbehalfagreements}} 95 | 101 | 102 | {{/versions}} 103 | {{/policies}} 104 | 105 |
{{#str}} policydocname, tool_policy {{/str}}{{#str}} policydocrevision, tool_policy {{/str}}{{#str}} agreed, tool_policy {{/str}}{{#str}} agreedon, tool_policy {{/str}}{{#str}} agreedby, tool_policy {{/str}}{{#str}} acceptancenote, tool_policy {{/str}}
71 | {{^isfirst}} 72 |
73 | {{#pix}} level, tool_policy {{/pix}} 74 |
75 | {{/isfirst}} 76 |
77 | 78 |
79 |
81 | {{{revision}}} 82 | {{#iscurrent}}{{#pix}} t/check, core {{/pix}}{{/iscurrent}} 83 | 85 | {{#agreement}} 86 | {{>tool_policy/user_agreement}} 87 | {{/agreement}} 88 | 89 | {{timeaccepted}}{{{acceptedby}}}{{{note}}} 96 | {{#hasarchived}} 97 | 98 |
{{#pix}}t/more, moodle, {{#str}}detailedmore, moodle{{/str}}{{/pix}}
99 |
{{/hasarchived}} 100 |
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 | '
' + 152 | '
' + _self.params.popupTitle + '
' + 153 | '
' + _self.params.popupText + '
' + 154 | '' + 161 | 'x' + 162 | '
'; 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 | --------------------------------------------------------------------------------