AutorÃa | Ultima modificación | Ver Log |
<?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/>.
/**
* Implementation of the Amanote filter plugin.
*
* @package filter_amanote
* @copyright 2020 Amaplex Software
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
require_once($CFG->libdir . '/externallib.php');
require_once(__DIR__ . '/helpers/filehelper.php');
require_once(__DIR__ . '/models/annotatable.php');
/**
* Filter for processing file links for Amanote enhancements.
*
* @copyright 2020 Amaplex Software
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class filter_amanote extends moodle_text_filter {
/**
* Set up the filter and insert JS scripts to page using amd.
*
* @param moodle_page $page The current page.
* @param context $context The current context.
*/
public function setup($page, $context) {
try {
global $PAGE, $COURSE;
// Check if the filter is enabled for the current course.
$enabledfilters = filter_get_active_in_context(context_course::instance($COURSE->id));
if (!isset($enabledfilters['amanote'])) {
return;
}
static $scriptinserted = false;
// Insert script if needed.
if ($scriptinserted ||
(stripos($PAGE->pagetype, 'course-view') !== 0 && $PAGE->pagetype !== 'mod-folder-view') ||
(strpos($PAGE->url, 'user/') !== false)) {
return;
}
$this->insert_script($page);
$scriptinserted = true;
} catch (Exception $e) {
debugging('An error occurred: ' . $e->getMessage(), DEBUG_DEVELOPER);
}
}
/**
* Insert the js script.
*
* @param moodle_page $page The page in which the script should be inserted.
*/
private function insert_script($page) {
global $CFG;
$params = $this->generate_json_params();
$userparams = $this->generate_json_user_params();
// Insert user params using AMD.
$page->requires->js_call_amd('filter_amanote/main', 'init', [$userparams]);
// Insert params in footer (AMD can't handle long params).
$script = <<<EOF
<script>
var amanote_params = $params;
</script>
EOF;
if (!isset($CFG->additionalhtmlfooter)) {
$CFG->additionalhtmlfooter = '';
}
$CFG->additionalhtmlfooter .= $script;
}
/**
* Return the Moodle params needed by the js script in JSON format.
*
* @return string The params in JSON string format.
*/
private function generate_json_params() {
global $USER, $COURSE, $CFG, $OUTPUT;
try {
$config = get_config('filter_amanote');
$siteurl = $this->get_site_url();
$language = substr($USER->lang, 0, 2);
$usercontext = context_user::instance($USER->id);
$privatefilepath = '/' . $usercontext->id . '/user/private/Amanote/';
$contentkind = $config->anonymous ? 'document' : null;
$annotatables = $this->get_annotatables($COURSE, $contentkind);
$moodleversion = preg_replace('/(\d+\.\d+(\.\d+)?) .*$/', '$1', $CFG->release);
$notelogo = $this->get_note_taking_logo_name($config->openingmode);
$logourl = $OUTPUT->image_url($notelogo , 'filter_amanote')->__toString();
$annotatedlogourl = $OUTPUT->image_url($notelogo . '-annotated', 'filter_amanote')->__toString();
$savednotes = null;
if ($config->saveinprivate) {
$savednotes = get_user_notes_for_course($USER->id, $COURSE->id);
}
return json_encode([
'siteURL' => $siteurl,
'privateFilePath' => $privatefilepath,
'savedNotes' => $savednotes,
'annotatables' => $annotatables,
'moodle' => [
'version' => $moodleversion,
],
'plugin' => [
'version' => $config->version,
'saveInProvider' => ($config->saveinprivate == '1'),
'preventDownload' => ($config->preventdownload == '1'),
'openingMode' => $config->openingmode,
'target' => $config->target,
'key' => $config->key,
'anonymous' => ($config->anonymous == '1'),
'worksheet' => ($config->worksheet == '1'),
'logo' => $logourl,
'annotatedLogo' => $annotatedlogourl,
],
'language' => $language,
'strings' => [
'modalDescription' => get_string('modaldescription', 'filter_amanote'),
'annotateResource' => get_string('annotateresource', 'filter_amanote'),
'viewResource' => get_string('viewresource', 'filter_amanote'),
'downloadNotes' => get_string('downloadnotes', 'filter_amanote'),
'openAnalytics' => get_string('openanalytics', 'filter_amanote'),
'openPodcastCreator' => get_string('openpodcast', 'filter_amanote'),
'openStudentsWorks' => get_string('openstudentsworks', 'filter_amanote'),
'teacher' => get_string('teacher', 'filter_amanote'),
'deletefilewarning' => get_string('deletefilewarning', 'filter_amanote'),
'seeguide' => get_string('seeguide', 'filter_amanote'),
'stopmodal' => get_string('stopmodal', 'filter_amanote'),
],
]);
} catch (Exception $e) {
debugging('An error occurred: ' . $e->getMessage() . $e->getTraceAsString(), DEBUG_DEVELOPER);
}
}
/**
* Return the note-taking logo name for the given opening mode.
*
* @param integer $openingmode The opening mode.
*
* @return string The note-taking logo name.
*/
private function get_note_taking_logo_name($openingmode) {
$openingmodeicons = [
'0' => 'amanote-logo',
'1' => 'amanote-logo',
'2' => 'note-icon',
'3' => get_string('takenotesicon', 'filter_amanote'),
];
return $openingmodeicons[$openingmode];
}
/**
* Return the user params needed by the js script in JSON format.
*
* @return string The user params in JSON string format.
*/
private function generate_json_user_params() {
global $USER, $COURSE;
$coursecontext = context_course::instance($COURSE->id, MUST_EXIST);
$isteacher = has_capability('moodle/course:update', $coursecontext, $USER->id, false);
$token = $this->get_current_user_token();
return json_encode([
'id' => $USER->id,
'token' => [
'value' => $token->token,
'expiration' => $token->validuntil,
],
'isTeacher' => $isteacher,
]);
}
/**
* Return the token of the current user.
*
* @return token The user token.
*/
private function get_current_user_token() {
global $DB;
$params = ['shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE, 'enabled' => 1];
$service = $DB->get_record('external_services', $params);
if (empty($service)) {
return null;
}
return external_generate_token_for_current_user($service);
}
/**
* Return the site url.
*
* @return string The site url (example: https://demo.moodle.com).
*/
private function get_site_url() {
global $CFG;
// Check if protocol is HTTP.
if (preg_match('/^http:\/\//', $CFG->wwwroot)) {
$securewwwroot = preg_replace('/^http:\/\//', 'https://', $CFG->wwwroot, 1);
// Check if Moodle site exists in HTTPS.
$curl = curl_init($securewwwroot);
if (curl_exec($curl)) {
return $securewwwroot;
}
curl_close($curl);
}
return $CFG->wwwroot;
}
/**
* Return all annotatables for the given course.
*
* @param course $course The course.
* @param string $contentkind Get only a specific content type.
*
* @return array List of all annotatable for the given course.
*/
private function get_annotatables($course, $contentkind = null) {
global $DB;
$annotatables = [];
$supportedtypes = get_supported_mimetypes($contentkind);
// Get all the annotable files for the given course.
$sql = "SELECT
{files}.id as id,
{course_modules}.id as cmid,
{course_modules}.instance as modinstance,
{context}.id as contextid,
{files}.mimetype,
{files}.component,
{files}.filearea,
{files}.filepath,
{files}.filename
FROM {course_modules}
LEFT JOIN {context} ON {context}.instanceid = {course_modules}.id
LEFT JOIN {files} ON {files}.contextid = {context}.id
AND {course_modules}.course = :courseid
WHERE {files}.component in ('mod_resource', 'mod_label', 'mod_folder')
AND {files}.source IS NOT NULL AND {files}.filename != '.'
";
$files = $DB->get_records_sql($sql, ['courseid' => $course->id]);
if (!$files || count($files) <= 0) {
return [];
}
foreach ($files as $file) {
try {
// Add only supported files.
if (!in_array($file->mimetype, $supportedtypes)) {
continue;
}
$annotatable = get_annotatable_for_file($file, $course->id, $file->cmid, $file->modinstance);
// Add the annotatable to the array of annotatables.
array_push($annotatables, $annotatable);
} catch (Exception $e) {
debugging('An error occurred: ' . $e->getMessage(), DEBUG_DEVELOPER);
continue;
}
}
// Add the annotables for urls.
$annotatables = array_merge($annotatables, $this->get_annotatable_urls($course, $contentkind));
return $annotatables;
}
/**
* Return all annotable urls for a given course.
*
* @param course $course The course.
* @param string $contentkind Get only a specific content type.
*
* @return array List of annotable urls for the given course.
*/
private function get_annotatable_urls($course, $contentkind = null) {
global $DB;
$annotatables = [];
$supportedtypes = get_supported_mimetypes($contentkind);
// Get the urls for the given course.
$sql = "SELECT {course_modules}.id as cmid, {url}.externalurl FROM {url}
LEFT JOIN {course_modules} ON {course_modules}.instance = {url}.id
LEFT JOIN {modules} ON {modules}.id = {course_modules}.module
WHERE {course_modules}.course = :courseid
AND {modules}.name = 'url'";
$urls = $DB->get_records_sql($sql, ['courseid' => $course->id]);
if (!$urls || count($urls) <= 0) {
return $annotatables;
}
foreach ($urls as $url) {
try {
// Add only supported files.
$annotatable = get_annotatable_for_url($url, $course->id, $url->cmid);
if (!$annotatable->mimetype || !in_array($annotatable->mimetype, $supportedtypes)) {
continue;
}
// Add the annotatable to the array of annotatables.
array_push($annotatables, $annotatable);
} catch (Exception $e) {
debugging('An error occurred: ' . $e->getMessage(), DEBUG_DEVELOPER);
continue;
}
}
return $annotatables;
}
/**
* Filters the given HTML text.
*
* @param string $text HTML to be processed.
* @param array $options The options.
*
* @return string String containing processed HTML.
*/
public function filter($text, array $options = []) {
return $text;
}
}