Файловый менеджер - Редактировать - /home/harasnat/www/mf/notes.tar
Назад
upgrade.txt 0000604 00000000573 15062070721 0006735 0 ustar 00 This file describes API changes in /notes/*, information provided here is intended especially for developers. === 3.7 === * External function core_notes_external::get_course_notes now returns this additional two fields: - canmanagesystemnotes: Whether the user can manage notes at system level. - canmanagecoursenotes: Whether the user can manage notes at the given course. delete.php 0000604 00000006124 15062070721 0006516 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. require_once('../config.php'); require_once('lib.php'); require_once($CFG->dirroot . '/course/lib.php'); $noteid = required_param('id', PARAM_INT); $PAGE->set_url('/notes/delete.php', array('id' => $noteid)); if (!$note = note_load($noteid)) { throw new \moodle_exception('invalidid'); } if (!$course = $DB->get_record('course', array('id' => $note->courseid))) { throw new \moodle_exception('invalidcourseid'); } require_login($course); if (empty($CFG->enablenotes)) { throw new \moodle_exception('notesdisabled', 'notes'); } if (!$user = $DB->get_record('user', array('id' => $note->userid))) { throw new \moodle_exception('invaliduserid'); } $context = context_course::instance($course->id); if (!has_capability('moodle/notes:manage', $context)) { throw new \moodle_exception('nopermissiontodelete', 'notes'); } if (data_submitted() && confirm_sesskey()) { // If data was submitted and is valid, then delete note. $returnurl = $CFG->wwwroot . '/notes/index.php?course=' . $course->id . '&user=' . $note->userid; note_delete($note); redirect($returnurl); } else { // If data was not submitted yet, then show note data with a delete confirmation form. $strnotes = get_string('notes', 'notes'); $optionsyes = array('id' => $noteid, 'sesskey' => sesskey()); $optionsno = array('course' => $course->id, 'user' => $note->userid); // Output HTML. $link = null; if (course_can_view_participants($context) || course_can_view_participants(context_system::instance())) { $link = new moodle_url('/user/index.php', array('id' => $course->id)); } $PAGE->navbar->add(get_string('participants'), $link); $PAGE->navbar->add(fullname($user), new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id))); $PAGE->navbar->add(get_string('notes', 'notes'), new moodle_url('/notes/index.php', array('user' => $user->id, 'course' => $course->id))); $PAGE->navbar->add(get_string('delete')); $PAGE->set_title($course->shortname . ': ' . $strnotes); $PAGE->set_heading($course->fullname); echo $OUTPUT->header(); echo $OUTPUT->confirm(get_string('deleteconfirm', 'notes'), new moodle_url('delete.php', $optionsyes), new moodle_url('index.php', $optionsno)); echo '<br />'; note_print($note, NOTES_SHOW_BODY | NOTES_SHOW_HEAD); echo $OUTPUT->footer(); } edit_form.php 0000604 00000004014 15062070721 0007220 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. if (!defined('MOODLE_INTERNAL')) { die('Direct access to this script is forbidden.'); // It must be included from a Moodle page. } require_once($CFG->libdir.'/formslib.php'); class note_edit_form extends moodleform { /** * Define the form for editing notes */ public function definition() { $mform =& $this->_form; $mform->addElement('header', 'general', get_string('note', 'notes')); $mform->addElement('textarea', 'content', get_string('content', 'notes'), array('rows' => 15, 'cols' => 40)); $mform->setType('content', PARAM_RAW); $mform->addRule('content', get_string('nocontent', 'notes'), 'required', null, 'client'); $mform->setForceLtr('content', false); $mform->addElement('select', 'publishstate', get_string('publishstate', 'notes'), note_get_state_names()); $mform->setDefault('publishstate', NOTES_STATE_PUBLIC); $mform->setType('publishstate', PARAM_ALPHA); $mform->addHelpButton('publishstate', 'publishstate', 'notes'); $this->add_action_buttons(); $mform->addElement('hidden', 'courseid'); $mform->setType('courseid', PARAM_INT); $mform->addElement('hidden', 'userid'); $mform->setType('userid', PARAM_INT); $mform->addElement('hidden', 'id'); $mform->setType('id', PARAM_INT); } } classes/privacy/provider.php 0000604 00000024243 15062070721 0012222 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Privacy Subsystem implementation for core_notes. * * @package core_notes * @copyright 2018 Zig Tan <zig@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_notes\privacy; use core_privacy\local\metadata\collection; use core_privacy\local\request\approved_contextlist; use core_privacy\local\request\contextlist; use core_privacy\local\request\transform; use core_privacy\local\request\writer; use core_privacy\local\request\userlist; use \core_privacy\local\request\approved_userlist; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/notes/lib.php'); /** * Implementation of the privacy subsystem plugin provider for core_notes. * * @copyright 2018 Zig Tan <zig@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\plugin\provider { /** * Return the fields which contain personal data. * * @param collection $items a reference to the collection to use to store the metadata. * @return collection the updated collection of metadata items. */ public static function get_metadata(collection $items) : collection { // The core_notes components utilises the shared mdl_post table. $items->add_database_table( 'post', [ 'content' => 'privacy:metadata:core_notes:content', 'courseid' => 'privacy:metadata:core_notes:courseid', 'created' => 'privacy:metadata:core_notes:created', 'lastmodified' => 'privacy:metadata:core_notes:lastmodified', 'publishstate' => 'privacy:metadata:core_notes:publishstate', 'userid' => 'privacy:metadata:core_notes:userid' ], 'privacy:metadata:core_notes' ); return $items; } /** * Get the list of contexts that contain user information for the specified user. * * @param int $userid the userid. * @return contextlist the list of contexts containing user info for the user. */ public static function get_contexts_for_userid(int $userid) : contextlist { global $DB; $contextlist = new contextlist(); $publishstates = [ NOTES_STATE_PUBLIC, NOTES_STATE_SITE ]; list($publishstatesql, $publishstateparams) = $DB->get_in_or_equal($publishstates, SQL_PARAMS_NAMED); // Retrieve all the Course contexts associated with notes written by the user, and also written about the user. // Only notes written about the user that are public or site wide will be exported. $sql = "SELECT c.id FROM {context} c INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenby WHERE p.module = 'notes' AND p.usermodified = :usermodified UNION SELECT c.id FROM {context} c INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenfor WHERE p.module = 'notes' AND p.userid = :userid AND p.publishstate {$publishstatesql}"; $params = [ 'contextcoursewrittenby' => CONTEXT_COURSE, 'usermodified' => $userid, 'contextcoursewrittenfor' => CONTEXT_COURSE, 'userid' => $userid ]; $params += $publishstateparams; $contextlist->add_from_sql($sql, $params); return $contextlist; } /** * Get the list of users who have data within a context. * * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. */ public static function get_users_in_context(userlist $userlist) { global $DB; $context = $userlist->get_context(); if (!$context instanceof \context_course) { return; } $params = [ 'instanceid' => $context->instanceid ]; $sql = "SELECT usermodified as userid FROM {post} WHERE module = 'notes' AND courseid = :instanceid"; $userlist->add_from_sql('userid', $sql, $params); $publishstates = [ NOTES_STATE_PUBLIC, NOTES_STATE_SITE ]; list($publishstatesql, $publishstateparams) = $DB->get_in_or_equal($publishstates, SQL_PARAMS_NAMED); $params += $publishstateparams; $sql = "SELECT userid FROM {post} WHERE module = 'notes' AND courseid = :instanceid AND publishstate {$publishstatesql}"; $userlist->add_from_sql('userid', $sql, $params); } /** * Export personal data for the given approved_contextlist. * User and context information is contained within the contextlist. * * @param approved_contextlist $contextlist a list of contexts approved for export. */ public static function export_user_data(approved_contextlist $contextlist) { global $DB; if (empty($contextlist->count())) { return; } $userid = $contextlist->get_user()->id; list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); // Export all notes written by and written about the user, and organize it by the associated Course context(s). $sql = "SELECT p.courseid as courseid, p.content as content, p.publishstate as publishstate, p.userid as userid, p.usermodified as usermodified, p.created as datecreated, p.lastmodified as datemodified FROM {context} c INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcourse WHERE p.module = 'notes' AND (p.usermodified = :usermodified OR p.userid = :userid) AND c.id {$contextsql}"; $params = [ 'contextcourse' => CONTEXT_COURSE, 'usermodified' => $userid, 'userid' => $userid ]; $params += $contextparams; $notes = $DB->get_recordset_sql($sql, $params); foreach ($notes as $note) { $contextcourse = \context_course::instance($note->courseid); // The exported notes will be organized in {Course Context}/Notes/{publishstate}/usernote-{userid}.json. $subcontext = [ get_string('notes', 'notes'), $note->publishstate ]; $name = 'usernote-' . transform::user($note->userid); $notecontent = (object) [ 'content' => $note->content, 'publishstate' => $note->publishstate, 'userid' => transform::user($note->userid), 'usermodified' => transform::user($note->usermodified), 'datecreated' => transform::datetime($note->datecreated), 'datemodified' => transform::datetime($note->datemodified) ]; writer::with_context($contextcourse)->export_related_data($subcontext, $name, $notecontent); } $notes->close(); } /** * Delete all data for all users in the specified context. * * @param \context $context the context to delete in. */ public static function delete_data_for_all_users_in_context(\context $context) { global $DB; if ($context->contextlevel != CONTEXT_COURSE) { return; } $DB->delete_records('post', ['module' => 'notes', 'courseid' => $context->instanceid]); } /** * Delete multiple users within a single context. * * @param approved_userlist $userlist The approved context and user information to delete information for. */ public static function delete_data_for_users(approved_userlist $userlist) { global $DB; $context = $userlist->get_context(); if ($context->contextlevel != CONTEXT_COURSE) { return; } $userids = $userlist->get_userids(); if (empty($userids)) { return; } list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); $select = "module = :module AND courseid = :courseid AND usermodified {$usersql}"; $params = ['module' => 'notes', 'courseid' => $context->instanceid] + $userparams; $DB->delete_records_select('post', $select, $params); } /** * Delete all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist a list of contexts approved for deletion. */ public static function delete_data_for_user(approved_contextlist $contextlist) { global $DB; if (empty($contextlist->count())) { return; } $userid = $contextlist->get_user()->id; foreach ($contextlist->get_contexts() as $context) { $conditions = [ 'module' => 'notes', 'courseid' => $context->instanceid, 'usermodified' => $userid ]; $DB->delete_records('post', $conditions); } } } classes/reportbuilder/local/entities/note.php 0000604 00000016076 15062070721 0015465 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. declare(strict_types=1); namespace core_notes\reportbuilder\local\entities; use lang_string; use stdClass; use core_reportbuilder\local\entities\base; use core_reportbuilder\local\filters\{date, select, text}; use core_reportbuilder\local\helpers\format; use core_reportbuilder\local\report\{column, filter}; defined('MOODLE_INTERNAL') || die; global $CFG; require_once("{$CFG->dirroot}/notes/lib.php"); /** * Note entity * * @package core_notes * @copyright 2022 Paul Holden <paulh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class note extends base { /** * Database tables that this entity uses and their default aliases * * @return array */ protected function get_default_table_aliases(): array { return ['post' => 'np']; } /** * The default title for this entity * * @return lang_string */ protected function get_default_entity_title(): lang_string { return new lang_string('note', 'core_notes'); } /** * Initialise the entity * * @return base */ public function initialise(): base { $columns = $this->get_all_columns(); foreach ($columns as $column) { $this->add_column($column); } // All the filters defined by the entity can also be used as conditions. $filters = $this->get_all_filters(); foreach ($filters as $filter) { $this ->add_filter($filter) ->add_condition($filter); } return $this; } /** * Returns list of all available columns * * @return column[] */ protected function get_all_columns(): array { global $DB; $postalias = $this->get_table_alias('post'); // Content. $contentfieldsql = "{$postalias}.content"; if ($DB->get_dbfamily() === 'oracle') { $contentfieldsql = $DB->sql_order_by_text($contentfieldsql, 1024); } $columns[] = (new column( 'content', new lang_string('content', 'core_notes'), $this->get_entity_name() )) ->add_joins($this->get_joins()) ->set_type(column::TYPE_LONGTEXT) ->add_field($contentfieldsql, 'content') ->add_field("{$postalias}.format") ->add_callback(static function(?string $content, stdClass $note): string { if ($content === null) { return ''; } return format_text($content, $note->format); }); // Publish state. $columns[] = (new column( 'publishstate', new lang_string('publishstate', 'core_notes'), $this->get_entity_name() )) ->add_joins($this->get_joins()) ->set_type(column::TYPE_TEXT) ->add_fields("{$postalias}.publishstate") ->set_is_sortable(true) ->add_callback(static function(string $publishstate): string { $states = [ NOTES_STATE_SITE => new lang_string('sitenotes', 'core_notes'), NOTES_STATE_PUBLIC => new lang_string('coursenotes', 'core_notes'), NOTES_STATE_DRAFT => new lang_string('personalnotes', 'core_notes'), ]; return (string) ($states[$publishstate] ?? $publishstate); }); // Time created. $columns[] = (new column( 'timecreated', new lang_string('timecreated', 'core_reportbuilder'), $this->get_entity_name() )) ->add_joins($this->get_joins()) ->set_type(column::TYPE_TIMESTAMP) ->add_fields("{$postalias}.created") ->set_is_sortable(true) ->add_callback([format::class, 'userdate']); // Time modified. $columns[] = (new column( 'timemodified', new lang_string('timemodified', 'core_reportbuilder'), $this->get_entity_name() )) ->add_joins($this->get_joins()) ->set_type(column::TYPE_TIMESTAMP) ->add_fields("{$postalias}.lastmodified") ->set_is_sortable(true) ->add_callback([format::class, 'userdate']); return $columns; } /** * Return list of all available filters * * @return filter[] */ protected function get_all_filters(): array { global $DB; $postalias = $this->get_table_alias('post'); // Content. $filters[] = (new filter( text::class, 'content', new lang_string('content', 'core_notes'), $this->get_entity_name(), $DB->sql_cast_to_char("{$postalias}.content") )) ->add_joins($this->get_joins()); // Publish state. $filters[] = (new filter( select::class, 'publishstate', new lang_string('publishstate', 'core_notes'), $this->get_entity_name(), "{$postalias}.publishstate" )) ->add_joins($this->get_joins()) ->set_options([ NOTES_STATE_SITE => new lang_string('sitenotes', 'core_notes'), NOTES_STATE_PUBLIC => new lang_string('coursenotes', 'core_notes'), NOTES_STATE_DRAFT => new lang_string('personalnotes', 'core_notes'), ]); // Time created. $filters[] = (new filter( date::class, 'timecreated', new lang_string('timecreated', 'core_reportbuilder'), $this->get_entity_name(), "{$postalias}.created" )) ->add_joins($this->get_joins()) ->set_limited_operators([ date::DATE_ANY, date::DATE_CURRENT, date::DATE_LAST, date::DATE_RANGE, ]); // Time modified. $filters[] = (new filter( date::class, 'timemodified', new lang_string('timemodified', 'core_reportbuilder'), $this->get_entity_name(), "{$postalias}.lastmodified" )) ->add_joins($this->get_joins()) ->set_limited_operators([ date::DATE_ANY, date::DATE_CURRENT, date::DATE_LAST, date::DATE_RANGE, ]); return $filters; } } classes/reportbuilder/datasource/notes.php 0000604 00000010736 15062070721 0015061 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. declare(strict_types=1); namespace core_notes\reportbuilder\datasource; use lang_string; use core_reportbuilder\datasource; use core_reportbuilder\local\entities\{course, user}; use core_notes\reportbuilder\local\entities\note; defined('MOODLE_INTERNAL') || die; global $CFG; require_once("{$CFG->dirroot}/notes/lib.php"); /** * Notes datasource * * @package core_notes * @copyright 2022 Paul Holden <paulh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class notes extends datasource { /** * Return user friendly name of the report source * * @return string */ public static function get_name(): string { return get_string('notes', 'core_notes'); } /** * Initialise report */ protected function initialise(): void { $noteentity = new note(); $postalias = $noteentity->get_table_alias('post'); $this->set_main_table('post', $postalias); $this->add_base_condition_simple("{$postalias}.module", 'notes'); $this->add_entity($noteentity); // Join the user entity to represent the note recipient. $recipiententity = (new user()) ->set_entity_name('recipient') ->set_entity_title(new lang_string('recipient', 'core_notes')); $recipientalias = $recipiententity->get_table_alias('user'); $this->add_entity($recipiententity->add_join(" LEFT JOIN {user} {$recipientalias} ON {$recipientalias}.id = {$postalias}.userid") ); // Join the user entity to represent the note author. Override all entity table aliases to avoid clash with first instance. $authorentity = (new user()) ->set_entity_name('author') ->set_entity_title(new lang_string('author', 'core_notes')) ->set_table_aliases([ 'user' => 'au', 'context' => 'auctx', ]); $this->add_entity($authorentity->add_join(" LEFT JOIN {user} au ON au.id = {$postalias}.usermodified") ); // Join the course entity for course notes. $courseentity = new course(); $coursealias = $courseentity->get_table_alias('course'); $this->add_entity($courseentity->add_join(" LEFT JOIN {course} {$coursealias} ON {$coursealias}.id = {$postalias}.courseid AND {$postalias}.publishstate = '" . NOTES_STATE_PUBLIC . "'") ); // Add report elements from each of the entities we added to the report. $this->add_all_from_entities(); } /** * Return the columns that will be added to the report upon creation * * @return string[] */ public function get_default_columns(): array { return [ 'recipient:fullname', 'note:publishstate', 'course:fullname', 'note:content', 'note:timecreated', ]; } /** * Return the column sorting that will be added to the report upon creation * * @return int[] */ public function get_default_column_sorting(): array { return [ 'recipient:fullname' => SORT_ASC, 'note:timecreated' => SORT_ASC, ]; } /** * Return the filters that will be added to the report upon creation * * @return string[] */ public function get_default_filters(): array { return [ 'recipient:fullname', ]; } /** * Return the conditions that will be added to the report upon creation * * @return string[] */ public function get_default_conditions(): array { return [ 'note:publishstate', 'course:fullname', 'recipient:fullname', ]; } } index.php 0000604 00000014474 15062070721 0006372 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * file index.php * index page to view notes. * if a course id is specified then the entries from that course are shown * if a user id is specified only notes related to that user are shown */ require_once('../config.php'); require_once('lib.php'); require_once($CFG->dirroot . '/course/lib.php'); $courseid = optional_param('course', SITEID, PARAM_INT); $userid = optional_param('user', 0, PARAM_INT); $filtertype = optional_param('filtertype', '', PARAM_ALPHA); $filterselect = optional_param('filterselect', 0, PARAM_INT); if (empty($CFG->enablenotes)) { throw new \moodle_exception('notesdisabled', 'notes'); } $url = new moodle_url('/notes/index.php'); if ($courseid != SITEID) { $url->param('course', $courseid); } if ($userid !== 0) { $url->param('user', $userid); } $PAGE->set_url($url); // Tabs compatibility. switch($filtertype) { case 'course': $courseid = $filterselect; break; case 'site': $courseid = SITEID; break; } if (empty($courseid)) { $courseid = SITEID; } $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); if ($userid) { $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); $filtertype = 'user'; $filterselect = $user->id; if ($user->deleted) { echo $OUTPUT->header(); echo $OUTPUT->heading(get_string('userdeleted')); echo $OUTPUT->footer(); die; } } else { $filtertype = 'course'; $filterselect = $course->id; $user = $USER; } require_login($course); // Output HTML. if ($course->id == SITEID) { $coursecontext = context_system::instance(); } else { $coursecontext = context_course::instance($course->id); } require_capability('moodle/notes:view', $coursecontext); $systemcontext = context_system::instance(); // Trigger event. note_view($coursecontext, $userid); $strnotes = get_string('notes', 'notes'); if ($userid && $course->id == SITEID) { $PAGE->set_context(context_user::instance($user->id)); $PAGE->navigation->extend_for_user($user); // If we are looking at our own notes, then change focus to 'my notes'. if ($userid == $USER->id) { $notenode = $PAGE->navigation->find('notes', null)->make_inactive(); } $notesurl = new moodle_url('/notes/index.php', array('user' => $userid)); $PAGE->navbar->add(get_string('notes', 'notes'), $notesurl); } else if ($course->id != SITEID) { $notenode = $PAGE->navigation->find('currentcoursenotes', null)->make_inactive(); $notesurl = new moodle_url('/notes/index.php', array('user' => $userid, 'course' => $courseid)); $PAGE->navbar->add(get_string('notes', 'notes'), $notesurl); $PAGE->set_context(context_course::instance($courseid)); } else { $link = null; if (course_can_view_participants($coursecontext) || course_can_view_participants($systemcontext)) { $link = new moodle_url('/user/index.php', array('id' => $course->id)); } } $PAGE->set_pagelayout('incourse'); $PAGE->set_title($course->fullname); if ($course->id == SITEID) { $PAGE->set_heading(fullname($user)); } else { $PAGE->set_heading($course->fullname); } echo $OUTPUT->header(); if ($course->id != SITEID) { $backurl = new moodle_url('/user/view.php', ['id' => $userid, 'course' => $courseid]); echo $OUTPUT->single_button($backurl, get_string('back'), 'get', ['class' => 'mb-3']); $headerinfo = array('heading' => fullname($user), 'user' => $user); echo $OUTPUT->context_header($headerinfo, 2); } echo $OUTPUT->heading($strnotes); $strsitenotes = get_string('sitenotes', 'notes'); $strcoursenotes = get_string('coursenotes', 'notes'); $strpersonalnotes = get_string('personalnotes', 'notes'); $straddnewnote = get_string('addnewnote', 'notes'); echo $OUTPUT->box_start(); if ($courseid != SITEID) { $context = context_course::instance($courseid); $addid = has_capability('moodle/notes:manage', $context) ? $courseid : 0; $view = has_capability('moodle/notes:view', $context); $fullname = format_string($course->fullname, true, array('context' => $context)); note_print_notes( '<a name="sitenotes"></a>' . $strsitenotes, $addid, $view, 0, $userid, NOTES_STATE_SITE, 0 ); note_print_notes( '<a name="coursenotes"></a>' . $strcoursenotes. ' ('.$fullname.')', $addid, $view, $courseid, $userid, NOTES_STATE_PUBLIC, 0 ); note_print_notes( '<a name="personalnotes"></a>' . $strpersonalnotes, $addid, $view, $courseid, $userid, NOTES_STATE_DRAFT, $USER->id ); } else { // Normal course. $view = has_capability('moodle/notes:view', context_system::instance()); note_print_notes('<a name="sitenotes"></a>' . $strsitenotes, 0, $view, 0, $userid, NOTES_STATE_SITE, 0); echo '<a name="coursenotes"></a>'; if (!empty($userid)) { $courses = enrol_get_users_courses($userid); foreach ($courses as $c) { $ccontext = context_course::instance($c->id); $cfullname = format_string($c->fullname, true, array('context' => $ccontext)); $header = '<a href="' . $CFG->wwwroot . '/course/view.php?id=' . $c->id . '">' . $cfullname . '</a>'; $viewcoursenotes = has_capability('moodle/notes:view', $ccontext); if (has_capability('moodle/notes:manage', $ccontext)) { $addid = $c->id; } else { $addid = 0; } note_print_notes($header, $addid, $viewcoursenotes, $c->id, $userid, NOTES_STATE_PUBLIC, 0); } } } echo $OUTPUT->box_end(); echo $OUTPUT->footer(); lib.php 0000604 00000032677 15062070721 0006036 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Library of functions and constants for notes * * @package core_notes * @copyright 2007 onwards Yu Zhang * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Constants for states. */ define('NOTES_STATE_DRAFT', 'draft'); define('NOTES_STATE_PUBLIC', 'public'); define('NOTES_STATE_SITE', 'site'); /** * Constants for note parts (flags used by note_print and note_print_list). */ define('NOTES_SHOW_FULL', 0x07); define('NOTES_SHOW_HEAD', 0x02); define('NOTES_SHOW_BODY', 0x01); define('NOTES_SHOW_FOOT', 0x04); /** * Retrieves a list of note objects with specific atributes. * * @param int $courseid id of the course in which the notes were posted (0 means any) * @param int $userid id of the user to which the notes refer (0 means any) * @param string $state state of the notes (i.e. draft, public, site) ('' means any) * @param int $author id of the user who modified the note last time (0 means any) * @param string $order an order to sort the results in * @param int $limitfrom number of records to skip (offset) * @param int $limitnum number of records to fetch * @return array of note objects */ function note_list($courseid=0, $userid=0, $state = '', $author = 0, $order='lastmodified DESC', $limitfrom=0, $limitnum=0) { global $DB; // Setup filters. $selects = array(); $params = array(); if ($courseid) { $selects[] = 'courseid=?'; $params[] = $courseid; } if ($userid) { $selects[] = 'userid=?'; $params[] = $userid; } if ($author) { $selects[] = 'usermodified=?'; $params[] = $author; } if ($state) { $selects[] = 'publishstate=?'; $params[] = $state; } $selects[] = "module=?"; $params[] = 'notes'; $select = implode(' AND ', $selects); $fields = 'id,courseid,userid,content,format,created,lastmodified,usermodified,publishstate'; return $DB->get_records_select('post', $select, $params, $order, $fields, $limitfrom, $limitnum); } /** * Retrieves a note object based on its id. * * @param int $noteid ID of the note to retrieve * @return stdClass object */ function note_load($noteid) { global $DB; $fields = 'id,courseid,userid,content,format,created,lastmodified,usermodified,publishstate'; return $DB->get_record('post', array('id' => $noteid, 'module' => 'notes'), $fields); } /** * Saves a note object. The note object is passed by reference and its fields (i.e. id) * might change during the save. * * @param stdClass $note object to save * @return boolean true if the object was saved; false otherwise */ function note_save(&$note) { global $USER, $DB; // Setup & clean fields. $note->module = 'notes'; $note->lastmodified = time(); $note->usermodified = $USER->id; if (empty($note->format)) { $note->format = FORMAT_PLAIN; } if (empty($note->publishstate)) { $note->publishstate = NOTES_STATE_PUBLIC; } if (empty(trim($note->content))) { // Don't save empty notes. return false; } // Save data. if (empty($note->id)) { // Insert new note. $note->created = $note->lastmodified; $id = $DB->insert_record('post', $note); $note = note_load($id); // Trigger event. $event = \core\event\note_created::create(array( 'objectid' => $note->id, 'courseid' => $note->courseid, 'relateduserid' => $note->userid, 'userid' => $note->usermodified, 'context' => context_course::instance($note->courseid), 'other' => array('publishstate' => $note->publishstate) )); $event->trigger(); } else { // Update old note. $DB->update_record('post', $note); $note = note_load($note->id); // Trigger event. $event = \core\event\note_updated::create(array( 'objectid' => $note->id, 'courseid' => $note->courseid, 'relateduserid' => $note->userid, 'userid' => $note->usermodified, 'context' => context_course::instance($note->courseid), 'other' => array('publishstate' => $note->publishstate) )); $event->trigger(); } unset($note->module); return true; } /** * Deletes a note object based on its id. * * @param int|object $note id of the note to delete, or a note object which is to be deleted. * @return boolean true always */ function note_delete($note) { global $DB; if (is_int($note)) { $noteid = $note; } else { $noteid = $note->id; } // Get the full record, note_load doesn't return everything. $note = $DB->get_record('post', array('id' => $noteid), '*', MUST_EXIST); $return = $DB->delete_records('post', array('id' => $note->id, 'module' => 'notes')); // Trigger event. $event = \core\event\note_deleted::create(array( 'objectid' => $note->id, 'courseid' => $note->courseid, 'relateduserid' => $note->userid, 'userid' => $note->usermodified, 'context' => context_course::instance($note->courseid), 'other' => array('publishstate' => $note->publishstate) )); $event->add_record_snapshot('post', $note); $event->trigger(); return $return; } /** * Converts a state value to its corespondent name * * @param string $state state value to convert * @return string corespondent state name */ function note_get_state_name($state) { // Cache state names. static $states; if (empty($states)) { $states = note_get_state_names(); } if (isset($states[$state])) { return $states[$state]; } else { return null; } } /** * Returns an array of mappings from state values to state names * * @return array of mappings */ function note_get_state_names() { return array( NOTES_STATE_DRAFT => get_string('personal', 'notes'), NOTES_STATE_PUBLIC => get_string('course', 'notes'), NOTES_STATE_SITE => get_string('site', 'notes'), ); } /** * Prints a note object * * @param note $note the note object to print * @param int $detail OR-ed NOTES_SHOW_xyz flags that specify which note parts to print */ function note_print($note, $detail = NOTES_SHOW_FULL) { global $CFG, $USER, $DB, $OUTPUT; if (!$user = $DB->get_record('user', array('id' => $note->userid))) { debugging("User $note->userid not found"); return; } if (!$author = $DB->get_record('user', array('id' => $note->usermodified))) { debugging("User $note->usermodified not found"); return; } $context = context_course::instance($note->courseid); $systemcontext = context_system::instance(); $authoring = new stdClass(); $authoring->name = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $author->id . '&course='.$note->courseid . '">' . fullname($author) . '</a>'; $authoring->date = userdate($note->lastmodified); echo '<div class="notepost '. $note->publishstate . 'notepost' . ($note->usermodified == $USER->id ? ' ownnotepost' : '') . '" id="note-' . $note->id . '">'; // Print note head (e.g. author, user refering to, etc). if ($detail & NOTES_SHOW_HEAD) { echo '<div class="header">'; echo '<div class="user">'; echo $OUTPUT->user_picture($user, array('courseid' => $note->courseid)); echo fullname($user) . '</div>'; echo '<div class="info">' . get_string('bynameondate', 'notes', $authoring) . ' (' . get_string('created', 'notes') . ': ' . userdate($note->created) . ')</div>'; echo '</div>'; } // Print note content. if ($detail & NOTES_SHOW_BODY) { echo '<div class="content">'; echo format_text($note->content, $note->format, array('overflowdiv' => true)); echo '</div>'; } // Print note options (e.g. delete, edit). if ($detail & NOTES_SHOW_FOOT) { if (has_capability('moodle/notes:manage', $systemcontext) && $note->publishstate == NOTES_STATE_SITE || has_capability('moodle/notes:manage', $context) && ($note->publishstate == NOTES_STATE_PUBLIC || $note->usermodified == $USER->id)) { echo '<div class="footer"><p>'; echo '<a href="' . $CFG->wwwroot . '/notes/edit.php?id=' . $note->id. '">' . get_string('edit') . '</a> | '; echo '<a href="' . $CFG->wwwroot . '/notes/delete.php?id=' . $note->id. '">' . get_string('delete') . '</a>'; echo '</p></div>'; } } echo '</div>'; } /** * Prints a list of note objects * * @param array $notes array of note objects to print * @param int $detail OR-ed NOTES_SHOW_xyz flags that specify which note parts to print */ function note_print_list($notes, $detail = NOTES_SHOW_FULL) { echo '<div class="notelist">'; foreach ($notes as $note) { note_print($note, $detail); } echo '</div>'; } /** * Retrieves and prints a list of note objects with specific atributes. * * @param string $header HTML to print above the list * @param int $addcourseid id of the course for the add notes link (0 hide link) * @param boolean $viewnotes true if the notes should be printed; false otherwise (print notesnotvisible string) * @param int $courseid id of the course in which the notes were posted (0 means any) * @param int $userid id of the user to which the notes refer (0 means any) * @param string $state state of the notes (i.e. draft, public, site) ('' means any) * @param int $author id of the user who modified the note last time (0 means any) */ function note_print_notes($header, $addcourseid = 0, $viewnotes = true, $courseid = 0, $userid = 0, $state = '', $author = 0) { global $CFG; if ($header) { echo '<h3 class="notestitle">' . $header . '</h3>'; echo '<div class="notesgroup">'; } if ($addcourseid) { if ($userid) { echo '<p><a href="' . $CFG->wwwroot . '/notes/edit.php?courseid=' . $addcourseid . '&userid=' . $userid . '&publishstate=' . $state . '">' . get_string('addnewnote', 'notes') . '</a></p>'; } else { echo '<p><a href="' . $CFG->wwwroot . '/user/index.php?id=' . $addcourseid. '">' . get_string('addnewnoteselect', 'notes') . '</a></p>'; } } if ($viewnotes) { $notes = note_list($courseid, $userid, $state, $author); if ($notes) { note_print_list($notes); } } else { echo '<p>' . get_string('notesnotvisible', 'notes') . '</p>'; } if ($header) { echo '</div>'; // The notesgroup div. } } /** * Delete all notes about users in course- * @param int $courseid * @return bool success */ function note_delete_all($courseid) { global $DB; return $DB->delete_records('post', array('module' => 'notes', 'courseid' => $courseid)); } /** * Return a list of page types * @param string $pagetype current page type * @param stdClass $parentcontext Block's parent context * @param stdClass $currentcontext Current context of block */ function note_page_type_list($pagetype, $parentcontext, $currentcontext) { return array('notes-*' => get_string('page-notes-x', 'notes')); } /** * Trigger notes viewed event * * @param stdClass $context context object * @param int $userid user id (the user we are viewing the notes) * @since Moodle 2.9 */ function note_view($context, $userid) { $event = \core\event\notes_viewed::create(array( 'relateduserid' => $userid, 'context' => $context )); $event->trigger(); } /** * Add nodes to myprofile page. * * @param \core_user\output\myprofile\tree $tree Tree object * @param stdClass $user user object * @param bool $iscurrentuser * @param stdClass $course Course object * * @return bool */ function core_notes_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) { global $CFG; if (empty($CFG->enablenotes)) { // Notes are disabled, nothing to do. return false; } if (isguestuser($user)) { // No notes for guest users. return false; } $url = new moodle_url("/notes/index.php", array('user' => $user->id)); $title = get_string('notes', 'core_notes'); if (empty($course)) { // Site level profile. if (!has_capability('moodle/notes:view', context_system::instance())) { // No cap, nothing to do. return false; } } else { if (!has_capability('moodle/notes:view', context_course::instance($course->id))) { // No cap, nothing to do. return false; } $url->param('course', $course->id); } $notesnode = new core_user\output\myprofile\node('miscellaneous', 'notes', $title, null, $url); $tree->add_node($notesnode); } externallib.php 0000604 00000071310 15062070721 0007564 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. use core_external\external_api; use core_external\external_format_value; use core_external\external_function_parameters; use core_external\external_multiple_structure; use core_external\external_single_structure; use core_external\external_value; use core_external\external_warnings; use core_external\util; /** * External notes API * * @package core_notes * @category external * @copyright 2011 Jerome Mouneyrac * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . "/notes/lib.php"); /** * Notes external functions * * @package core_notes * @category external * @copyright 2011 Jerome Mouneyrac * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.2 */ class core_notes_external extends external_api { /** * Returns description of method parameters * * @return external_function_parameters * @since Moodle 2.2 */ public static function create_notes_parameters() { return new external_function_parameters( array( 'notes' => new external_multiple_structure( new external_single_structure( array( 'userid' => new external_value(PARAM_INT, 'id of the user the note is about'), 'publishstate' => new external_value(PARAM_ALPHA, '\'personal\', \'course\' or \'site\''), 'courseid' => new external_value(PARAM_INT, 'course id of the note (in Moodle a note can only be created into a course, even for site and personal notes)'), 'text' => new external_value(PARAM_RAW, 'the text of the message - text or HTML'), 'format' => new external_format_value('text', VALUE_DEFAULT), 'clientnoteid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the note. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL), ) ) ) ) ); } /** * Create notes about some users * Note: code should be matching the /notes/edit.php checks * and the /user/addnote.php checks. (they are similar cheks) * * @param array $notes An array of notes to create. * @return array (success infos and fail infos) * @since Moodle 2.2 */ public static function create_notes($notes = array()) { global $CFG, $DB; $params = self::validate_parameters(self::create_notes_parameters(), array('notes' => $notes)); // Check if note system is enabled. if (!$CFG->enablenotes) { throw new moodle_exception('notesdisabled', 'notes'); } // Retrieve all courses. $courseids = array(); foreach ($params['notes'] as $note) { $courseids[] = $note['courseid']; } $courses = $DB->get_records_list("course", "id", $courseids); // Retrieve all users of the notes. $userids = array(); foreach ($params['notes'] as $note) { $userids[] = $note['userid']; } list($sqluserids, $sqlparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'userid_'); $users = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams); $resultnotes = array(); foreach ($params['notes'] as $note) { $success = true; $resultnote = array(); // The infos about the success of the operation. // Check the course exists. if (empty($courses[$note['courseid']])) { $success = false; $errormessage = get_string('invalidcourseid', 'error'); } else { // Ensure the current user is allowed to run this function. $context = context_course::instance($note['courseid']); self::validate_context($context); require_capability('moodle/notes:manage', $context); } // Check the user exists. if (empty($users[$note['userid']])) { $success = false; $errormessage = get_string('invaliduserid', 'notes', $note['userid']); } // Build the resultnote. if (isset($note['clientnoteid'])) { $resultnote['clientnoteid'] = $note['clientnoteid']; } if ($success) { // Now we can create the note. $dbnote = new stdClass; $dbnote->courseid = $note['courseid']; $dbnote->userid = $note['userid']; // Need to support 'html' and 'text' format values for backward compatibility. switch (strtolower($note['format'])) { case 'html': $textformat = FORMAT_HTML; break; case 'text': $textformat = FORMAT_PLAIN; default: $textformat = util::validate_format($note['format']); break; } $dbnote->content = $note['text']; $dbnote->format = $textformat; // Get the state ('personal', 'course', 'site'). switch ($note['publishstate']) { case 'personal': $dbnote->publishstate = NOTES_STATE_DRAFT; break; case 'course': $dbnote->publishstate = NOTES_STATE_PUBLIC; break; case 'site': $dbnote->publishstate = NOTES_STATE_SITE; $dbnote->courseid = SITEID; break; default: break; } // TODO MDL-31119 performance improvement - if possible create a bulk functions for saving multiple notes at once if (note_save($dbnote)) { // Note_save attribut an id in case of success. $success = $dbnote->id; } $resultnote['noteid'] = $success; } else { // WARNINGS: for backward compatibility we return this errormessage. // We should have thrown exceptions as these errors prevent results to be returned. // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side . $resultnote['noteid'] = -1; $resultnote['errormessage'] = $errormessage; } $resultnotes[] = $resultnote; } return $resultnotes; } /** * Returns description of method result value * * @return \core_external\external_description * @since Moodle 2.2 */ public static function create_notes_returns() { return new external_multiple_structure( new external_single_structure( array( 'clientnoteid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the note', VALUE_OPTIONAL), 'noteid' => new external_value(PARAM_INT, 'ID of the created note when successful, -1 when failed'), 'errormessage' => new external_value(PARAM_TEXT, 'error message - if failed', VALUE_OPTIONAL) ) ) ); } /** * Returns description of delete_notes parameters * * @return external_function_parameters * @since Moodle 2.5 */ public static function delete_notes_parameters() { return new external_function_parameters( array( "notes"=> new external_multiple_structure( new external_value(PARAM_INT, 'ID of the note to be deleted'), 'Array of Note Ids to be deleted.' ) ) ); } /** * Delete notes about users. * Note: code should be matching the /notes/delete.php checks. * * @param array $notes An array of ids for the notes to delete. * @return null * @since Moodle 2.5 */ public static function delete_notes($notes = array()) { global $CFG; $params = self::validate_parameters(self::delete_notes_parameters(), array('notes' => $notes)); // Check if note system is enabled. if (!$CFG->enablenotes) { throw new moodle_exception('notesdisabled', 'notes'); } $warnings = array(); foreach ($params['notes'] as $noteid) { $note = note_load($noteid); if (isset($note->id)) { // Ensure the current user is allowed to run this function. $context = context_course::instance($note->courseid); self::validate_context($context); require_capability('moodle/notes:manage', $context); note_delete($note); } else { $warnings[] = array('item'=>'note', 'itemid'=>$noteid, 'warningcode'=>'badid', 'message'=>'Note does not exist'); } } return $warnings; } /** * Returns description of delete_notes result value. * * @return \core_external\external_description * @since Moodle 2.5 */ public static function delete_notes_returns() { return new external_warnings('item is always \'note\'', 'When errorcode is savedfailed the note could not be modified.' . 'When errorcode is badparam, an incorrect parameter was provided.' . 'When errorcode is badid, the note does not exist', 'errorcode can be badparam (incorrect parameter), savedfailed (could not be modified), or badid (note does not exist)'); } /** * Returns description of get_notes parameters. * * @return external_function_parameters * @since Moodle 2.5 */ public static function get_notes_parameters() { return new external_function_parameters( array( "notes"=> new external_multiple_structure( new external_value(PARAM_INT, 'ID of the note to be retrieved'), 'Array of Note Ids to be retrieved.' ) ) ); } /** * Get notes about users. * * @param array $notes An array of ids for the notes to retrieve. * @return null * @since Moodle 2.5 */ public static function get_notes($notes) { global $CFG; $params = self::validate_parameters(self::get_notes_parameters(), array('notes' => $notes)); // Check if note system is enabled. if (!$CFG->enablenotes) { throw new moodle_exception('notesdisabled', 'notes'); } $resultnotes = array(); foreach ($params['notes'] as $noteid) { $resultnote = array(); $note = note_load($noteid); if (isset($note->id)) { // Ensure the current user is allowed to run this function. $context = context_course::instance($note->courseid); self::validate_context($context); require_capability('moodle/notes:view', $context); list($gotnote['text'], $gotnote['format']) = util::format_text($note->content, $note->format, $context->id, 'notes', '', ''); $gotnote['noteid'] = $note->id; $gotnote['userid'] = $note->userid; $gotnote['publishstate'] = $note->publishstate; $gotnote['courseid'] = $note->courseid; $resultnotes["notes"][] = $gotnote; } else { $resultnotes["warnings"][] = array('item' => 'note', 'itemid' => $noteid, 'warningcode' => 'badid', 'message' => 'Note does not exist'); } } return $resultnotes; } /** * Returns description of get_notes result value. * * @return \core_external\external_description * @since Moodle 2.5 */ public static function get_notes_returns() { return new external_single_structure( array( 'notes' => new external_multiple_structure( new external_single_structure( array( 'noteid' => new external_value(PARAM_INT, 'id of the note', VALUE_OPTIONAL), 'userid' => new external_value(PARAM_INT, 'id of the user the note is about', VALUE_OPTIONAL), 'publishstate' => new external_value(PARAM_ALPHA, '\'personal\', \'course\' or \'site\'', VALUE_OPTIONAL), 'courseid' => new external_value(PARAM_INT, 'course id of the note', VALUE_OPTIONAL), 'text' => new external_value(PARAM_RAW, 'the text of the message - text or HTML', VALUE_OPTIONAL), 'format' => new external_format_value('text', VALUE_OPTIONAL), ), 'note' ) ), 'warnings' => new external_warnings('item is always \'note\'', 'When errorcode is savedfailed the note could not be modified.' . 'When errorcode is badparam, an incorrect parameter was provided.' . 'When errorcode is badid, the note does not exist', 'errorcode can be badparam (incorrect parameter), savedfailed (could not be modified), or badid (note does not exist)') ) ); } /** * Returns description of update_notes parameters. * * @return external_function_parameters * @since Moodle 2.5 */ public static function update_notes_parameters() { return new external_function_parameters( array( 'notes' => new external_multiple_structure( new external_single_structure( array( 'id' => new external_value(PARAM_INT, 'id of the note'), 'publishstate' => new external_value(PARAM_ALPHA, '\'personal\', \'course\' or \'site\''), 'text' => new external_value(PARAM_RAW, 'the text of the message - text or HTML'), 'format' => new external_format_value('text', VALUE_DEFAULT), ) ), "Array of Notes", VALUE_DEFAULT, array() ) ) ); } /** * Update notes about users. * * @param array $notes An array of ids for the notes to update. * @return array fail infos. * @since Moodle 2.2 */ public static function update_notes($notes = array()) { global $CFG, $DB; $params = self::validate_parameters(self::update_notes_parameters(), array('notes' => $notes)); // Check if note system is enabled. if (!$CFG->enablenotes) { throw new moodle_exception('notesdisabled', 'notes'); } $warnings = array(); foreach ($params['notes'] as $note) { $notedetails = note_load($note['id']); if (isset($notedetails->id)) { // Ensure the current user is allowed to run this function. $context = context_course::instance($notedetails->courseid); self::validate_context($context); require_capability('moodle/notes:manage', $context); $dbnote = new stdClass; $dbnote->id = $note['id']; $dbnote->content = $note['text']; $dbnote->format = util::validate_format($note['format']); // Get the state ('personal', 'course', 'site'). switch ($note['publishstate']) { case 'personal': $dbnote->publishstate = NOTES_STATE_DRAFT; break; case 'course': $dbnote->publishstate = NOTES_STATE_PUBLIC; break; case 'site': $dbnote->publishstate = NOTES_STATE_SITE; $dbnote->courseid = SITEID; break; default: $warnings[] = array('item' => 'note', 'itemid' => $note["id"], 'warningcode' => 'badparam', 'message' => 'Provided publishstate incorrect'); break; } if (!note_save($dbnote)) { $warnings[] = array('item' => 'note', 'itemid' => $note["id"], 'warningcode' => 'savedfailed', 'message' => 'Note could not be modified'); } } else { $warnings[] = array('item' => 'note', 'itemid' => $note["id"], 'warningcode' => 'badid', 'message' => 'Note does not exist'); } } return $warnings; } /** * Returns description of update_notes result value. * * @return \core_external\external_description * @since Moodle 2.5 */ public static function update_notes_returns() { return new external_warnings('item is always \'note\'', 'When errorcode is savedfailed the note could not be modified.' . 'When errorcode is badparam, an incorrect parameter was provided.' . 'When errorcode is badid, the note does not exist', 'errorcode can be badparam (incorrect parameter), savedfailed (could not be modified), or badid (note does not exist)'); } /** * Returns description of method parameters * * @return external_function_parameters * @since Moodle 2.9 */ public static function get_course_notes_parameters() { return new external_function_parameters( array( 'courseid' => new external_value(PARAM_INT, 'course id, 0 for SITE'), 'userid' => new external_value(PARAM_INT, 'user id', VALUE_DEFAULT, 0), ) ); } /** * Create a notes list * * @param int $courseid ID of the Course * @param stdClass $context context object * @param int $userid ID of the User * @param int $state * @param int $author * @return array of notes * @since Moodle 2.9 */ protected static function create_note_list($courseid, $context, $userid, $state, $author = 0) { $results = []; $notes = note_list($courseid, $userid, $state, $author); foreach ($notes as $key => $note) { $note = (array)$note; [$note['content'], $note['format']] = util::format_text( $note['content'], $note['format'], $context->id, '', '', 0 ); $results[$key] = $note; } return $results; } /** * Get a list of course notes * * @param int $courseid ID of the Course * @param int $userid ID of the User * @return array of site, course and personal notes and warnings * @since Moodle 2.9 * @throws moodle_exception */ public static function get_course_notes($courseid, $userid = 0) { global $CFG, $USER; if (empty($CFG->enablenotes)) { throw new moodle_exception('notesdisabled', 'notes'); } $warnings = array(); $arrayparams = array( 'courseid' => $courseid, 'userid' => $userid, ); $params = self::validate_parameters(self::get_course_notes_parameters(), $arrayparams); if (empty($params['courseid'])) { $params['courseid'] = SITEID; } $user = null; if (!empty($params['userid'])) { $user = core_user::get_user($params['userid'], '*', MUST_EXIST); core_user::require_active_user($user); } $course = get_course($params['courseid']); $systemcontext = context_system::instance(); $canmanagesystemnotes = has_capability('moodle/notes:manage', $systemcontext); if ($course->id == SITEID) { $context = $systemcontext; $canmanagecoursenotes = $canmanagesystemnotes; } else { $context = context_course::instance($course->id); $canmanagecoursenotes = has_capability('moodle/notes:manage', $context); } self::validate_context($context); $sitenotes = array(); $coursenotes = array(); $personalnotes = array(); if ($course->id != SITEID) { require_capability('moodle/notes:view', $context); $sitenotes = self::create_note_list(0, $systemcontext, $params['userid'], NOTES_STATE_SITE); $coursenotes = self::create_note_list($course->id, $context, $params['userid'], NOTES_STATE_PUBLIC); $personalnotes = self::create_note_list($course->id, $context, $params['userid'], NOTES_STATE_DRAFT, $USER->id); } else { if (has_capability('moodle/notes:view', $context)) { $sitenotes = self::create_note_list(0, $context, $params['userid'], NOTES_STATE_SITE); } // It returns notes only for a specific user! if (!empty($user)) { $usercourses = enrol_get_users_courses($user->id, true); foreach ($usercourses as $c) { // All notes at course level, only if we have capability on every course. if (has_capability('moodle/notes:view', context_course::instance($c->id))) { $coursenotes += self::create_note_list($c->id, $context, $params['userid'], NOTES_STATE_PUBLIC); } } } } $results = array( 'sitenotes' => $sitenotes, 'coursenotes' => $coursenotes, 'personalnotes' => $personalnotes, 'canmanagesystemnotes' => $canmanagesystemnotes, 'canmanagecoursenotes' => $canmanagecoursenotes, 'warnings' => $warnings ); return $results; } /** * Returns array of note structure * * @return \core_external\external_description * @since Moodle 2.9 */ protected static function get_note_structure() { return array( 'id' => new external_value(PARAM_INT, 'id of this note'), 'courseid' => new external_value(PARAM_INT, 'id of the course'), 'userid' => new external_value(PARAM_INT, 'user id'), 'content' => new external_value(PARAM_RAW, 'the content text formated'), 'format' => new external_format_value('content'), 'created' => new external_value(PARAM_INT, 'time created (timestamp)'), 'lastmodified' => new external_value(PARAM_INT, 'time of last modification (timestamp)'), 'usermodified' => new external_value(PARAM_INT, 'user id of the creator of this note'), 'publishstate' => new external_value(PARAM_ALPHA, "state of the note (i.e. draft, public, site) ") ); } /** * Returns description of method result value * * @return \core_external\external_description * @since Moodle 2.9 */ public static function get_course_notes_returns() { return new external_single_structure( array( 'sitenotes' => new external_multiple_structure( new external_single_structure(self::get_note_structure() , ''), 'site notes', VALUE_OPTIONAL ), 'coursenotes' => new external_multiple_structure( new external_single_structure(self::get_note_structure() , ''), 'couse notes', VALUE_OPTIONAL ), 'personalnotes' => new external_multiple_structure( new external_single_structure(self::get_note_structure() , ''), 'personal notes', VALUE_OPTIONAL ), 'canmanagesystemnotes' => new external_value(PARAM_BOOL, 'Whether the user can manage notes at system level.', VALUE_OPTIONAL), 'canmanagecoursenotes' => new external_value(PARAM_BOOL, 'Whether the user can manage notes at the given course.', VALUE_OPTIONAL), 'warnings' => new external_warnings() ), 'notes' ); } /** * Returns description of method parameters * * @return external_function_parameters * @since Moodle 2.9 */ public static function view_notes_parameters() { return new external_function_parameters( array( 'courseid' => new external_value(PARAM_INT, 'course id, 0 for notes at system level'), 'userid' => new external_value(PARAM_INT, 'user id, 0 means view all the user notes', VALUE_DEFAULT, 0) ) ); } /** * Simulates the web interface view of notes/index.php: trigger events * * @param int $courseid id of the course * @param int $userid id of the user * @return array of warnings and status result * @since Moodle 2.9 * @throws moodle_exception */ public static function view_notes($courseid, $userid = 0) { global $CFG; require_once($CFG->dirroot . "/notes/lib.php"); if (empty($CFG->enablenotes)) { throw new moodle_exception('notesdisabled', 'notes'); } $warnings = array(); $arrayparams = array( 'courseid' => $courseid, 'userid' => $userid ); $params = self::validate_parameters(self::view_notes_parameters(), $arrayparams); if (empty($params['courseid'])) { $params['courseid'] = SITEID; } $course = get_course($params['courseid']); if ($course->id == SITEID) { $context = context_system::instance(); } else { $context = context_course::instance($course->id); } // First of all, validate the context before do further permission checks. self::validate_context($context); require_capability('moodle/notes:view', $context); if (!empty($params['userid'])) { $user = core_user::get_user($params['userid'], '*', MUST_EXIST); core_user::require_active_user($user); if ($course->id != SITEID and !can_access_course($course, $user, '', true)) { throw new moodle_exception('notenrolledprofile'); } } note_view($context, $params['userid']); $result = array(); $result['status'] = true; $result['warnings'] = $warnings; return $result; } /** * Returns description of method result value * * @return \core_external\external_description * @since Moodle 2.9 */ public static function view_notes_returns() { return new external_single_structure( array( 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 'warnings' => new external_warnings() ) ); } } edit.php 0000604 00000007374 15062070721 0006211 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. require_once('../config.php'); require_once('lib.php'); require_once('edit_form.php'); require_once($CFG->dirroot . '/course/lib.php'); $noteid = optional_param('id', 0, PARAM_INT); $url = new moodle_url('/notes/edit.php'); if ($noteid) { // Existing note. $url->param('id', $noteid); if (!$note = note_load($noteid)) { throw new \moodle_exception('invalidid', 'notes'); } } else { // Adding new note. $courseid = required_param('courseid', PARAM_INT); $userid = required_param('userid', PARAM_INT); $state = optional_param('publishstate', NOTES_STATE_PUBLIC, PARAM_ALPHA); $note = new stdClass(); $note->courseid = $courseid; $note->userid = $userid; $note->publishstate = $state; $url->param('courseid', $courseid); $url->param('userid', $userid); if ($state !== NOTES_STATE_PUBLIC) { $url->param('publishstate', $state); } } $PAGE->set_url($url); if (!$course = $DB->get_record('course', array('id' => $note->courseid))) { throw new \moodle_exception('invalidcourseid'); } require_login($course); if (empty($CFG->enablenotes)) { throw new \moodle_exception('notesdisabled', 'notes'); } $context = context_course::instance($course->id); require_capability('moodle/notes:manage', $context); if (!$user = $DB->get_record('user', array('id' => $note->userid))) { throw new \moodle_exception('invaliduserid'); } $noteform = new note_edit_form(); $noteform->set_data($note); // If form was cancelled then return to the notes list of the note. if ($noteform->is_cancelled()) { redirect($CFG->wwwroot . '/notes/index.php?course=' . $note->courseid . '&user=' . $note->userid); } // If data was submitted and validated, then save it to database. if ($note = $noteform->get_data()) { if ($noteid) { // A noteid has been used, we don't allow editing of course or user so // lets unset them to be sure we never change that by accident. unset($note->courseid); unset($note->userid); } note_save($note); // Redirect to notes list that contains this note. redirect($CFG->wwwroot . '/notes/index.php?course=' . $note->courseid . '&user=' . $note->userid); } if ($noteid) { $strnotes = get_string('editnote', 'notes'); } else { $strnotes = get_string('addnewnote', 'notes'); } // Output HTML. $link = null; if (course_can_view_participants($context) || course_can_view_participants(context_system::instance())) { $link = new moodle_url('/user/index.php', array('id' => $course->id)); } $PAGE->navbar->add(get_string('participants'), $link); $PAGE->navbar->add(fullname($user), new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id))); $PAGE->navbar->add(get_string('notes', 'notes'), new moodle_url('/notes/index.php', array('user' => $user->id, 'course' => $course->id))); $PAGE->navbar->add($strnotes); $PAGE->set_title($course->shortname . ': ' . $strnotes); $PAGE->set_heading($course->fullname); echo $OUTPUT->header(); echo $OUTPUT->heading(fullname($user)); $noteform->display(); echo $OUTPUT->footer(); tests/lib_test.php 0000604 00000007234 15062070721 0010226 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Tests for notes library functions. * * @package core_notes * @copyright 2015 onwards Ankit agarwal <ankit.agrr@gmail.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ namespace core_notes; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/notes/lib.php'); /** * Class core_notes_lib_testcase * * @package core_notes * @copyright 2015 onwards Ankit agarwal <ankit.agrr@gmail.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ class lib_test extends \advanced_testcase { /** * @var stdClass The user. */ private $user; /** * @var stdClass The course. */ private $course; /** * @var \core_user\output\myprofile\tree The navigation tree. */ private $tree; public function setUp(): void { $this->user = $this->getDataGenerator()->create_user(); $this->course = $this->getDataGenerator()->create_course(); $this->tree = new \core_user\output\myprofile\tree(); $this->resetAfterTest(); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation() { global $USER; // Set up the test. $this->setAdminUser(); $iscurrentuser = true; // Enable notes. set_config('enablenotes', true); // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $nodes->setAccessible(true); $this->assertArrayHasKey('notes', $nodes->getValue($this->tree)); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation_as_guest() { global $USER; $this->setGuestUser(); $iscurrentuser = false; // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $nodes->setAccessible(true); $this->assertArrayNotHasKey('notes', $nodes->getValue($this->tree)); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation_notes_disabled() { global $USER; $this->setAdminUser(); $iscurrentuser = false; // Disable notes. set_config('enablenotes', false); // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $nodes->setAccessible(true); $this->assertArrayNotHasKey('notes', $nodes->getValue($this->tree)); } } tests/event/events_test.php 0000604 00000013321 15062070721 0012077 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Tests for notes events. * * @package core_notes * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ namespace core_notes\event; /** * Class core_notes_events_testcase * * Class for tests related to notes events. * * @package core_notes * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ class events_test extends \advanced_testcase { /** @var stdClass A note object. */ private $eventnote; /** @var stdClass A complete record from post table */ private $noterecord; public function setUp(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $user = $this->getDataGenerator()->create_user(); $gen = $this->getDataGenerator()->get_plugin_generator('core_notes'); $this->eventnote = $gen->create_instance(array('courseid' => $course->id, 'userid' => $user->id)); // Get the full record, note_load doesn't return everything. $this->noterecord = $DB->get_record('post', array('id' => $this->eventnote->id), '*', MUST_EXIST); } /** * Tests for event note_deleted. */ public function test_note_deleted_event() { // Delete a note. $sink = $this->redirectEvents(); note_delete($this->eventnote); $events = $sink->get_events(); $event = array_pop($events); // Delete note event. $sink->close(); // Validate event data. $this->assertInstanceOf('\core\event\note_deleted', $event); $this->assertEquals($this->eventnote->id, $event->objectid); $this->assertEquals($this->eventnote->usermodified, $event->userid); $this->assertEquals($this->eventnote->userid, $event->relateduserid); $this->assertEquals('post', $event->objecttable); $this->assertEquals(null, $event->get_url()); $this->assertEquals($this->noterecord, $event->get_record_snapshot('post', $event->objectid)); $this->assertEquals(NOTES_STATE_SITE, $event->other['publishstate']); // Test legacy data. $logurl = new \moodle_url('index.php', array('course' => $this->eventnote->courseid, 'user' => $this->eventnote->userid)); $logurl->set_anchor('note-' . $this->eventnote->id); $this->assertEventContextNotUsed($event); } /** * Tests for event note_created. */ public function test_note_created_event() { // Delete a note. $sink = $this->redirectEvents(); $note = clone $this->eventnote; unset($note->id); note_save($note); $events = $sink->get_events(); $event = array_pop($events); // Delete note event. $sink->close(); // Validate event data. $this->assertInstanceOf('\core\event\note_created', $event); $this->assertEquals($note->id, $event->objectid); $this->assertEquals($note->usermodified, $event->userid); $this->assertEquals($note->userid, $event->relateduserid); $this->assertEquals('post', $event->objecttable); $this->assertEquals(NOTES_STATE_SITE, $event->other['publishstate']); $this->assertEventContextNotUsed($event); } /** * Tests for event note_updated. */ public function test_note_updated_event() { // Delete a note. $sink = $this->redirectEvents(); $note = clone $this->eventnote; $note->publishstate = NOTES_STATE_DRAFT; note_save($note); $events = $sink->get_events(); $event = array_pop($events); // Delete note event. $sink->close(); // Validate event data. $this->assertInstanceOf('\core\event\note_updated', $event); $this->assertEquals($note->id, $event->objectid); $this->assertEquals($note->usermodified, $event->userid); $this->assertEquals($note->userid, $event->relateduserid); $this->assertEquals('post', $event->objecttable); $this->assertEquals(NOTES_STATE_DRAFT, $event->other['publishstate']); $this->assertEventContextNotUsed($event); } /** * Test the notes viewed event. * * It's not possible to use the moodle API to simulate the viewing of notes, so here we * simply create the event and trigger it. */ public function test_notes_viewed() { $coursecontext = \context_course::instance($this->eventnote->courseid); // Trigger event for notes viewed. $event = \core\event\notes_viewed::create(array( 'context' => $coursecontext, 'relateduserid' => $this->eventnote->userid )); // Trigger and capture the event. $sink = $this->redirectEvents(); $event->trigger(); $events = $sink->get_events(); $event = reset($events); $this->assertInstanceOf('\core\event\notes_viewed', $event); $this->assertEquals($coursecontext, $event->get_context()); $this->assertEventContextNotUsed($event); } } tests/externallib_test.php 0000604 00000053242 15062070721 0011771 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * External notes functions unit tests * * @package core_notes * @category external * @copyright 2012 Jerome Mouneyrac * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_notes; use core_external\external_api; use core_notes_external; use externallib_advanced_testcase; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/webservice/tests/helpers.php'); require_once($CFG->dirroot . '/notes/externallib.php'); class externallib_test extends externallib_advanced_testcase { /** * Test create_notes */ public function test_create_notes() { global $DB, $USER; $this->resetAfterTest(true); $course = self::getDataGenerator()->create_course(); // Set the required capabilities by the external function. $contextid = \context_course::instance($course->id)->id; $roleid = $this->assignUserCapability('moodle/notes:manage', $contextid); $this->assignUserCapability('moodle/course:view', $contextid, $roleid); // Create test note data. $note1 = array(); $note1['userid'] = $USER->id; $note1['publishstate'] = 'personal'; $note1['courseid'] = $course->id; $note1['text'] = 'the text'; $note1['clientnoteid'] = 4; $notes = array($note1); $creatednotes = core_notes_external::create_notes($notes); // We need to execute the return values cleaning process to simulate the web service server. $creatednotes = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes); $thenote = $DB->get_record('post', array('id' => $creatednotes[0]['noteid'])); // Confirm that base note data was inserted correctly. $this->assertEquals($thenote->userid, $note1['userid']); $this->assertEquals($thenote->courseid, $note1['courseid']); $this->assertEquals($thenote->publishstate, NOTES_STATE_DRAFT); $this->assertEquals($thenote->content, $note1['text']); $this->assertEquals($creatednotes[0]['clientnoteid'], $note1['clientnoteid']); // Call without required capability. $this->unassignUserCapability('moodle/notes:manage', $contextid, $roleid); $this->expectException('\required_capability_exception'); $creatednotes = core_notes_external::create_notes($notes); } public function test_delete_notes() { global $DB, $USER; $this->resetAfterTest(true); $course = self::getDataGenerator()->create_course(); // Set the required capabilities by the external function. $contextid = \context_course::instance($course->id)->id; $roleid = $this->assignUserCapability('moodle/notes:manage', $contextid); $this->assignUserCapability('moodle/course:view', $contextid, $roleid); // Create test note data. $cnote = array(); $cnote['userid'] = $USER->id; $cnote['publishstate'] = 'personal'; $cnote['courseid'] = $course->id; $cnote['text'] = 'the text'; $cnote['clientnoteid'] = 4; $cnotes = array($cnote); $creatednotes = core_notes_external::create_notes($cnotes); $creatednotes = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes); $dnotes1 = array($creatednotes[0]['noteid']); $deletednotes1 = core_notes_external::delete_notes($dnotes1); $deletednotes1 = external_api::clean_returnvalue(core_notes_external::delete_notes_returns(), $deletednotes1); // Confirm that base note data was deleted correctly. $notdeletedcount = $DB->count_records_select('post', 'id = ' . $creatednotes[0]['noteid']); $this->assertEquals(0, $notdeletedcount); $dnotes2 = array(33); // This note does not exist. $deletednotes2 = core_notes_external::delete_notes($dnotes2); $deletednotes2 = external_api::clean_returnvalue(core_notes_external::delete_notes_returns(), $deletednotes2); $this->assertEquals("note", $deletednotes2[0]["item"]); $this->assertEquals(33, $deletednotes2[0]["itemid"]); $this->assertEquals("badid", $deletednotes2[0]["warningcode"]); $this->assertEquals("Note does not exist", $deletednotes2[0]["message"]); // Call without required capability. $creatednotes = core_notes_external::create_notes($cnotes); $creatednotes = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes); $dnotes3 = array($creatednotes[0]['noteid']); $this->unassignUserCapability('moodle/notes:manage', $contextid, $roleid); $this->expectException('\required_capability_exception'); $deletednotes = core_notes_external::delete_notes($dnotes3); $deletednotes = external_api::clean_returnvalue(core_notes_external::delete_notes_returns(), $deletednotes); } public function test_get_notes() { global $DB, $USER; $this->resetAfterTest(true); $course = self::getDataGenerator()->create_course(); // Set the required capabilities by the external function. $contextid = \context_course::instance($course->id)->id; $roleid = $this->assignUserCapability('moodle/notes:manage', $contextid); $this->assignUserCapability('moodle/notes:view', $contextid, $roleid); $this->assignUserCapability('moodle/course:view', $contextid, $roleid); // Create test note data. $cnote = array(); $cnote['userid'] = $USER->id; $cnote['publishstate'] = 'personal'; $cnote['courseid'] = $course->id; $cnote['text'] = 'the text'; $cnotes = array($cnote); $creatednotes1 = core_notes_external::create_notes($cnotes); $creatednotes2 = core_notes_external::create_notes($cnotes); $creatednotes3 = core_notes_external::create_notes($cnotes); $creatednotes1 = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes1); $creatednotes2 = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes2); $creatednotes3 = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes3); // Note 33 does not exist. $gnotes = array($creatednotes1[0]['noteid'], $creatednotes2[0]['noteid'], $creatednotes3[0]['noteid'], 33); $getnotes = core_notes_external::get_notes($gnotes); $getnotes = external_api::clean_returnvalue(core_notes_external::get_notes_returns(), $getnotes); $this->unassignUserCapability('moodle/notes:manage', $contextid, $roleid); // Confirm that base note data was retrieved correctly. $this->assertEquals($cnote['userid'], $getnotes["notes"][0]["userid"]); $this->assertEquals($cnote['text'], $getnotes["notes"][0]["text"]); $this->assertEquals($cnote['userid'], $getnotes["notes"][1]["userid"]); $this->assertEquals($cnote['text'], $getnotes["notes"][1]["text"]); $this->assertEquals($cnote['userid'], $getnotes["notes"][2]["userid"]); $this->assertEquals($cnote['text'], $getnotes["notes"][2]["text"]); $this->assertEquals("note", $getnotes["warnings"][0]["item"]); $this->assertEquals(33, $getnotes["warnings"][0]["itemid"]); $this->assertEquals("badid", $getnotes["warnings"][0]["warningcode"]); $this->assertEquals("Note does not exist", $getnotes["warnings"][0]["message"]); // Call without required capability. $this->unassignUserCapability('moodle/notes:view', $contextid, $roleid); $this->expectException('\required_capability_exception'); $creatednotes = core_notes_external::get_notes($gnotes); } public function test_update_notes() { global $DB, $USER; $this->resetAfterTest(true); $course = self::getDataGenerator()->create_course(); // Set the required capabilities by the external function. $contextid = \context_course::instance($course->id)->id; $roleid = $this->assignUserCapability('moodle/notes:manage', $contextid); $this->assignUserCapability('moodle/course:view', $contextid, $roleid); // Create test note data. $note1 = array(); $note1['userid'] = $USER->id; $note1['publishstate'] = 'personal'; $note1['courseid'] = $course->id; $note1['text'] = 'the text'; $note2['userid'] = $USER->id; $note2['publishstate'] = 'course'; $note2['courseid'] = $course->id; $note2['text'] = 'the text'; $note3['userid'] = $USER->id; $note3['publishstate'] = 'site'; $note3['courseid'] = $course->id; $note3['text'] = 'the text'; $notes1 = array($note1, $note2, $note3); $creatednotes = core_notes_external::create_notes($notes1); $creatednotes = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes); $note2 = array(); $note2["id"] = $creatednotes[0]['noteid']; $note2['publishstate'] = 'personal'; $note2['text'] = 'the new text'; $note2['format'] = FORMAT_HTML; $notes2 = array($note2); $updatednotes = core_notes_external::update_notes($notes2); $updatednotes = external_api::clean_returnvalue(core_notes_external::update_notes_returns(), $updatednotes); $thenote = $DB->get_record('post', array('id' => $creatednotes[0]['noteid'])); // Confirm that base note data was updated correctly. $this->assertEquals($thenote->publishstate, NOTES_STATE_DRAFT); $this->assertEquals($note2['text'], $thenote->content); // Call without required capability. $creatednotes = core_notes_external::create_notes($notes1); $creatednotes = external_api::clean_returnvalue(core_notes_external::create_notes_returns(), $creatednotes); $this->unassignUserCapability('moodle/notes:manage', $contextid, $roleid); $this->expectException('\required_capability_exception'); $note2 = array(); $note2["id"] = $creatednotes[0]['noteid']; $note2['publishstate'] = 'personal'; $note2['text'] = 'the new text'; $note2['format'] = FORMAT_HTML; $notes2 = array($note2); $updatednotes = core_notes_external::update_notes($notes2); $updatednotes = external_api::clean_returnvalue(core_notes_external::update_notes_returns(), $updatednotes); } /** * Test get_course_notes */ public function test_get_course_notes() { global $DB, $CFG; $this->resetAfterTest(true); $CFG->enablenotes = true; // Take role definitions. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); // Create students and teachers. $student1 = $this->getDataGenerator()->create_user(); $student2 = $this->getDataGenerator()->create_user(); $teacher1 = $this->getDataGenerator()->create_user(); $teacher2 = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); // Enroll students and teachers to COURSE-1. $this->getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student2->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, $teacherrole->id); $this->getDataGenerator()->enrol_user($teacher2->id, $course1->id, $teacherrole->id); // Enroll students and teachers to COURSE-2 (teacher1 is not enrolled in Course 2). $this->getDataGenerator()->enrol_user($student1->id, $course2->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student2->id, $course2->id, $studentrole->id); $this->getDataGenerator()->enrol_user($teacher2->id, $course2->id, $teacherrole->id); // Generate notes. $gen = $this->getDataGenerator()->get_plugin_generator('core_notes'); $this->setUser($teacher1); // NoteA1: on student1 (Course1) by Teacher1. $params = array('courseid' => $course1->id, 'userid' => $student1->id, 'publishstate' => NOTES_STATE_PUBLIC, 'usermodified' => $teacher1->id); $notea1 = $gen->create_instance($params); // NoteA2: on student1 (Course1) by Teacher1. $params = array('courseid' => $course1->id, 'userid' => $student1->id, 'publishstate' => NOTES_STATE_PUBLIC, 'usermodified' => $teacher1->id); $notea2 = $gen->create_instance($params); // NoteS1: on student1 SITE-LEVEL by teacher1. $params = array('courseid' => $course1->id, 'userid' => $student1->id, 'publishstate' => NOTES_STATE_SITE, 'usermodified' => $teacher1->id); $notes1 = $gen->create_instance($params); // NoteP1: on student1 PERSONAL by teacher1. $params = array('courseid' => $course1->id, 'userid' => $student1->id, 'publishstate' => NOTES_STATE_DRAFT, 'usermodified' => $teacher1->id); $notep1 = $gen->create_instance($params); // NoteB1: on student1 (Course2) by teacher1. $params = array('courseid' => $course2->id, 'userid' => $student1->id, 'publishstate' => NOTES_STATE_PUBLIC, 'usermodified' => $teacher1->id); $noteb1 = $gen->create_instance($params); // Retrieve notes, normal case. $result = core_notes_external::get_course_notes($course1->id, $student1->id); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEquals($notes1->id, $result['sitenotes'][0]['id']); $this->assertCount(2, $result['coursenotes']); // Teacher can manage only the course notes. $this->assertFalse($result['canmanagesystemnotes']); $this->assertTrue($result['canmanagecoursenotes']); foreach ($result['coursenotes'] as $coursenote) { if ($coursenote['id'] != $notea1->id and $coursenote['id'] != $notea2->id) { $this->fail('the returned notes ids does not match with the created ones'); } } $this->assertEquals($notep1->id, $result['personalnotes'][0]['id']); // Try to get notes from a course the user is not enrolled. try { $result = core_notes_external::get_course_notes($course2->id, $student1->id); $this->fail('the user is not enrolled in the course'); } catch (\require_login_exception $e) { $this->assertEquals('requireloginerror', $e->errorcode); } $result = core_notes_external::get_course_notes(0, $student1->id); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEmpty($result['sitenotes']); // Teacher can't manage system notes. $this->assertFalse($result['canmanagesystemnotes']); $this->assertFalse($result['canmanagecoursenotes']); foreach ($result['coursenotes'] as $coursenote) { if ($coursenote['id'] != $notea1->id and $coursenote['id'] != $notea2->id) { $this->fail('the returned notes ids does not match with the created ones'); } } $this->assertCount(2, $result['coursenotes']); $this->setAdminUser(); $result = core_notes_external::get_course_notes(0, $student1->id); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEquals($notes1->id, $result['sitenotes'][0]['id']); $this->assertCount(1, $result['sitenotes']); // Admin user can manage both system and course notes. $this->assertTrue($result['canmanagesystemnotes']); $this->assertTrue($result['canmanagecoursenotes']); $this->setUser($teacher1); $result = core_notes_external::get_course_notes(0, 0); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEmpty($result['sitenotes']); $this->assertEmpty($result['coursenotes']); $this->assertEmpty($result['personalnotes']); // Teacher can't manage system notes. $this->assertFalse($result['canmanagesystemnotes']); $this->assertFalse($result['canmanagecoursenotes']); $this->setUser($teacher2); $result = core_notes_external::get_course_notes($course1->id, $student1->id); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEquals($notes1->id, $result['sitenotes'][0]['id']); foreach ($result['coursenotes'] as $coursenote) { if ($coursenote['id'] != $notea1->id and $coursenote['id'] != $notea2->id) { $this->fail('the returned notes ids does not match with the created ones'); } } $this->assertCount(1, $result['sitenotes']); $this->assertCount(2, $result['coursenotes']); // Teacher can manage only the course notes. $this->assertFalse($result['canmanagesystemnotes']); $this->assertTrue($result['canmanagecoursenotes']); $result = core_notes_external::get_course_notes($course1->id, 0); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEquals($notes1->id, $result['sitenotes'][0]['id']); foreach ($result['coursenotes'] as $coursenote) { if ($coursenote['id'] != $notea1->id and $coursenote['id'] != $notea2->id) { $this->fail('the returned notes ids does not match with the created ones'); } } $this->assertCount(1, $result['sitenotes']); $this->assertCount(2, $result['coursenotes']); $this->setUser($teacher1); $result = core_notes_external::get_course_notes($course1->id, 0); $result = external_api::clean_returnvalue(core_notes_external::get_course_notes_returns(), $result); $this->assertEquals($notep1->id, $result['personalnotes'][0]['id']); $this->assertCount(1, $result['personalnotes']); // Teacher can manage only the course notes. $this->assertFalse($result['canmanagesystemnotes']); $this->assertTrue($result['canmanagecoursenotes']); } /** * Test view_notes */ public function test_view_notes() { global $DB, $CFG; $this->resetAfterTest(true); $CFG->enablenotes = true; // Take role definitions. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); // Create students and teachers. $student = $this->getDataGenerator()->create_user(); $teacher = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); // Enroll students and teachers to course. $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); // Generate notes. $gen = $this->getDataGenerator()->get_plugin_generator('core_notes'); $this->setUser($teacher); // NoteA1: on student (Course) by Teacher. $params = array('courseid' => $course->id, 'userid' => $student->id, 'publishstate' => NOTES_STATE_PUBLIC, 'usermodified' => $teacher->id); $notea1 = $gen->create_instance($params); $sink = $this->redirectEvents(); $result = core_notes_external::view_notes($course->id, $student->id); $result = external_api::clean_returnvalue(core_notes_external::view_notes_returns(), $result); $result = core_notes_external::view_notes($course->id); $result = external_api::clean_returnvalue(core_notes_external::view_notes_returns(), $result); $events = $sink->get_events(); $this->assertCount(2, $events); $this->assertInstanceOf('\core\event\notes_viewed', $events[0]); $this->assertEquals($coursecontext, $events[0]->get_context()); $this->assertEquals($student->id, $events[0]->relateduserid); $this->assertInstanceOf('\core\event\notes_viewed', $events[1]); $this->assertEquals($coursecontext, $events[1]->get_context()); $this->assertEquals(0, $events[1]->relateduserid); try { core_notes_external::view_notes(0); $this->fail('Exception expected due to invalid permissions at system level.'); } catch (\moodle_exception $e) { $this->assertEquals('nopermissions', $e->errorcode); } try { core_notes_external::view_notes($course->id, $student->id + 100); $this->fail('Exception expected due to invalid user id.'); } catch (\moodle_exception $e) { $this->assertEquals('invaliduser', $e->errorcode); } } } tests/privacy/provider_test.php 0000604 00000064106 15062070721 0012770 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Unit tests for the core_notes implementation of the privacy API. * * @package core_notes * @category test * @copyright 2018 Zig Tan <zig@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_notes\privacy; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . "/notes/lib.php"); use core_notes\privacy\provider; use core_privacy\local\request\writer; use core_privacy\local\request\approved_contextlist; use core_privacy\local\request\approved_userlist; /** * Unit tests for the core_notes implementation of the privacy API. * * @copyright 2018 Zig Tan <zig@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider_test extends \core_privacy\tests\provider_testcase { /** * Test for provider::get_contexts_for_userid(). */ public function test_get_contexts_for_userid() { global $DB; // Test setup. $this->resetAfterTest(true); $this->setAdminUser(); set_config('enablenotes', true); $teacher1 = $this->getDataGenerator()->create_user(); $this->setUser($teacher1); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); // Create Courses, then enrol a teacher and a student. $nocourses = 5; $courses = []; $coursecontextids = []; for ($c = 1; $c <= $nocourses; $c++) { $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); role_assign($teacherrole->id, $teacher1->id, $coursecontext->id); role_assign($studentrole->id, $student->id, $coursecontext->id); // Only create private user notes (i.e. NOTES_STATE_DRAFT) for student in Course 1, 2, 3 written by the teacher. if ($c <= 3) { $this->help_create_user_note( $student->id, NOTES_STATE_DRAFT, $course->id, "Test private user note about the student in Course $c by the teacher" ); } $courses[$c] = $course; $coursecontextids[] = $coursecontext->id; } // Test Teacher 1's contexts equals 3 because only 3 user notes were added for Course 1, 2, and 3. // Course 4 and 5 does not have any notes associated with it, so the contexts should not be returned. $contexts = provider::get_contexts_for_userid($teacher1->id); $this->assertCount(3, $contexts->get_contextids()); // Test the Student's contexts is 0 because the notes written by the teacher are private. $contexts = provider::get_contexts_for_userid($student->id); $this->assertCount(0, $contexts->get_contextids()); // Add a public user note (i.e. NOTES_STATE_PUBLIC) written by the Teacher about the Student in Course 4. $course = $courses[4]; $this->help_create_user_note( $student->id, NOTES_STATE_PUBLIC, $course->id, "Test public user note about the student in Course 4 by the teacher" ); // Test Teacher 1's contexts equals 4 after adding a public note about a student in Course 4. $contexts = provider::get_contexts_for_userid($teacher1->id); $this->assertCount(4, $contexts->get_contextids()); // Test the Student's contexts is 1 for Course 4 because there is a public note written by the teacher. $contexts = provider::get_contexts_for_userid($student->id); $this->assertCount(1, $contexts->get_contextids()); // Add a site-wide user note (i.e. NOTES_STATE_SITE) written by the Teacher 1 about the Student in Course 3. $course = $courses[3]; $this->help_create_user_note( $student->id, NOTES_STATE_SITE, $course->id, "Test site-wide user note about the student in Course 3 by the teacher" ); // Test the Student's contexts is 2 for Courses 3, 4 because there is a public and site-wide note written by the Teacher. $contexts = provider::get_contexts_for_userid($student->id); $this->assertCount(2, $contexts->get_contextids()); // Add a site-wide user note for the Teacher 1 by another Teacher 2 in Course 5. $teacher2 = $this->getDataGenerator()->create_user(); $this->setUser($teacher2); $course = $courses[5]; $this->help_create_user_note( $teacher1->id, NOTES_STATE_SITE, $course->id, "Test site-wide user note about the teacher in Course 5 by another teacher" ); // Test Teacher 1's contexts equals 5 after adding the note from another teacher. $contextlist = provider::get_contexts_for_userid($teacher1->id); $this->assertCount(5, $contextlist->get_contextids()); // Test Teacher 1's contexts match the contexts of the Courses associated with notes created. $this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids())); } /** * Test for provider::export_user_data(). */ public function test_export_user_data() { global $DB; // Test setup. $this->resetAfterTest(true); $this->setAdminUser(); set_config('enablenotes', true); $teacher1 = $this->getDataGenerator()->create_user(); $this->setUser($teacher1); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $nocourses = 5; $nostudents = 2; $studentrole = $DB->get_record('role', array('shortname' => 'student')); $courses = []; $coursecontextids = []; for ($c = 1; $c <= $nocourses; $c++) { // Create a Course, then enrol a teacher and enrol 2 students. $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); role_assign($teacherrole->id, $teacher1->id, $coursecontext->id); // Only create public user notes (i.e. NOTES_STATE_PUBLIC) for students in Course 1, 2, 3 written by the teacher. if ($c <= 3) { for ($s = 0; $s < $nostudents; $s++) { $student = $this->getDataGenerator()->create_user(); role_assign($studentrole->id, $student->id, $coursecontext->id); // Create test public user note data written for students by the teacher. $this->help_create_user_note( $student->id, NOTES_STATE_PUBLIC, $course->id, "Test public user note for student $s in Course $c by the teacher" ); } // Store the Course context for those which have test notes added for verification. $coursecontextids[] = $coursecontext->id; } $courses[$c] = $course; } // Add a site-wide user note for Teacher 1 by another Teacher 2 in Course 4. $teacher2 = $this->getDataGenerator()->create_user(); $this->setUser($teacher2); $course = $courses[4]; $this->help_create_user_note( $teacher1->id, NOTES_STATE_SITE, $course->id, "Test site-wide user note about the teacher in Course 4 by another teacher" ); // Store the Course context for those which have test notes added for verification. $coursecontextids[] = \context_course::instance($course->id)->id; // Add a private user note for Teacher 1 by another Teacher 2 in Course 5. $course = $courses[5]; $this->help_create_user_note( $teacher1->id, NOTES_STATE_DRAFT, $course->id, "Test private user note about the teacher in Course 5 by another teacher" ); // Test the number of contexts returned matches the Course contexts created with notes. $contextlist = provider::get_contexts_for_userid($teacher1->id); $this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids())); $approvedcontextlist = new approved_contextlist($teacher1, 'core_notes', $contextlist->get_contextids()); // Retrieve User notes created by the teacher. provider::export_user_data($approvedcontextlist); // Test the core_notes data is exported at the Course context level and has content. foreach ($contextlist as $context) { $this->assertEquals(CONTEXT_COURSE, $context->contextlevel); /** @var \core_privacy\tests\request\content_writer $writer */ $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); } } /** * Test for provider::delete_data_for_all_users_in_context(). */ public function test_delete_data_for_all_users_in_context() { global $DB; // Test setup. $this->resetAfterTest(true); $this->setAdminUser(); set_config('enablenotes', true); $teacher = $this->getDataGenerator()->create_user(); $this->setUser($teacher); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $nocourses = 2; $nostudents = 5; $nonotes = 7; $studentrole = $DB->get_record('role', array('shortname' => 'student')); $n = 0; for ($c = 0; $c < $nocourses; $c++) { // Create a Course, then enrol a teacher and enrol 2 students. $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); role_assign($teacherrole->id, $teacher->id, $coursecontext->id); for ($s = 0; $s < $nostudents; $s++) { if ($n < $nonotes) { $student = $this->getDataGenerator()->create_user(); role_assign($studentrole->id, $student->id, $coursecontext->id); // Create test note data. $this->help_create_user_note( $student->id, NOTES_STATE_PUBLIC, $course->id, "Test user note for student $s in Course $c" ); } $n++; } } // Test the number of contexts returned equals the number of Courses created with user notes for its students. $contextlist = provider::get_contexts_for_userid($teacher->id); $this->assertCount($nocourses, $contextlist->get_contextids()); // Test the created user note records in mdl_post table matches the test number of user notes specified. $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); $this->assertCount($nonotes, $notes); // Delete all user note records in mdl_post table by the specified Course context. foreach ($contextlist->get_contexts() as $context) { provider::delete_data_for_all_users_in_context($context); } // Test the core_note records in mdl_post table is equals zero. $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); $this->assertCount(0, $notes); } /** * Test for provider::delete_data_for_user(). */ public function test_delete_data_for_user() { global $DB; // Test setup. $this->resetAfterTest(true); $this->setAdminUser(); set_config('enablenotes', true); $teacher = $this->getDataGenerator()->create_user(); $this->setUser($teacher); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $nocourses = 2; $nostudents = 5; $nonotes = 7; $studentrole = $DB->get_record('role', array('shortname' => 'student')); $n = 0; for ($c = 0; $c < $nocourses; $c++) { // Create a Course, then enrol a teacher and enrol 2 students. $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); role_assign($teacherrole->id, $teacher->id, $coursecontext->id); for ($s = 0; $s < $nostudents; $s++) { if ($n < $nonotes) { $student = $this->getDataGenerator()->create_user(); role_assign($studentrole->id, $student->id, $coursecontext->id); // Create test note data. $this->help_create_user_note( $student->id, NOTES_STATE_PUBLIC, $course->id, "Test user note for student $s in Course $c" ); } $n++; } } // Test the number of contexts returned equals the number of Courses created with user notes for its students. $contextlist = provider::get_contexts_for_userid($teacher->id); $this->assertCount($nocourses, $contextlist->get_contextids()); // Test the created user note records in mdl_post table matches the test number of user notes specified. $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); $this->assertCount($nonotes, $notes); // Delete all user note records in mdl_post table created by the specified teacher. $approvedcontextlist = new approved_contextlist($teacher, 'core_notes', $contextlist->get_contextids()); provider::delete_data_for_user($approvedcontextlist); // Test the core_note records in mdl_post table is equals zero. $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); $this->assertCount(0, $notes); } /** * Test that only users within a course context are fetched. */ public function test_get_users_in_context() { global $DB; $this->resetAfterTest(true); $component = 'core_notes'; // Test setup. $this->setAdminUser(); set_config('enablenotes', true); // Create a teacher. $teacher1 = $this->getDataGenerator()->create_user(); $this->setUser($teacher1); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); // Create a student. $student = $this->getDataGenerator()->create_user(); // Create student2. $student2 = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); // Create courses, then enrol a teacher and a student. $nocourses = 3; for ($c = 1; $c <= $nocourses; $c++) { ${'course' . $c} = $this->getDataGenerator()->create_course(); ${'coursecontext' . $c} = \context_course::instance(${'course' . $c}->id); role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id); role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id); role_assign($studentrole->id, $student2->id, ${'coursecontext' . $c}->id); } // The list of users in coursecontext1 should be empty (related data still have not been created). $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); provider::get_users_in_context($userlist1); $this->assertCount(0, $userlist1); // The list of users in coursecontext2 should be empty (related data still have not been created). $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); provider::get_users_in_context($userlist2); $this->assertCount(0, $userlist2); // The list of users in coursecontext3 should be empty (related data still have not been created). $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); provider::get_users_in_context($userlist3); $this->assertCount(0, $userlist3); // Create private user notes (i.e. NOTES_STATE_DRAFT) for student in course1 and course2 written by the teacher. $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id, "Test private user note about the student in Course 1 by the teacher"); $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id, "Test private user note about the student in Course 2 by the teacher"); // The list of users in coursecontext1 should return one user (teacher1). provider::get_users_in_context($userlist1); $this->assertCount(1, $userlist1); $this->assertTrue(in_array($teacher1->id, $userlist1->get_userids())); // The list of users in coursecontext2 should return one user (teacher1). provider::get_users_in_context($userlist2); $this->assertCount(1, $userlist2); $this->assertTrue(in_array($teacher1->id, $userlist2->get_userids())); // The list of users in coursecontext3 should not return any users. provider::get_users_in_context($userlist3); $this->assertCount(0, $userlist3); // Create public user note (i.e. NOTES_STATE_PUBLIC) for student in course3 written by the teacher. $this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id, "Test public user note about the student in Course 3 by the teacher"); // The list of users in coursecontext3 should return 2 users (teacher and student). provider::get_users_in_context($userlist3); $this->assertCount(2, $userlist3); $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); $this->assertTrue(in_array($student->id, $userlist3->get_userids())); // Create site user note (i.e. NOTES_STATE_SITE) for student2 in course3 written by the teacher. $this->help_create_user_note($student2->id, NOTES_STATE_SITE, $course3->id, "Test site-wide user note about student2 in Course 3 by the teacher" ); // The list of users in coursecontext3 should return 3 users (teacher, student and student2). provider::get_users_in_context($userlist3); $this->assertCount(3, $userlist3); $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); $this->assertTrue(in_array($student->id, $userlist3->get_userids())); $this->assertTrue(in_array($student2->id, $userlist3->get_userids())); // The list of users should not return any users in a different context than course context. $contextsystem = \context_system::instance(); $userlist4 = new \core_privacy\local\request\userlist($contextsystem, $component); provider::get_users_in_context($userlist4); $this->assertCount(0, $userlist4); } /** * Test that data for users in approved userlist is deleted. */ public function test_delete_data_for_users() { global $DB; $this->resetAfterTest(true); $component = 'core_notes'; // Test setup. $this->setAdminUser(); set_config('enablenotes', true); // Create a teacher. $teacher1 = $this->getDataGenerator()->create_user(); $this->setUser($teacher1); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); // Create a student. $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); // Create Courses, then enrol a teacher and a student. $nocourses = 3; for ($c = 1; $c <= $nocourses; $c++) { ${'course' . $c} = $this->getDataGenerator()->create_course(); ${'coursecontext' . $c} = \context_course::instance(${'course' . $c}->id); role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id); role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id); } // Create private notes for student in the course1 and course2 written by the teacher. $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id, "Test private user note about the student in Course 1 by the teacher"); $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id, "Test private user note about the student in Course 2 by the teacher"); // Create public notes for student in the course3 written by the teacher. $this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id, "Test public user note about the student in Course 3 by the teacher"); // The list of users in coursecontext1 should return one user (teacher1). $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); provider::get_users_in_context($userlist1); $this->assertCount(1, $userlist1); $this->assertTrue(in_array($teacher1->id, $userlist1->get_userids())); // The list of users in coursecontext2 should return one user (teacher1). $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); provider::get_users_in_context($userlist2); $this->assertCount(1, $userlist2); $this->assertTrue(in_array($teacher1->id, $userlist2->get_userids())); // The list of users in coursecontext3 should return two users (teacher1 and student). $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); provider::get_users_in_context($userlist3); $this->assertCount(2, $userlist3); $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); $this->assertTrue(in_array($student->id, $userlist3->get_userids())); $approvedlist = new approved_userlist($coursecontext3, $component, [$student->id]); // Delete using delete_data_for_user. provider::delete_data_for_users($approvedlist); // Re-fetch users in the coursecontext3. $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); // The user data in coursecontext3 should not be removed. provider::get_users_in_context($userlist3); $this->assertCount(2, $userlist3); $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); $this->assertTrue(in_array($student->id, $userlist3->get_userids())); $approvedlist = new approved_userlist($coursecontext3, $component, [$teacher1->id]); // Delete using delete_data_for_user. provider::delete_data_for_users($approvedlist); // Re-fetch users in the coursecontext3. $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); // The user data in coursecontext3 should be removed. provider::get_users_in_context($userlist3); $this->assertCount(0, $userlist3); // Re-fetch users in the coursecontext1. $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); provider::get_users_in_context($userlist1); $this->assertCount(1, $userlist1); $approvedlist = new approved_userlist($coursecontext1, $component, [$student->id]); // Delete using delete_data_for_user. provider::delete_data_for_users($approvedlist); // Re-fetch users in the coursecontext1. $userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component); // The user data in coursecontext1 should not be removed. provider::get_users_in_context($userlist3); $this->assertCount(1, $userlist3); $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); $approvedlist = new approved_userlist($coursecontext1, $component, [$teacher1->id]); // Delete using delete_data_for_user. provider::delete_data_for_users($approvedlist); // Re-fetch users in the coursecontext1. $userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component); // The user data in coursecontext1 should be removed. provider::get_users_in_context($userlist3); $this->assertCount(0, $userlist3); // Re-fetch users in the coursecontext2. $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); provider::get_users_in_context($userlist2); $this->assertCount(1, $userlist2); // The list of users should not return any users for contexts different than course context. $systemcontext = \context_system::instance(); $userlist4 = new \core_privacy\local\request\userlist($systemcontext, $component); provider::get_users_in_context($userlist4); $this->assertCount(0, $userlist4); } /** * Helper function to create user notes for testing. * * @param int $userid The ID of the User associated with the note. * @param string $state The publish status * @param int $courseid The ID of the Course associated with the note. * @param string $content The note content. */ protected function help_create_user_note($userid, $state, $courseid, $content) { $note = (object) [ 'userid' => $userid, 'publishstate' => $state, 'courseid' => $courseid, 'content' => $content, ]; note_save($note); } } tests/behat/participants_notes.feature 0000604 00000006311 15062070721 0014254 0 ustar 00 @core @core_notes @javascript Feature: Add notes to course participants In order to share information with other staff As a teacher I need to add notes from the course particpants list Scenario: An teacher can add multiple notes Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | | student1 | Student | 1 | student1@example.com | | student2 | Student | 2 | student2@example.com | | student3 | Student | 3 | student3@example.com | And the following "courses" exist: | fullname | shortname | format | | Course 1 | C1 | topics | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | | student1 | C1 | student | | student2 | C1 | student | | student3 | C1 | student | # TODO MDL-57120 "Notes" and site "Participants" links are not accessible without navigation block. Given I log in as "admin" And I am on site homepage And I turn editing mode on And the following config values are set as admin: | unaddableblocks | | theme_boost| And I add the "Navigation" block if not present And I configure the "Navigation" block And I set the following fields to these values: | Page contexts | Display throughout the entire site | And I press "Save changes" And I log out And I log in as "teacher1" And I am on "Course 1" course homepage And I follow "Participants" And I set the field with xpath "//tr[contains(normalize-space(.), 'Student 1')]//input[@type='checkbox']" to "1" And I choose "Add a new note" from the participants page bulk action menu And I set the field "bulk-note" to "Student 1 needs to pick up his game" And I press "Add a new note to 1 person" And I set the field with xpath "//tr[contains(normalize-space(.), 'Student 1')]//input[@type='checkbox']" to "0" And I set the field with xpath "//tr[contains(normalize-space(.), 'Student 2')]//input[@type='checkbox']" to "1" And I choose "Add a new note" from the participants page bulk action menu And I set the field "bulk-note" to "" And I press "Add a new note to 1 person" And I set the field with xpath "//tr[contains(normalize-space(.), 'Student 2')]//input[@type='checkbox']" to "0" And I set the field with xpath "//tr[contains(normalize-space(.), 'Student 3')]//input[@type='checkbox']" to "1" And I choose "Add a new note" from the participants page bulk action menu And I set the field "bulk-note" to " " And I press "Add a new note to 1 person" And I follow "Student 1" And I follow "Notes" # Student 1 has note from Teacher Then I should see "Teacher" in the "region-main" "region" And I should see "Student 1 needs to pick up his game" And I follow "Participants" And I follow "Student 2" And I follow "Notes" And I am on "Course 1" course homepage And I follow "Participants" And I follow "Notes" Then I should see "Student 1" And I should see "Student 1 needs to pick up his game" # Verify Student 2 does not have a note added. And I should not see "Student 2" And I should not see "Student 3" tests/generator/lib.php 0000604 00000007223 15062070721 0011153 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * core_notes data generator. * * @package core_notes * @category test * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * core_notes data generator class. * * @package core_notes * @category test * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_notes_generator extends component_generator_base { /** * @var number of created instances */ protected $instancecount = 0; /** * To be called from data reset code only, * do not use in tests. * @return void */ public function reset() { $this->instancecount = 0; } /** * Create a new note. * * @param array|stdClass $record * @throws coding_exception * @return stdClass activity record with extra cmid field */ public function create_instance($record = null) { global $CFG, $USER; require_once("$CFG->dirroot/notes/lib.php"); $this->instancecount++; $i = $this->instancecount; $record = (object)(array)$record; if (empty($record->courseid)) { throw new coding_exception('Module generator requires $record->courseid.'); } if (empty($record->userid)) { throw new coding_exception('Module generator requires $record->userid.'); } if (!isset($record->module)) { $record->module = 'notes'; } if (!isset($record->groupid)) { $record->groupid = 0; } if (!isset($record->moduleid)) { $record->moduleid = 0; } if (!isset($record->coursemoduleid)) { $record->coursemoduleid = 0; } if (!isset($record->subject)) { $record->subject = ''; } if (!isset($record->summary)) { $record->summary = null; } if (!isset($record->content)) { $record->content = "This is test generated note - $i ."; } if (!isset($record->uniquehash)) { $record->uniquehash = ''; } if (!isset($record->rating)) { $record->rating = 0; } if (!isset($record->format)) { $record->format = FORMAT_PLAIN; } if (!isset($record->summaryformat)) { $record->summaryformat = FORMAT_MOODLE; } if (!isset($record->attachment)) { $record->attachment = null; } if (!isset($record->publishstate)) { $record->publishstate = NOTES_STATE_SITE; } if (!isset($record->lastmodified)) { $record->lastmodified = time(); } if (!isset($record->created)) { $record->created = time(); } if (!isset($record->usermodified)) { $record->usermodified = $USER->id; } note_save($record); return $record; } } tests/reportbuilder/datasource/notes_test.php 0000604 00000024614 15062070721 0015625 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. declare(strict_types=1); namespace core_notes\reportbuilder\datasource; use core_notes_generator; use core_reportbuilder_generator; use core_reportbuilder_testcase; use core_reportbuilder\local\filters\{date, select, text}; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php"); /** * Unit tests for notes datasource * * @package core_notes * @covers \core_notes\reportbuilder\datasource\notes * @copyright 2022 Paul Holden <paulh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class notes_test extends core_reportbuilder_testcase { /** * Load required test libraries */ public static function setUpBeforeClass(): void { global $CFG; require_once("{$CFG->dirroot}/notes/lib.php"); } /** * Test default datasource */ public function test_datasource_default(): void { $this->resetAfterTest(); /** @var core_notes_generator $notesgenerator */ $notesgenerator = $this->getDataGenerator()->get_plugin_generator('core_notes'); // Our first user will create a course note. $course = $this->getDataGenerator()->create_course(); $userone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']); $coursenote = $notesgenerator->create_instance(['courseid' => $course->id, 'userid' => $userone->id, 'content' => 'Course', 'publishstate' => NOTES_STATE_PUBLIC]); // Our second user will create a personal and site note. $usertwo = $this->getDataGenerator()->create_user(['firstname' => 'Amy']); $personalnote = $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $usertwo->id, 'content' => 'Personal', 'publishstate' => NOTES_STATE_DRAFT]); $this->waitForSecond(); // For consistent ordering we need distinct time for second user notes. $sitenote = $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $usertwo->id, 'content' => 'Site', 'publishstate' => NOTES_STATE_SITE]); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); $report = $generator->create_report(['name' => 'Notes', 'source' => notes::class, 'default' => 1]); $content = $this->get_custom_report_content($report->get('id')); // Default columns are recipient, publishstate, course, note, time created. Sorted by recipient and time created. $this->assertEquals([ [fullname($usertwo), 'Personal notes', '', 'Personal', userdate($personalnote->created)], [fullname($usertwo), 'Site notes', '', 'Site', userdate($sitenote->created)], [fullname($userone), 'Course notes', $course->fullname, 'Course', userdate($coursenote->created)], ], array_map('array_values', $content)); } /** * Test datasource columns that aren't added by default */ public function test_datasource_non_default_columns(): void { global $DB; $this->resetAfterTest(); $recipient = $this->getDataGenerator()->create_user(); $author = $this->getDataGenerator()->create_user(); $this->setUser($author); /** @var core_notes_generator $notesgenerator */ $notesgenerator = $this->getDataGenerator()->get_plugin_generator('core_notes'); $note = $notesgenerator->create_instance(['courseid' => SITEID, 'publishstate' => NOTES_STATE_SITE, 'content' => 'Cool', 'userid' => $recipient->id, ]); // Manually update the created/modified date of the note. $note->created = 1654038000; $note->lastmodified = $note->created + HOURSECS; $DB->update_record('post', $note); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); $report = $generator->create_report(['name' => 'Notes', 'source' => notes::class, 'default' => 0]); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'note:content']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'note:timecreated']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'note:timemodified']); // Ensure we can add data from both user entities. $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'recipient:fullname']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'author:fullname']); $content = $this->get_custom_report_content($report->get('id')); $this->assertCount(1, $content); $this->assertEquals([ 'Cool', userdate($note->created), userdate($note->lastmodified), fullname($recipient), fullname($author), ], array_values($content[0])); } /** * Data provider for {@see test_datasource_filters} * * @return array[] */ public function datasource_filters_provider(): array { return [ 'Filter content' => ['content', 'Cool', 'note:content', [ 'note:content_operator' => text::IS_EQUAL_TO, 'note:content_value' => 'Cool', ], true], 'Filter content (no match)' => ['content', 'Cool', 'note:content', [ 'note:content_operator' => text::DOES_NOT_CONTAIN, 'note:content_value' => 'Cool', ], false], 'Filter publish state' => ['publishstate', 'site', 'note:publishstate', [ 'note:publishstate_operator' => select::EQUAL_TO, 'note:publishstate_value' => 'site', ], true], 'Filter publish state (no match)' => ['publishstate', 'site', 'note:publishstate', [ 'note:publishstate_operator' => select::EQUAL_TO, 'note:publishstate_value' => 'public', ], false], 'Filter time created' => ['created', 1654038000, 'note:timecreated', [ 'note:timecreated_operator' => date::DATE_RANGE, 'note:timecreated_from' => 1622502000, ], true], 'Filter time created (no match)' => ['created', 1654038000, 'note:timecreated', [ 'note:timecreated_operator' => date::DATE_RANGE, 'note:timecreated_to' => 1622502000, ], false], 'Filter time modified' => ['lastmodified', 1654038000, 'note:timemodified', [ 'note:timemodified_operator' => date::DATE_RANGE, 'note:timemodified_from' => 1622502000, ], true], 'Filter time modified (no match)' => ['lastmodified', 1654038000, 'note:timemodified', [ 'note:timemodified_operator' => date::DATE_RANGE, 'note:timemodified_to' => 1622502000, ], false], ]; } /** * Test datasource filters * * @param string $field * @param mixed $value * @param string $filtername * @param array $filtervalues * @param bool $expectmatch * * @dataProvider datasource_filters_provider */ public function test_datasource_filters( string $field, $value, string $filtername, array $filtervalues, bool $expectmatch ): void { global $DB; $this->resetAfterTest(); $recipient = $this->getDataGenerator()->create_user(); /** @var core_notes_generator $notesgenerator */ $notesgenerator = $this->getDataGenerator()->get_plugin_generator('core_notes'); // Create default note, then manually override one of it's properties to use for filtering. $note = $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $recipient->id]); $DB->set_field('post', $field, $value, ['id' => $note->id]); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); // Create report containing single recipient column, and given filter. $report = $generator->create_report(['name' => 'Notes', 'source' => notes::class, 'default' => 0]); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'recipient:fullname']); // Add filter, set it's values. $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]); $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues); if ($expectmatch) { $this->assertCount(1, $content); $this->assertEquals(fullname($recipient), reset($content[0])); } else { $this->assertEmpty($content); } } /** * Stress test datasource * * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php */ public function test_stress_datasource(): void { if (!PHPUNIT_LONGTEST) { $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); } $this->resetAfterTest(); $recipient = $this->getDataGenerator()->create_user(); /** @var core_notes_generator $notesgenerator */ $notesgenerator = $this->getDataGenerator()->get_plugin_generator('core_notes'); $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $recipient->id]); $this->datasource_stress_test_columns(notes::class); $this->datasource_stress_test_columns_aggregation(notes::class); $this->datasource_stress_test_conditions(notes::class, 'note:content'); } } tests/generator_test.php 0000604 00000006277 15062070721 0011454 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Generator tests. * * @package core_notes * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_notes; /** * Generator tests class. * * @package core_notes * @copyright 2013 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class generator_test extends \advanced_testcase { /** Test create_instance method */ public function test_create_instance() { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $user = $this->getDataGenerator()->create_user(); $gen = $this->getDataGenerator()->get_plugin_generator('core_notes'); $this->assertFalse($DB->record_exists('post', array('courseid' => $course->id))); $note = $gen->create_instance(array('courseid' => $course->id, 'userid' => $user->id)); $this->assertEquals(1, $DB->count_records('post', array('courseid' => $course->id, 'userid' => $user->id))); $this->assertTrue($DB->record_exists('post', array('id' => $note->id))); $params = array('courseid' => $course->id, 'userid' => $user->id, 'publishstate' => NOTES_STATE_DRAFT); $note = $gen->create_instance($params); $this->assertEquals(2, $DB->count_records('post', array('courseid' => $course->id, 'userid' => $user->id))); $this->assertEquals(NOTES_STATE_DRAFT, $DB->get_field_select('post', 'publishstate', 'id = :id', array('id' => $note->id))); } /** Test Exceptions thrown by create_instance method */ public function test_create_instance_exceptions() { $this->resetAfterTest(); $gen = $this->getDataGenerator()->get_plugin_generator('core_notes'); // Test not setting userid. try { $gen->create_instance(array('courseid' => 2)); $this->fail('A note should not be allowed to be created without associcated userid'); } catch (\coding_exception $e) { $this->assertStringContainsString('Module generator requires $record->userid', $e->getMessage()); } // Test not setting courseid. try { $gen->create_instance(array('userid' => 2)); $this->fail('A note should not be allowed to be created without associcated courseid'); } catch (\coding_exception $e) { $this->assertStringContainsString('Module generator requires $record->courseid', $e->getMessage()); } } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка