diff --git a/public/lib/filelib.php b/public/lib/filelib.php index e42900e3acf..8f4c38c2ae2 100644 --- a/public/lib/filelib.php +++ b/public/lib/filelib.php @@ -5198,6 +5198,26 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null, $offlin \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60*60, 0, $forcedownload, $sendfileoptions); } + } else if ($component === 'notes') { + require_login($course); + + $noteid = (int) array_shift($args); + + $note = $DB->get_record('post', ['module' => 'notes', 'id' => $noteid]); + $notecontext = \core\context\course::instance($note->courseid); + + if ($context->id !== $notecontext->id || !has_capability('moodle/notes:view', $context)) { + send_file_not_found(); + } + + $filename = array_pop($args); + $file = $fs->get_file($context->id, $component, $filearea, $note->id, '/', $filename); + if ($file !== false && !$file->is_directory()) { + \core\session\manager::write_close(); + send_stored_file($file, HOURSECS, 0, $forcedownload, $sendfileoptions); + } + + send_file_not_found(); } else if ($component === 'contentbank') { if ($filearea != 'public' || isguestuser()) { send_file_not_found(); diff --git a/public/notes/classes/reportbuilder/local/entities/note.php b/public/notes/classes/reportbuilder/local/entities/note.php index 8c595e77872..a0349ca4208 100644 --- a/public/notes/classes/reportbuilder/local/entities/note.php +++ b/public/notes/classes/reportbuilder/local/entities/note.php @@ -18,7 +18,8 @@ declare(strict_types=1); namespace core_notes\reportbuilder\local\entities; -use lang_string; +use core\{context, context_helper}; +use core\lang_string; use stdClass; use core_reportbuilder\local\entities\base; use core_reportbuilder\local\filters\{date, select, text}; @@ -46,6 +47,7 @@ class note extends base { */ protected function get_default_tables(): array { return [ + 'context', 'post', ]; } @@ -65,7 +67,10 @@ class note extends base { * @return column[] */ protected function get_available_columns(): array { - $postalias = $this->get_table_alias('post'); + [ + 'context' => $contextalias, + 'post' => $postalias, + ] = $this->get_table_aliases(); // Content. $columns[] = (new column( @@ -74,14 +79,27 @@ class note extends base { $this->get_entity_name() )) ->add_joins($this->get_joins()) + ->add_join("LEFT JOIN {context} {$contextalias} + ON {$contextalias}.contextlevel = " . CONTEXT_COURSE . " + AND {$contextalias}.instanceid = {$postalias}.courseid") ->set_type(column::TYPE_LONGTEXT) - ->add_fields("{$postalias}.content, {$postalias}.format") + ->add_fields("{$postalias}.content, {$postalias}.format, {$postalias}.id") + ->add_fields(context_helper::get_preload_record_columns_sql($contextalias)) ->set_is_sortable(true) ->add_callback(static function(?string $content, stdClass $note): string { - if ($content === null) { + global $CFG; + require_once("{$CFG->libdir}/filelib.php"); + + if ($content === null || $note->ctxid === null) { return ''; } - return format_text($content, $note->format); + + context_helper::preload_from_record(clone $note); + $context = context::instance_by_id($note->ctxid); + + $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $context->id, 'notes', 'content', $note->id); + + return format_text($content, $note->format, ['context' => $context]); }); // Publish state. diff --git a/public/notes/edit.php b/public/notes/edit.php index 5d7970f4047..702309902ba 100644 --- a/public/notes/edit.php +++ b/public/notes/edit.php @@ -37,6 +37,8 @@ if ($noteid) { $state = optional_param('publishstate', NOTES_STATE_PUBLIC, PARAM_ALPHA); $note = new stdClass(); + $note->id = null; + $note->format = FORMAT_HTML; $note->courseid = $courseid; $note->userid = $userid; $note->publishstate = $state; @@ -67,7 +69,16 @@ if (!$user = $DB->get_record('user', array('id' => $note->userid))) { throw new \moodle_exception('invaliduserid'); } -$noteform = new note_edit_form(); +$editoroptions = [ + 'context' => $context, + 'maxfiles' => EDITOR_UNLIMITED_FILES, + 'maxbytes' => get_user_max_upload_file_size($context, $CFG->maxbytes, $course->maxbytes), +]; + +$note->contentformat = $note->format; +$note = file_prepare_standard_editor($note, 'content', $editoroptions, $context, 'notes', 'content', $note->id); + +$noteform = new note_edit_form(null, ['editoroptions' => $editoroptions]); $noteform->set_data($note); // If form was cancelled then return to the notes list of the note. @@ -83,7 +94,17 @@ if ($note = $noteform->get_data()) { unset($note->courseid); unset($note->userid); } + + // Extract editor content so it can be initially saved. + $contenteditor = $note->content_editor; + ['text' => $note->content, 'format' => $note->format] = $contenteditor; note_save($note); + + // Post-process editor content. + $note->content_editor = $contenteditor; + file_postupdate_standard_editor($note, 'content', $editoroptions, $context, 'notes', 'content', $note->id); + $DB->update_record('post', $note); + // Redirect to notes list that contains this note. redirect($CFG->wwwroot . '/notes/index.php?course=' . $note->courseid . '&user=' . $note->userid); } diff --git a/public/notes/edit_form.php b/public/notes/edit_form.php index b124a631477..f9e3ddc046c 100644 --- a/public/notes/edit_form.php +++ b/public/notes/edit_form.php @@ -27,12 +27,14 @@ class note_edit_form extends moodleform { */ public function definition() { $mform =& $this->_form; + + $editoroptions = $this->_customdata['editoroptions']; + $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('editor', 'content_editor', get_string('content', 'notes'), null, $editoroptions); + $mform->setType('content_editor', PARAM_RAW); + $mform->addRule('content_editor', get_string('nocontent', 'notes'), 'required', null, 'client'); $mform->addElement('select', 'publishstate', get_string('publishstate', 'notes'), note_get_state_names()); $mform->setDefault('publishstate', NOTES_STATE_PUBLIC); diff --git a/public/notes/externallib.php b/public/notes/externallib.php index ecca3c6ea37..abdc4f15a9c 100644 --- a/public/notes/externallib.php +++ b/public/notes/externallib.php @@ -313,12 +313,16 @@ class core_notes_external extends external_api { $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['text'], $gotnote['format']] = util::format_text( + $note->content, + $note->format, + $context, + 'notes', + 'content', + $note->id, + ); + $gotnote['noteid'] = $note->id; $gotnote['userid'] = $note->userid; $gotnote['publishstate'] = $note->publishstate; @@ -485,7 +489,7 @@ class core_notes_external extends external_api { * Create a notes list * * @param int $courseid ID of the Course - * @param stdClass $context context object + * @param context $context context instance * @param int $userid ID of the User * @param int $state * @param int $author @@ -500,10 +504,10 @@ class core_notes_external extends external_api { [$note['content'], $note['format']] = util::format_text( $note['content'], $note['format'], - $context->id, - '', - '', - 0 + $context, + 'notes', + 'content', + $note['id'], ); $results[$key] = $note; } diff --git a/public/notes/lib.php b/public/notes/lib.php index a4ef3b8de59..3d9a3ef3e54 100644 --- a/public/notes/lib.php +++ b/public/notes/lib.php @@ -172,13 +172,16 @@ function note_delete($note) { $note = $DB->get_record('post', array('id' => $noteid), '*', MUST_EXIST); $return = $DB->delete_records('post', array('id' => $note->id, 'module' => 'notes')); + $context = \core\context\course::instance($note->courseid); + get_file_storage()->delete_area_files($context->id, 'notes', 'content', $note->id); + // 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), + 'context' => $context, 'other' => array('publishstate' => $note->publishstate) )); $event->add_record_snapshot('post', $note); @@ -263,7 +266,8 @@ function note_print($note, $detail = NOTES_SHOW_FULL) { // Print note content. if ($detail & NOTES_SHOW_BODY) { echo '
'; - echo format_text($note->content, $note->format, array('overflowdiv' => true)); + $content = file_rewrite_pluginfile_urls($note->content, 'pluginfile.php', $context->id, 'notes', 'content', $note->id); + echo format_text($content, $note->format, ['overflowdiv' => true, 'context' => $context]); echo '
'; } @@ -344,6 +348,9 @@ function note_print_notes($header, $addcourseid = 0, $viewnotes = true, $coursei function note_delete_all($courseid) { global $DB; + $context = \core\context\course::instance($courseid); + get_file_storage()->delete_area_files($context->id, 'notes', 'content'); + return $DB->delete_records('post', array('module' => 'notes', 'courseid' => $courseid)); }