├── README.md
├── pix
├── icon.png
└── icon.svg
├── amd
├── build
│ └── confirm.min.js
└── src
│ └── confirm.js
├── db
├── events.php
├── install.xml
├── access.php
├── services.php
└── upgrade.php
├── version.php
├── .travis.yml
├── classes
├── renderer.php
├── output
│ └── entries_list.php
├── form.php
├── event
│ ├── entry_created.php
│ ├── entry_deleted.php
│ └── entry_updated.php
├── external.php
├── table.php
└── api.php
├── lang
└── en
│ └── tool_devcourse.php
├── templates
└── entries_list.mustache
├── index.php
├── edit.php
├── tests
├── behat
│ └── editing.feature
├── events_test.php
└── api_test.php
└── lib.php
/README.md:
--------------------------------------------------------------------------------
1 | Plugin tool_devcourse
2 |
--------------------------------------------------------------------------------
/pix/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marinaglancy/moodle-tool_devcourse/master/pix/icon.png
--------------------------------------------------------------------------------
/amd/build/confirm.min.js:
--------------------------------------------------------------------------------
1 | define(["jquery","core/str","core/notification","core/ajax","core/templates"],function(a,b,c,d,e){var f=function(a,d){b.get_strings([{key:"delete"},{key:"confirmdeleteentry",component:"tool_devcourse"},{key:"yes"},{key:"no"}]).done(function(b){c.confirm(b[0],b[1],b[2],b[3],function(){g(a,d)})}).fail(c.exception)},g=function(a,b){var e=b.attr("data-courseid"),f=d.call([{methodname:"tool_devcourse_delete_entry",args:{id:a}},{methodname:"tool_devcourse_entries_list",args:{courseid:e}}]);f[1].done(function(a){h(a,b)}).fail(c.exception)},h=function(a,b){e.render("tool_devcourse/entries_list",a).done(function(a){b.replaceWith(a)})},i=function(b){a(b).on("click",function(b){b.preventDefault();var c=a(b.currentTarget).attr("data-entryid"),d=a(b.currentTarget).closest(".tool_devcourse_entries_list");f(c,d)})};return{init:function(a){i(a)}}});
--------------------------------------------------------------------------------
/db/events.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Add event handlers for the tool_devcourse
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $observers = array(
29 |
30 | array(
31 | 'eventname' => '\core\event\course_deleted',
32 | 'callback' => 'tool_devcourse_api::course_deleted_observer',
33 | ),
34 | );
35 |
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Version information
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $plugin->version = 2018072500; // The current plugin version (Date: YYYYMMDDXX).
28 | $plugin->requires = 2018050800; // Requires this Moodle version.
29 | $plugin->release = 'v2.5'; // Release name.
30 | $plugin->maturity = MATURITY_STABLE; // Maturity.
31 | $plugin->component = 'tool_devcourse'; // Full name of the plugin (used for diagnostics).
32 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | # Workaround for fixing that Selenium server is not running and therefore javascript Behat tests are not working:
4 | # https://github.com/moodlerooms/moodle-plugin-ci/issues/70
5 | sudo: required
6 | # ORIGINAL:
7 | # sudo: false
8 |
9 | addons:
10 | firefox: "47.0.1"
11 | postgresql: "9.6"
12 | apt:
13 | packages:
14 | - oracle-java8-installer
15 | - oracle-java8-set-default
16 |
17 | cache:
18 | directories:
19 | - $HOME/.composer/cache
20 | - $HOME/.npm
21 |
22 | php:
23 | - 7.0
24 | - 7.2
25 |
26 | env:
27 | global:
28 | - MOODLE_BRANCH=master
29 | matrix:
30 | - DB=pgsql
31 | - DB=mysqli
32 |
33 | before_install:
34 | - phpenv config-rm xdebug.ini
35 | - nvm install 8.9
36 | - nvm use 8.9
37 | - cd ../../..
38 | - composer create-project -n --no-dev --prefer-dist moodlerooms/moodle-plugin-ci ci ^2
39 | - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
40 |
41 | install:
42 | - moodle-plugin-ci install
43 |
44 | script:
45 | - moodle-plugin-ci phplint
46 | - moodle-plugin-ci phpcpd
47 | - moodle-plugin-ci phpmd
48 | - moodle-plugin-ci codechecker
49 | - moodle-plugin-ci validate
50 | - moodle-plugin-ci savepoints
51 | - moodle-plugin-ci mustache
52 | - moodle-plugin-ci grunt -t eslint:amd -t uglify
53 | - moodle-plugin-ci phpunit
54 | - moodle-plugin-ci behat
55 |
--------------------------------------------------------------------------------
/classes/renderer.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse_renderer
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | use tool_devcourse\output\entries_list;
28 |
29 | /**
30 | * Renderer for tool_devcourse
31 | *
32 | * @package tool_devcourse
33 | * @copyright 2018 Marina Glancy
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class tool_devcourse_renderer extends plugin_renderer_base {
37 |
38 | /**
39 | * Renders an entries list.
40 | *
41 | * @param entries_list $list
42 | * @return string HTML
43 | */
44 | protected function render_entries_list(entries_list $list) {
45 | $context = $list->export_for_template($this);
46 | return $this->render_from_template('tool_devcourse/entries_list', $context);
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/db/access.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Capability definitions for this module.
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $capabilities = [
28 |
29 | // Capability for viewing data.
30 | 'tool/devcourse:view' => [
31 | 'captype' => 'read',
32 | 'contextlevel' => CONTEXT_COURSE,
33 | 'archetypes' => array(
34 | 'student' => CAP_ALLOW,
35 | 'teacher' => CAP_ALLOW,
36 | 'editingteacher' => CAP_ALLOW,
37 | 'manager' => CAP_ALLOW
38 | )
39 | ],
40 |
41 | // Capability for editing data.
42 | 'tool/devcourse:edit' => [
43 | 'riskbitmask' => RISK_SPAM | RISK_XSS,
44 | 'captype' => 'write',
45 | 'contextlevel' => CONTEXT_COURSE,
46 | 'archetypes' => [
47 | 'editingteacher' => CAP_ALLOW,
48 | 'manager' => CAP_ALLOW,
49 | ]
50 | ],
51 | ];
52 |
--------------------------------------------------------------------------------
/db/services.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Web services for tool_devcourse
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | // We defined the web service functions to install.
28 | $functions = array(
29 | 'tool_devcourse_delete_entry' => array(
30 | 'classname' => 'tool_devcourse_external',
31 | 'methodname' => 'delete_entry',
32 | 'description' => 'Deletes an entry',
33 | 'type' => 'write',
34 | 'capabilities' => 'tool/devcourse:edit',
35 | 'ajax' => true,
36 | ),
37 | 'tool_devcourse_entries_list' => array(
38 | 'classname' => 'tool_devcourse_external',
39 | 'methodname' => 'entries_list',
40 | 'description' => 'Returns list of entries',
41 | 'type' => 'read',
42 | 'capabilities' => 'tool/devcourse:view',
43 | 'ajax' => true,
44 | ),
45 | );
46 |
--------------------------------------------------------------------------------
/lang/en/tool_devcourse.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Strings for component 'tool_devcourse', language 'en'
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $string['completed'] = 'Completed';
28 | $string['confirmdeleteentry'] = 'Are you sure you want to delete this entry?';
29 | $string['description'] = 'Description';
30 | $string['devcourse:edit'] = 'Edit devcourse data';
31 | $string['devcourse:view'] = 'View devcourse data';
32 | $string['editentry'] = 'Edit entry';
33 | $string['errornameexists'] = 'Name must be unique in this course';
34 | $string['evententrydeleted'] = 'Entry deleted';
35 | $string['evententrycreated'] = 'Entry created';
36 | $string['evententryupdated'] = 'Entry updated';
37 | $string['helloworld'] = 'Hello world!';
38 | $string['name'] = 'Name';
39 | $string['newentry'] = 'New entry';
40 | $string['pluginname'] = 'Dev course example';
41 | $string['priority'] = 'Priority';
42 | $string['timecreated'] = 'Created';
43 | $string['timemodified'] = 'Modified';
44 | $string['youareviewing'] = 'You are viewing course {$a}';
45 |
--------------------------------------------------------------------------------
/templates/entries_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 tool_devcourse/entries_list
19 |
20 | Template for the list of etries.
21 |
22 | Classes required for JS:
23 | * tool_devcourse_entries_list
24 |
25 | Data attributes required for JS:
26 | * data-entryid
27 | * data-action
28 | * data-courseid
29 |
30 | Context variables required for this template:
31 | -
32 |
33 | Example context (json):
34 | {
35 | "courseid": 2,
36 | "coursename": "Test course",
37 | "contents": "Here goes the list of entries",
38 | "addlink": "#"
39 | }
40 | }}
41 |
42 |
53 |
54 | {{#js}}
55 | require(
56 | [
57 | 'tool_devcourse/confirm'
58 | ],
59 | function(
60 | c
61 | ) {
62 | c.init('[data-action=deleteentry]');
63 | });
64 |
65 | {{/js}}
66 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Main file
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | require_once(__DIR__ . '/../../../config.php');
26 |
27 | $courseid = required_param('id', PARAM_INT);
28 |
29 | $url = new moodle_url('/admin/tool/devcourse/index.php', ['id' => $courseid]);
30 | $PAGE->set_url($url);
31 |
32 | require_login($courseid);
33 | $context = context_course::instance($courseid);
34 | require_capability('tool/devcourse:view', $context);
35 |
36 | $PAGE->set_title(get_string('helloworld', 'tool_devcourse'));
37 | $PAGE->set_heading(get_string('pluginname', 'tool_devcourse'));
38 |
39 | // Deleting an entry if specified.
40 | if ($deleteid = optional_param('delete', null, PARAM_INT)) {
41 | require_sesskey();
42 | $record = tool_devcourse_api::retrieve($deleteid, $courseid);
43 | require_capability('tool/devcourse:edit', $PAGE->context);
44 | tool_devcourse_api::delete($record->id);
45 | redirect(new moodle_url('/admin/tool/devcourse/index.php', ['id' => $courseid]));
46 | }
47 |
48 | $outputpage = new \tool_devcourse\output\entries_list($courseid);
49 | $output = $PAGE->get_renderer('tool_devcourse');
50 | echo $output->header();
51 | echo $output->render($outputpage);
52 | echo $output->footer();
53 |
--------------------------------------------------------------------------------
/edit.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Editing or creating entries
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | require_once(__DIR__ . '/../../../config.php');
26 |
27 | $id = optional_param('id', 0, PARAM_INT);
28 | if ($id) {
29 | // We are going to edit an entry.
30 | $entry = tool_devcourse_api::retrieve($id);
31 | $courseid = $entry->courseid;
32 | $urlparams = ['id' => $id];
33 | $title = get_string('newentry', 'tool_devcourse');
34 | } else {
35 | // We are going to add an entry. Parameter courseid is required.
36 | $courseid = required_param('courseid', PARAM_INT);
37 | $entry = (object)['courseid' => $courseid];
38 | $urlparams = ['courseid' => $courseid];
39 | $title = get_string('editentry', 'tool_devcourse');
40 | }
41 |
42 | $url = new moodle_url('/admin/tool/devcourse/edit.php', $urlparams);
43 | $PAGE->set_url($url);
44 |
45 | require_login($courseid);
46 | $context = context_course::instance($courseid);
47 | require_capability('tool/devcourse:edit', $context);
48 |
49 | $PAGE->set_title($title);
50 | $PAGE->set_heading(get_string('pluginname', 'tool_devcourse'));
51 |
52 | $form = new tool_devcourse_form();
53 | if (!empty($entry->id)) {
54 | file_prepare_standard_editor($entry, 'description',
55 | tool_devcourse_api::editor_options($courseid),
56 | $PAGE->context, 'tool_devcourse', 'entry', $entry->id);
57 | }
58 | $form->set_data($entry);
59 |
60 | $returnurl = new moodle_url('/admin/tool/devcourse/index.php', ['id' => $courseid]);
61 | if ($form->is_cancelled()) {
62 | redirect($returnurl);
63 | } else if ($data = $form->get_data()) {
64 | if ($data->id) {
65 | // Update entry.
66 | tool_devcourse_api::update($data);
67 | } else {
68 | // Add entry.
69 | tool_devcourse_api::insert($data);
70 | }
71 | redirect($returnurl);
72 | }
73 |
74 | echo $OUTPUT->header();
75 | echo $OUTPUT->heading($title);
76 |
77 | $form->display();
78 |
79 | echo $OUTPUT->footer();
--------------------------------------------------------------------------------
/classes/output/entries_list.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse\output\entries_list
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_devcourse\output;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use renderer_base;
30 | use moodle_url;
31 | use tool_devcourse_table;
32 | use context_course;
33 |
34 | /**
35 | * Class tool_devcourse\output\entries_list
36 | *
37 | * @package tool_devcourse
38 | * @copyright 2018 Marina Glancy
39 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 | */
41 | class entries_list implements \templatable, \renderable {
42 |
43 | /** @var int */
44 | protected $courseid;
45 |
46 | /**
47 | * entries_list constructor.
48 | * @param int $courseid
49 | */
50 | public function __construct($courseid) {
51 | $this->courseid = $courseid;
52 | }
53 |
54 | /**
55 | * Implementation of exporter from templatable interface
56 | *
57 | * @param renderer_base $output
58 | * @return array
59 | */
60 | public function export_for_template(renderer_base $output) {
61 | $course = get_course($this->courseid);
62 | $context = context_course::instance($this->courseid);
63 | $data = [
64 | 'courseid' => $this->courseid,
65 | 'coursename' => format_string($course->fullname, true, ['context' => $context])
66 | ];
67 |
68 | // Display table.
69 | ob_start();
70 | $table = new tool_devcourse_table('tool_devcourse', $this->courseid);
71 | $table->out(20, false);
72 | $data['contents'] = ob_get_clean();
73 |
74 | // Link to add new entry.
75 | if (has_capability('tool/devcourse:edit', $context)) {
76 | $url = new moodle_url('/admin/tool/devcourse/edit.php', ['courseid' => $this->courseid]);
77 | // Link will be escaped inside template so no need to escape it now.
78 | $data['addlink'] = $url->out(false);
79 | }
80 | return $data;
81 | }
82 | }
--------------------------------------------------------------------------------
/classes/form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse_form
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | require_once($CFG->libdir.'/formslib.php');
28 |
29 | /**
30 | * Class tool_devcourse_form for displaying an editing form
31 | *
32 | * @package tool_devcourse
33 | * @copyright 2018 Marina Glancy
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class tool_devcourse_form extends moodleform {
37 |
38 | /**
39 | * Form definition
40 | */
41 | public function definition() {
42 | $mform = $this->_form;
43 |
44 | $mform->addElement('hidden', 'courseid');
45 | $mform->setType('courseid', PARAM_INT);
46 |
47 | $mform->addElement('hidden', 'id');
48 | $mform->setType('id', PARAM_INT);
49 |
50 | $mform->addElement('text', 'name',
51 | get_string('name', 'tool_devcourse'));
52 | $mform->setType('name', PARAM_NOTAGS);
53 |
54 | $mform->addElement('advcheckbox', 'completed',
55 | get_string('completed', 'tool_devcourse'));
56 |
57 | $mform->addElement('editor', 'description_editor',
58 | get_string('description', 'tool_devcourse'),
59 | null, tool_devcourse_api::editor_options());
60 |
61 | $this->add_action_buttons();
62 | }
63 |
64 | /**
65 | * Form validation
66 | *
67 | * @param array $data
68 | * @param array $files
69 | * @return array
70 | */
71 | public function validation($data, $files) {
72 | global $DB;
73 | $errors = parent::validation($data, $files);
74 |
75 | // Check that name is unique for the course.
76 | if ($DB->record_exists_select('tool_devcourse',
77 | 'name = :name AND id <> :id AND courseid = :courseid',
78 | ['name' => $data['name'], 'id' => $data['id'], 'courseid' => $data['courseid']])) {
79 | $errors['name'] = get_string('errornameexists', 'tool_devcourse');
80 | }
81 |
82 | return $errors;
83 | }
84 | }
--------------------------------------------------------------------------------
/tests/behat/editing.feature:
--------------------------------------------------------------------------------
1 | @tool @tool_devcourse
2 | Feature: Creating, editing and deleting entries
3 | In order to manage entries
4 | As a teacher
5 | I need to be able to add, edit and delete entries
6 |
7 | Background:
8 | Given the following "users" exist:
9 | | username | firstname | lastname | email |
10 | | teacher1 | Teacher | 1 | teacher1@example.com |
11 | And the following "courses" exist:
12 | | fullname | shortname | format |
13 | | Course 1 | C1 | weeks |
14 | And the following "course enrolments" exist:
15 | | user | course | role |
16 | | teacher1 | C1 | editingteacher |
17 |
18 | Scenario: Add and edit an entry
19 | When I log in as "teacher1"
20 | And I follow "Course 1"
21 | And I navigate to "Dev course example" in current page administration
22 | And I follow "New entry"
23 | And I set the following fields to these values:
24 | | Name | test entry 1 |
25 | | Completed | 0 |
26 | | Description | cat |
27 | And I press "Save changes"
28 | Then the following should exist in the "tool_devcourse_overview" table:
29 | | Name | Completed | Description |
30 | | test entry 1 | No | cat |
31 | And I click on "Edit" "link" in the "test entry 1" "table_row"
32 | And I set the following fields to these values:
33 | | Completed | 1 |
34 | And I press "Save changes"
35 | And the following should exist in the "tool_devcourse_overview" table:
36 | | Name | Description | Completed |
37 | | test entry 1 | cat | Yes |
38 | And I log out
39 |
40 | Scenario: Delete an entry with javascript disabled
41 | When I log in as "teacher1"
42 | And I follow "Course 1"
43 | And I navigate to "Dev course example" in current page administration
44 | And I follow "New entry"
45 | And I set the field "Name" to "test entry 1"
46 | And I press "Save changes"
47 | And I follow "New entry"
48 | And I set the field "Name" to "test entry 2"
49 | And I press "Save changes"
50 | And I click on "Delete" "link" in the "test entry 1" "table_row"
51 | Then I should see "test entry 2"
52 | And I should not see "test entry 1"
53 | And I log out
54 |
55 | @javascript @xxx
56 | Scenario: Delete an entry with javascript enabled
57 | When I log in as "teacher1"
58 | And I am on "Course 1" course homepage
59 | And I navigate to "Dev course example" in current page administration
60 | And I follow "New entry"
61 | And I set the field "Name" to "test entry 1"
62 | And I press "Save changes"
63 | And I follow "New entry"
64 | And I set the field "Name" to "test entry 2"
65 | And I press "Save changes"
66 | And I click on "Delete" "link" in the "test entry 1" "table_row"
67 | And I press "Yes"
68 | Then I should see "test entry 2"
69 | And I should not see "test entry 1"
70 | And I log out
71 |
--------------------------------------------------------------------------------
/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Callbacks for plugin tool_devcourse
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | /**
28 | * Adds this plugin to the course administration menu
29 | *
30 | * @param navigation_node $navigation The navigation node to extend
31 | * @param stdClass $course The course to object for the tool
32 | * @param context $context The context of the course
33 | * @return void|null return null if we don't want to display the node.
34 | */
35 | function tool_devcourse_extend_navigation_course($navigation, $course, $context) {
36 | if (has_capability('tool/devcourse:view', $context)) {
37 | $navigation->add(
38 | get_string('pluginname', 'tool_devcourse'),
39 | new moodle_url('/admin/tool/devcourse/index.php', ['id' => $course->id]),
40 | navigation_node::TYPE_SETTING,
41 | get_string('pluginname', 'tool_devcourse'),
42 | 'devcourse',
43 | new pix_icon('icon', '', 'tool_devcourse'));
44 | }
45 | }
46 |
47 | /**
48 | * Serve the embedded files.
49 | *
50 | * @param stdClass $course the course object
51 | * @param stdClass $cm the course module object
52 | * @param context $context the context
53 | * @param string $filearea the name of the file area
54 | * @param array $args extra arguments (itemid, path)
55 | * @param bool $forcedownload whether or not force download
56 | * @param array $options additional options affecting the file serving
57 | * @return bool false if the file not found, just send the file otherwise and do not return anything
58 | */
59 | function tool_devcourse_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
60 |
61 | if ($context->contextlevel != CONTEXT_COURSE) {
62 | return false;
63 | }
64 |
65 | if ($filearea !== 'entry') {
66 | return false;
67 | }
68 |
69 | require_login($course);
70 | require_capability('tool/devcourse:view', $context);
71 |
72 | $itemid = array_shift($args);
73 |
74 | $entry = tool_devcourse_api::retrieve($itemid);
75 |
76 | $filename = array_pop($args);
77 |
78 | if (!$args) {
79 | $filepath = '/';
80 | } else {
81 | $filepath = '/'.implode('/', $args).'/';
82 | }
83 |
84 | $fs = get_file_storage();
85 | $file = $fs->get_file($context->id, 'tool_devcourse', $filearea, $itemid, $filepath, $filename);
86 |
87 | if (!$file) {
88 | return false;
89 | }
90 |
91 | send_stored_file($file, null, 0, $forcedownload, $options);
92 | }
93 |
--------------------------------------------------------------------------------
/classes/event/entry_created.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse\event\entry_created
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_devcourse\event;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use core\event\base;
30 |
31 | /**
32 | * Class tool_devcourse\event\entry_created
33 | *
34 | * @package tool_devcourse
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class entry_created extends base {
39 |
40 | /**
41 | * Initialise the event data.
42 | */
43 | protected function init() {
44 | $this->data['objecttable'] = 'tool_devcourse';
45 | $this->data['crud'] = 'c';
46 | $this->data['edulevel'] = self::LEVEL_TEACHING;
47 | }
48 |
49 | /**
50 | * Returns localised general event name.
51 | *
52 | * @return string
53 | */
54 | public static function get_name() {
55 | return get_string('evententrycreated', 'tool_devcourse');
56 | }
57 |
58 | /**
59 | * Returns non-localised description of what happened.
60 | *
61 | * @return string
62 | */
63 | public function get_description() {
64 | return "The user with id '$this->userid' created the entry with id '$this->objectid'.";
65 | }
66 |
67 | /**
68 | * Returns relevant URL.
69 | *
70 | * @return \moodle_url
71 | */
72 | public function get_url() {
73 | return new \moodle_url('/admin/tool/devcourse/index.php', ['id' => $this->courseid]);
74 | }
75 |
76 | /**
77 | * Custom validation.
78 | *
79 | * @throws \coding_exception
80 | * @return void
81 | */
82 | protected function validate_data() {
83 | parent::validate_data();
84 |
85 | if ($this->contextlevel != CONTEXT_COURSE) {
86 | throw new \coding_exception('Context level must be CONTEXT_COURSE.');
87 | }
88 | }
89 |
90 | /**
91 | * This is used when restoring course logs where it is required that we
92 | * map the objectid to it's new value in the new course.
93 | *
94 | * @return string the name of the restore mapping the objectid links to
95 | */
96 | public static function get_objectid_mapping() {
97 | return base::NOT_MAPPED;
98 | }
99 |
100 | /**
101 | * This is used when restoring course logs where it is required that we
102 | * map the information in 'other' to it's new value in the new course.
103 | *
104 | * @return array an array of other values and their corresponding mapping
105 | */
106 | public static function get_other_mapping() {
107 | // Nothing to map.
108 | return false;
109 | }
110 | }
--------------------------------------------------------------------------------
/classes/event/entry_deleted.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse\event\entry_deleted
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_devcourse\event;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use core\event\base;
30 |
31 | /**
32 | * Class tool_devcourse\event\entry_deleted
33 | *
34 | * @package tool_devcourse
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class entry_deleted extends base {
39 |
40 | /**
41 | * Initialise the event data.
42 | */
43 | protected function init() {
44 | $this->data['objecttable'] = 'tool_devcourse';
45 | $this->data['crud'] = 'd';
46 | $this->data['edulevel'] = self::LEVEL_TEACHING;
47 | }
48 |
49 | /**
50 | * Returns localised general event name.
51 | *
52 | * @return string
53 | */
54 | public static function get_name() {
55 | return get_string('evententrydeleted', 'tool_devcourse');
56 | }
57 |
58 | /**
59 | * Returns non-localised description of what happened.
60 | *
61 | * @return string
62 | */
63 | public function get_description() {
64 | return "The user with id '$this->userid' deleted the entry with id '$this->objectid'.";
65 | }
66 |
67 | /**
68 | * Returns relevant URL.
69 | *
70 | * @return \moodle_url
71 | */
72 | public function get_url() {
73 | return new \moodle_url('/admin/tool/devcourse/index.php', ['id' => $this->courseid]);
74 | }
75 |
76 | /**
77 | * Custom validation.
78 | *
79 | * @throws \coding_exception
80 | * @return void
81 | */
82 | protected function validate_data() {
83 | parent::validate_data();
84 |
85 | if ($this->contextlevel != CONTEXT_COURSE) {
86 | throw new \coding_exception('Context level must be CONTEXT_COURSE.');
87 | }
88 | }
89 |
90 | /**
91 | * This is used when restoring course logs where it is required that we
92 | * map the objectid to it's new value in the new course.
93 | *
94 | * @return string the name of the restore mapping the objectid links to
95 | */
96 | public static function get_objectid_mapping() {
97 | return base::NOT_MAPPED;
98 | }
99 |
100 | /**
101 | * This is used when restoring course logs where it is required that we
102 | * map the information in 'other' to it's new value in the new course.
103 | *
104 | * @return array an array of other values and their corresponding mapping
105 | */
106 | public static function get_other_mapping() {
107 | // Nothing to map.
108 | return false;
109 | }
110 | }
--------------------------------------------------------------------------------
/classes/event/entry_updated.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse\event\entry_updated
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | namespace tool_devcourse\event;
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | use core\event\base;
30 |
31 | /**
32 | * Class tool_devcourse\event\entry_updated
33 | *
34 | * @package tool_devcourse
35 | * @copyright 2018 Marina Glancy
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class entry_updated extends base {
39 |
40 | /**
41 | * Initialise the event data.
42 | */
43 | protected function init() {
44 | $this->data['objecttable'] = 'tool_devcourse';
45 | $this->data['crud'] = 'u';
46 | $this->data['edulevel'] = self::LEVEL_TEACHING;
47 | }
48 |
49 | /**
50 | * Returns localised general event name.
51 | *
52 | * @return string
53 | */
54 | public static function get_name() {
55 | return get_string('evententryupdated', 'tool_devcourse');
56 | }
57 |
58 | /**
59 | * Returns non-localised description of what happened.
60 | *
61 | * @return string
62 | */
63 | public function get_description() {
64 | return "The user with id '$this->userid' updated the entry with id '$this->objectid'.";
65 | }
66 |
67 | /**
68 | * Returns relevant URL.
69 | *
70 | * @return \moodle_url
71 | */
72 | public function get_url() {
73 | return new \moodle_url('/admin/tool/devcourse/index.php', ['id' => $this->courseid]);
74 | }
75 |
76 | /**
77 | * Custom validation.
78 | *
79 | * @throws \coding_exception
80 | * @return void
81 | */
82 | protected function validate_data() {
83 | parent::validate_data();
84 |
85 | if ($this->contextlevel != CONTEXT_COURSE) {
86 | throw new \coding_exception('Context level must be CONTEXT_COURSE.');
87 | }
88 | }
89 |
90 | /**
91 | * This is used when restoring course logs where it is required that we
92 | * map the objectid to it's new value in the new course.
93 | *
94 | * @return string the name of the restore mapping the objectid links to
95 | */
96 | public static function get_objectid_mapping() {
97 | return base::NOT_MAPPED;
98 | }
99 |
100 | /**
101 | * This is used when restoring course logs where it is required that we
102 | * map the information in 'other' to it's new value in the new course.
103 | *
104 | * @return array an array of other values and their corresponding mapping
105 | */
106 | public static function get_other_mapping() {
107 | // Nothing to map.
108 | return false;
109 | }
110 | }
--------------------------------------------------------------------------------
/amd/src/confirm.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 | * Add confirmation
18 | *
19 | * @module tool_devcourse/confirm
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 | define(['jquery', 'core/str', 'core/notification', 'core/ajax', 'core/templates'],
25 | function($, str, notification, ajax, templates) {
26 |
27 | /**
28 | * Displays the delete confirmation and on approval redirects to href
29 | * @param {Number} id
30 | * @param {jQuery} list
31 | */
32 | var confirmDelete = function(id, list) {
33 | str.get_strings([
34 | {key: 'delete'},
35 | {key: 'confirmdeleteentry', component: 'tool_devcourse'},
36 | {key: 'yes'},
37 | {key: 'no'}
38 | ]).done(function(s) {
39 | notification.confirm(s[0], s[1], s[2], s[3], function() {
40 | processDelete(id, list);
41 | });
42 | }
43 | ).fail(notification.exception);
44 | };
45 |
46 | /**
47 | * Processes deleting an entry
48 | * @param {Number} id
49 | * @param {jQuery} list
50 | */
51 | var processDelete = function(id, list) {
52 | var courseid = list.attr('data-courseid');
53 | // We are chaining ajax requests here.
54 | var requests = ajax.call([{
55 | methodname: 'tool_devcourse_delete_entry',
56 | args: {id: id}
57 | }, {
58 | methodname: 'tool_devcourse_entries_list',
59 | args: {courseid: courseid}
60 | }]);
61 | requests[1].done(function(data) {
62 | reloadList(data, list);
63 | }).fail(notification.exception);
64 | };
65 |
66 | /**
67 | * Replaces the current list with the data rendered from template
68 | * @param {Object} data
69 | * @param {jQuery} list
70 | */
71 | var reloadList = function(data, list) {
72 | templates.render('tool_devcourse/entries_list', data).done(function(html) {
73 | list.replaceWith(html);
74 | });
75 | };
76 |
77 | /**
78 | * Registers the handler for click event
79 | * @param {String} selector
80 | */
81 | var registerClickHandler = function(selector) {
82 | $(selector).on('click', function(e) {
83 | e.preventDefault();
84 | var id = $(e.currentTarget).attr('data-entryid'),
85 | list = $(e.currentTarget).closest('.tool_devcourse_entries_list');
86 | confirmDelete(id, list);
87 | });
88 | };
89 |
90 | return /** @alias module:tool_devcourse/confirm */ {
91 | /**
92 | * Initialise the confirmation for selector
93 | *
94 | * @method init
95 | * @param {String} selector
96 | */
97 | init: function(selector) {
98 | registerClickHandler(selector);
99 | }
100 | };
101 | });
--------------------------------------------------------------------------------
/tests/events_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * This file contains the class that handles testing of course events.
19 | *
20 | * @package core
21 | * @copyright 2016 Stephen Bourget
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | /**
28 | * This file contains the class that handles testing of course events.
29 | *
30 | * @package core_course
31 | * @copyright 2016 Stephen Bourget
32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 | */
34 | class tool_devcourse_events_testcase extends advanced_testcase {
35 |
36 | /**
37 | * Tests set up
38 | */
39 | protected function setUp() {
40 | $this->resetAfterTest();
41 | }
42 |
43 | /**
44 | * Test for event entry_created
45 | */
46 | public function test_entry_created() {
47 | $course = $this->getDataGenerator()->create_course();
48 | $sink = $this->redirectEvents();
49 | $entryid = tool_devcourse_api::insert((object)[
50 | 'courseid' => $course->id,
51 | 'name' => 'testname1',
52 | 'completed' => 1,
53 | 'priority' => 0,
54 | ]);
55 | $events = $sink->get_events();
56 | $this->assertCount(1, $events);
57 | $event = array_shift($events);
58 |
59 | // Checking that the event contains the expected values.
60 | $this->assertInstanceOf('\tool_devcourse\event\entry_created', $event);
61 | $this->assertEquals($course->id, $event->courseid);
62 | $this->assertEquals($entryid, $event->objectid);
63 | }
64 |
65 | /**
66 | * Test for event entry_updated
67 | */
68 | public function test_entry_updated() {
69 | $course = $this->getDataGenerator()->create_course();
70 | $entryid = tool_devcourse_api::insert((object)[
71 | 'courseid' => $course->id,
72 | 'name' => 'testname1'
73 | ]);
74 |
75 | $sink = $this->redirectEvents();
76 | tool_devcourse_api::update((object)[
77 | 'id' => $entryid,
78 | 'name' => 'testname2',
79 | ]);
80 | $events = $sink->get_events();
81 | $this->assertCount(1, $events);
82 | $event = array_shift($events);
83 |
84 | // Checking that the event contains the expected values.
85 | $this->assertInstanceOf('\tool_devcourse\event\entry_updated', $event);
86 | $this->assertEquals($course->id, $event->courseid);
87 | $this->assertEquals($entryid, $event->objectid);
88 | }
89 |
90 |
91 | /**
92 | * Test for event entry_deleted
93 | */
94 | public function test_entry_deleted() {
95 | $course = $this->getDataGenerator()->create_course();
96 | $entryid = tool_devcourse_api::insert((object)[
97 | 'courseid' => $course->id,
98 | 'name' => 'testname1'
99 | ]);
100 |
101 | $sink = $this->redirectEvents();
102 | tool_devcourse_api::delete($entryid);
103 | $events = $sink->get_events();
104 | $this->assertCount(1, $events);
105 | $event = array_shift($events);
106 |
107 | // Checking that the event contains the expected values.
108 | $this->assertInstanceOf('\tool_devcourse\event\entry_deleted', $event);
109 | $this->assertEquals($course->id, $event->courseid);
110 | $this->assertEquals($entryid, $event->objectid);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/pix/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/classes/external.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse_external
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | require_once($CFG->libdir . "/externallib.php");
28 |
29 | /**
30 | * Web services for tool_devcourse
31 | *
32 | * @package tool_devcourse
33 | * @copyright 2018 Marina Glancy
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class tool_devcourse_external extends external_api {
37 |
38 | /**
39 | * Returns description of method parameters
40 | * @return external_function_parameters
41 | */
42 | public static function entries_list_parameters() {
43 | return new external_function_parameters(
44 | array('courseid' => new external_value(PARAM_INT, 'Course id', VALUE_REQUIRED))
45 | );
46 | }
47 |
48 | /**
49 | * List of entries in the course
50 | * @return array
51 | */
52 | public static function entries_list($courseid) {
53 | global $PAGE;
54 |
55 | // Parameter validation.
56 | $params = self::validate_parameters(self::entries_list_parameters(),
57 | array('courseid' => $courseid));
58 | $courseid = $params['courseid'];
59 |
60 | // From web services we don't call require_login(), but rather validate_context.
61 | $context = context_course::instance($courseid);
62 | self::validate_context($context);
63 | require_capability('tool/devcourse:view', $context);
64 |
65 | $outputpage = new \tool_devcourse\output\entries_list($courseid);
66 | $renderer = $PAGE->get_renderer('tool_devcourse');
67 | return $outputpage->export_for_template($renderer);
68 | }
69 |
70 | /**
71 | * Returns description of method result value
72 | * @return external_description
73 | */
74 | public static function entries_list_returns() {
75 | return new external_single_structure(
76 | array(
77 | 'courseid' => new external_value(PARAM_INT, 'Course id'),
78 | 'coursename' => new external_value(PARAM_NOTAGS, 'Course name'),
79 | 'contents' => new external_value(PARAM_RAW, 'Contents'),
80 | 'addlink' => new external_value(PARAM_URL, 'Link to add an entry', VALUE_OPTIONAL),
81 | )
82 | );
83 | }
84 |
85 |
86 | /**
87 | * Returns description of method parameters
88 | * @return external_function_parameters
89 | */
90 | public static function delete_entry_parameters() {
91 | return new external_function_parameters(
92 | array('id' => new external_value(PARAM_INT, 'Id of an entry', VALUE_REQUIRED))
93 | );
94 | }
95 |
96 | /**
97 | * List of entries in the course
98 | * @param int $id
99 | * @return array
100 | */
101 | public static function delete_entry($id) {
102 | // Parameter validation.
103 | $params = self::validate_parameters(self::delete_entry_parameters(),
104 | array('id' => $id));
105 | $id = $params['id'];
106 |
107 | $entry = tool_devcourse_api::retrieve($id);
108 |
109 | // From web services we don't call require_login(), but rather validate_context.
110 | $context = context_course::instance($entry->courseid);
111 | self::validate_context($context);
112 | require_capability('tool/devcourse:edit', $context);
113 |
114 | tool_devcourse_api::delete($id);
115 | }
116 |
117 | /**
118 | * Returns description of method result value
119 | * @return external_description
120 | */
121 | public static function delete_entry_returns() {
122 | return null;
123 | }
124 | }
--------------------------------------------------------------------------------
/db/upgrade.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * tool_devcourse upgrade script.
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | /**
28 | * Run all upgrade steps between the current DB version and the current version on disk.
29 | *
30 | * @param int $oldversion The old version of atto equation in the DB.
31 | * @return bool
32 | */
33 | function xmldb_tool_devcourse_upgrade($oldversion) {
34 | global $CFG, $DB;
35 |
36 | $dbman = $DB->get_manager();
37 |
38 | if ($oldversion < 2018072005) {
39 |
40 | // Define table tool_devcourse to be created.
41 | $table = new xmldb_table('tool_devcourse');
42 |
43 | // Adding fields to table tool_devcourse.
44 | $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
45 | $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
46 | $table->add_field('name', XMLDB_TYPE_CHAR, '50', null, null, null, null);
47 | $table->add_field('completed', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
48 | $table->add_field('priority', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
49 | $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
50 | $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
51 |
52 | // Adding keys to table tool_devcourse.
53 | $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
54 |
55 | // Conditionally launch create table for tool_devcourse.
56 | if (!$dbman->table_exists($table)) {
57 | $dbman->create_table($table);
58 | }
59 |
60 | // Devcourse savepoint reached.
61 | upgrade_plugin_savepoint(true, 2018072005, 'tool', 'devcourse');
62 | }
63 |
64 | if ($oldversion < 2018072006) {
65 |
66 | // Define key courseid (foreign) to be added to tool_devcourse.
67 | $table = new xmldb_table('tool_devcourse');
68 | $key = new xmldb_key('courseid', XMLDB_KEY_FOREIGN, ['courseid'], 'course', ['id']);
69 |
70 | // Launch add key courseid.
71 | $dbman->add_key($table, $key);
72 |
73 | // Devcourse savepoint reached.
74 | upgrade_plugin_savepoint(true, 2018072006, 'tool', 'devcourse');
75 | }
76 |
77 | if ($oldversion < 2018072007) {
78 |
79 | // Define index courseidname (unique) to be added to tool_devcourse.
80 | $table = new xmldb_table('tool_devcourse');
81 | $index = new xmldb_index('courseidname', XMLDB_INDEX_UNIQUE, ['courseid', 'name']);
82 |
83 | // Conditionally launch add index courseidname.
84 | if (!$dbman->index_exists($table, $index)) {
85 | $dbman->add_index($table, $index);
86 | }
87 |
88 | // Devcourse savepoint reached.
89 | upgrade_plugin_savepoint(true, 2018072007, 'tool', 'devcourse');
90 | }
91 |
92 | if ($oldversion < 2018072307) {
93 |
94 | // Define field description to be added to tool_devcourse.
95 | $table = new xmldb_table('tool_devcourse');
96 | $field = new xmldb_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null, 'priority');
97 |
98 | // Conditionally launch add field description.
99 | if (!$dbman->field_exists($table, $field)) {
100 | $dbman->add_field($table, $field);
101 | }
102 |
103 | // Define field descriptionformat to be added to tool_devcourse.
104 | $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'description');
105 |
106 | // Conditionally launch add field descriptionformat.
107 | if (!$dbman->field_exists($table, $field)) {
108 | $dbman->add_field($table, $field);
109 | }
110 |
111 | // Devcourse savepoint reached.
112 | upgrade_plugin_savepoint(true, 2018072307, 'tool', 'devcourse');
113 | }
114 |
115 | return true;
116 | }
117 |
--------------------------------------------------------------------------------
/tests/api_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * API tests.
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | use core\invalid_persistent_exception;
26 | use core\task\manager;
27 | use tool_dataprivacy\context_instance;
28 | use tool_dataprivacy\api;
29 | use tool_dataprivacy\data_registry;
30 | use tool_dataprivacy\expired_context;
31 | use tool_dataprivacy\data_request;
32 | use tool_dataprivacy\local\helper;
33 | use tool_dataprivacy\task\initiate_data_request_task;
34 | use tool_dataprivacy\task\process_data_request_task;
35 |
36 | defined('MOODLE_INTERNAL') || die();
37 | global $CFG;
38 |
39 | /**
40 | * API tests.
41 | *
42 | * @package tool_devcourse
43 | * @copyright 2018 Marina Glancy
44 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 | */
46 | class tool_devcourse_api_testcase extends advanced_testcase {
47 |
48 | /**
49 | * Set up for the tests.
50 | */
51 | public function setUp() {
52 | $this->resetAfterTest();
53 | }
54 |
55 | /**
56 | * Test for tool_devcourse_api::insert and tool_devcourse_api::retrieve
57 | */
58 | public function test_insert() {
59 | $course = $this->getDataGenerator()->create_course();
60 | $entryid = tool_devcourse_api::insert((object)[
61 | 'courseid' => $course->id,
62 | 'name' => 'testname1',
63 | 'completed' => 1,
64 | 'priority' => 0,
65 | 'description' => 'description plain'
66 | ]);
67 | $entry = tool_devcourse_api::retrieve($entryid);
68 | $this->assertEquals($course->id, $entry->courseid);
69 | $this->assertEquals('testname1', $entry->name);
70 | $this->assertEquals('description plain', $entry->description);
71 | }
72 |
73 | /**
74 | * Test for tool_devcourse_api::update
75 | */
76 | public function test_update() {
77 | $course = $this->getDataGenerator()->create_course();
78 | $entryid = tool_devcourse_api::insert((object)[
79 | 'courseid' => $course->id,
80 | 'name' => 'testname1'
81 | ]);
82 | tool_devcourse_api::update((object)[
83 | 'id' => $entryid,
84 | 'name' => 'testname2',
85 | 'description' => 'description plain'
86 | ]);
87 | $entry = tool_devcourse_api::retrieve($entryid);
88 | $this->assertEquals($course->id, $entry->courseid);
89 | $this->assertEquals('testname2', $entry->name);
90 | $this->assertEquals('description plain', $entry->description);
91 | }
92 |
93 | /**
94 | * Test for tool_devcourse_api::delete
95 | */
96 | public function test_delete() {
97 | $course = $this->getDataGenerator()->create_course();
98 | $entryid = tool_devcourse_api::insert((object)[
99 | 'courseid' => $course->id,
100 | 'name' => 'testname1'
101 | ]);
102 | tool_devcourse_api::delete($entryid);
103 | $entry = tool_devcourse_api::retrieve($entryid, 0, IGNORE_MISSING);
104 | $this->assertEmpty($entry);
105 | }
106 |
107 | public function test_description_editor() {
108 | $this->setAdminUser();
109 | $course = $this->getDataGenerator()->create_course();
110 | $entryid = tool_devcourse_api::insert((object)[
111 | 'courseid' => $course->id,
112 | 'name' => 'testname1',
113 | 'description_editor' => [
114 | 'text' => 'description formatted',
115 | 'format' => FORMAT_HTML,
116 | 'itemid' => file_get_unused_draft_itemid()
117 | ]
118 | ]);
119 | $entry = tool_devcourse_api::retrieve($entryid);
120 | $this->assertEquals('description formatted', $entry->description);
121 | tool_devcourse_api::update((object)[
122 | 'id' => $entryid,
123 | 'name' => 'testname2',
124 | 'description_editor' => [
125 | 'text' => 'description edited',
126 | 'format' => FORMAT_HTML,
127 | 'itemid' => file_get_unused_draft_itemid()
128 | ]
129 | ]);
130 | $entry = tool_devcourse_api::retrieve($entryid);
131 | $this->assertEquals($course->id, $entry->courseid);
132 | $this->assertEquals('testname2', $entry->name);
133 | $this->assertEquals('description edited', $entry->description);
134 |
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/classes/table.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse_table
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | require_once($CFG->libdir.'/tablelib.php');
28 |
29 | /**
30 | * Class tool_devcourse_table for displaying tool_devcourse table
31 | *
32 | * @package tool_devcourse
33 | * @copyright 2018 Marina Glancy
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class tool_devcourse_table extends table_sql {
37 |
38 | /** @var context_course */
39 | protected $context;
40 |
41 | /**
42 | * Sets up the table_log parameters.
43 | *
44 | * @param string $uniqueid unique id of form.
45 | * @param int $courseid
46 | */
47 | public function __construct($uniqueid, $courseid) {
48 | global $PAGE;
49 |
50 | parent::__construct($uniqueid);
51 |
52 | $this->set_attribute('id', 'tool_devcourse_overview');
53 |
54 | $columns = array('name', 'description', 'completed', 'priority', 'timecreated', 'timemodified');
55 | $headers = array(
56 | get_string('name', 'tool_devcourse'),
57 | get_string('description', 'tool_devcourse'),
58 | get_string('completed', 'tool_devcourse'),
59 | get_string('priority', 'tool_devcourse'),
60 | get_string('timecreated', 'tool_devcourse'),
61 | get_string('timemodified', 'tool_devcourse'),
62 | );
63 | $this->context = context_course::instance($courseid);
64 | if (has_capability('tool/devcourse:edit', $this->context)) {
65 | $columns[] = 'edit';
66 | $headers[] = '';
67 | }
68 | $this->define_columns($columns);
69 | $this->define_headers($headers);
70 | $this->pageable(true);
71 | $this->collapsible(false);
72 | $this->sortable(false);
73 | $this->is_downloadable(false);
74 |
75 | $this->define_baseurl($PAGE->url);
76 |
77 | $this->set_sql('id, name, completed, priority, timecreated, timemodified, '.
78 | 'description, descriptionformat',
79 | '{tool_devcourse}', 'courseid = ?', [$courseid]);
80 | }
81 |
82 | /**
83 | * Displays column completed
84 | *
85 | * @param stdClass $row
86 | * @return string
87 | */
88 | protected function col_completed($row) {
89 | return $row->completed ? get_string('yes') : get_string('no');
90 | }
91 |
92 | /**
93 | * Displays column priority
94 | *
95 | * @param stdClass $row
96 | * @return string
97 | */
98 | protected function col_priority($row) {
99 | return $row->priority ? get_string('yes') : get_string('no');
100 | }
101 |
102 | /**
103 | * Displays column name
104 | *
105 | * @param stdClass $row
106 | * @return string
107 | */
108 | protected function col_name($row) {
109 | return format_string($row->name, true,
110 | ['context' => $this->context]);
111 | }
112 |
113 | /**
114 | * Displays column description
115 | *
116 | * @param stdClass $row
117 | * @return string
118 | */
119 | protected function col_description($row) {
120 | $options = tool_devcourse_api::editor_options();
121 | $description = file_rewrite_pluginfile_urls($row->description, 'pluginfile.php',
122 | $options['context']->id, 'tool_devcourse', 'entry', $row->id, $options);
123 | return format_text($description, $row->descriptionformat, $options);
124 | }
125 |
126 | /**
127 | * Displays column timecreated
128 | *
129 | * @param stdClass $row
130 | * @return string
131 | */
132 | protected function col_timecreated($row) {
133 | return userdate($row->timecreated, get_string('strftimedatetime'));
134 | }
135 |
136 | /**
137 | * Displays column timemodified
138 | *
139 | * @param stdClass $row
140 | * @return string
141 | */
142 | protected function col_timemodified($row) {
143 | return userdate($row->timemodified, get_string('strftimedatetime'));
144 | }
145 |
146 | protected function col_edit($row) {
147 | $url = new moodle_url('/admin/tool/devcourse/edit.php', ['id' => $row->id]);
148 | $deleteurl = new moodle_url('/admin/tool/devcourse/index.php',
149 | ['delete' => $row->id, 'id' => $this->context->instanceid,
150 | 'sesskey' => sesskey()]);
151 | return html_writer::link($url, get_string('edit')) . '
' .
152 | html_writer::link($deleteurl, get_string('delete'),
153 | ['data-action' => 'deleteentry', 'data-entryid' => $row->id]);
154 | }
155 | }
--------------------------------------------------------------------------------
/classes/api.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Class tool_devcourse_api
19 | *
20 | * @package tool_devcourse
21 | * @copyright 2018 Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | require_once($CFG->libdir.'/formslib.php');
28 |
29 | /**
30 | * Class tool_devcourse_api for various api methods
31 | *
32 | * @package tool_devcourse
33 | * @copyright 2018 Marina Glancy
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class tool_devcourse_api {
37 |
38 | /**
39 | * Retrieve an entry
40 | *
41 | * @param int $id id of the entry
42 | * @param int $courseid optional course id for validation
43 | * @param int $strictness
44 | * @return stdClass|bool retrieved object or false if entry not found and strictness is IGNORE_MISSING
45 | */
46 | public static function retrieve(int $id, int $courseid = 0, int $strictness = MUST_EXIST) {
47 | global $DB;
48 | $params = ['id' => $id];
49 | if ($courseid) {
50 | $params['courseid'] = $courseid;
51 | }
52 | return $DB->get_record('tool_devcourse', $params, '*', $strictness);
53 | }
54 |
55 | /**
56 | * Update an entry
57 | *
58 | * @param stdClass $data
59 | */
60 | public static function update(stdClass $data) {
61 | global $DB, $PAGE;
62 | if (empty($data->id)) {
63 | throw new coding_exception('Object data must contain property id');
64 | }
65 | if (isset($data->description_editor)) {
66 | $data = file_postupdate_standard_editor($data, 'description',
67 | self::editor_options(), $PAGE->context, 'tool_devcourse', 'entry', $data->id);
68 | }
69 | // Only fields name, completed, priority, description, descriptionformat can be modified.
70 | $updatedata = array_intersect_key((array)$data,
71 | ['id' => 1, 'name' => 1, 'completed' => 1, 'priority' => 1,
72 | 'description' => 1, 'descriptionformat' => 1]);
73 | $updatedata['timemodified'] = time();
74 | $DB->update_record('tool_devcourse', $updatedata);
75 |
76 | // Trigger event.
77 | $entry = self::retrieve($data->id);
78 | $event = \tool_devcourse\event\entry_updated::create([
79 | 'context' => context_course::instance($entry->courseid),
80 | 'objectid' => $entry->id
81 | ]);
82 | $event->add_record_snapshot('tool_devcourse', $entry);
83 | $event->trigger();
84 | }
85 |
86 | /**
87 | * Insert an entry
88 | *
89 | * @param stdClass $data
90 | * @return int id of the new entry
91 | */
92 | public static function insert(stdClass $data) : int {
93 | global $DB;
94 | if (empty($data->courseid)) {
95 | throw new coding_exception('Object data must contain property courseid');
96 | }
97 | $insertdata = array_intersect_key((array)$data,
98 | ['courseid' => 1, 'name' => 1, 'completed' => 1, 'priority' => 1,
99 | 'description' => 1, 'descriptionformat' => 1]);
100 | $insertdata['timemodified'] = $insertdata['timecreated'] = time();
101 | $entryid = $DB->insert_record('tool_devcourse', $insertdata);
102 |
103 | // Now when we know id update the description and save the files.
104 | if (isset($data->description_editor)) {
105 | $context = context_course::instance($data->courseid);
106 | $data = file_postupdate_standard_editor($data, 'description',
107 | self::editor_options(), $context, 'tool_devcourse', 'entry', $entryid);
108 | $updatedata = ['id' => $entryid, 'description' => $data->description,
109 | 'descriptionformat' => $data->descriptionformat];
110 | $DB->update_record('tool_devcourse', $updatedata);
111 | }
112 |
113 | // Trigger event.
114 | $event = \tool_devcourse\event\entry_created::create([
115 | 'context' => context_course::instance($data->courseid),
116 | 'objectid' => $entryid
117 | ]);
118 | $event->trigger();
119 |
120 | return $entryid;
121 | }
122 |
123 | /**
124 | * Delete an entry
125 | *
126 | * @param int $id
127 | */
128 | public static function delete(int $id) {
129 | global $DB;
130 | if (!$entry = self::retrieve($id, 0, IGNORE_MISSING)) {
131 | return;
132 | }
133 | $DB->delete_records('tool_devcourse', ['id' => $id]);
134 |
135 | // Trigger event.
136 | $event = \tool_devcourse\event\entry_deleted::create([
137 | 'context' => context_course::instance($entry->courseid),
138 | 'objectid' => $entry->id
139 | ]);
140 | $event->add_record_snapshot('tool_devcourse', $entry);
141 | $event->trigger();
142 | }
143 |
144 | /**
145 | * Options for the description editor
146 | * @return array
147 | */
148 | public static function editor_options() {
149 | global $PAGE;
150 | return [
151 | 'maxfiles' => -1,
152 | 'maxbytes' => 0,
153 | 'context' => $PAGE->context,
154 | 'noclean' => true,
155 | ];
156 | }
157 |
158 | /**
159 | * Observer for course_deleted event - deletes all associated entries
160 | *
161 | * @param \core\event\course_deleted $event
162 | */
163 | public static function course_deleted_observer(\core\event\course_deleted $event) {
164 | global $DB;
165 | $DB->delete_records('tool_devcourse', ['courseid' => $event->objectid]);
166 | }
167 | }
--------------------------------------------------------------------------------