diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..866a43f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,9 @@ +## Description + + +## Testing + + + +## Jira Link + \ No newline at end of file diff --git a/.github/workflows/moodle-plugin-ci.yml b/.github/workflows/moodle-plugin-ci.yml index b736c7f..fb77a72 100644 --- a/.github/workflows/moodle-plugin-ci.yml +++ b/.github/workflows/moodle-plugin-ci.yml @@ -38,17 +38,17 @@ jobs: fail-fast: false matrix: include: - - php: '8.0' + - php: '8.1' moodle-branch: 'master' database: 'pgsql' - - php: '8.0' - moodle-branch: 'MOODLE_400_STABLE' + - php: '8.2' + moodle-branch: 'MOODLE_403_STABLE' database: 'mariadb' - - php: '7.4' - moodle-branch: 'MOODLE_311_STABLE' + - php: '8.1' + moodle-branch: 'MOODLE_402_STABLE' database: 'pgsql' - - php: '7.4' - moodle-branch: 'MOODLE_39_STABLE' + - php: '8.1' + moodle-branch: 'MOODLE_401_STABLE' database: 'mariadb' steps: diff --git a/Gruntfile.js b/Gruntfile.js index 562fad1..216c747 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,152 +1,41 @@ -// 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 . -/* jshint node: true, browser: false */ -/* eslint-env node */ - -/** - * @copyright 2021 Panopto - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Grunt configuration - */ - -/* eslint-env node */ -module.exports = function(grunt) { - var path = require('path'), - tasks = {}, - cwd = process.env.PWD || process.cwd(), - async = require('async'); - - // Windows users can't run grunt in a subdirectory, so allow them to set - // the root by passing --root=path/to/dir. - if (grunt.option('root')) { - var root = grunt.option('root'); - if (grunt.file.exists(__dirname, root)) { - cwd = path.join(__dirname, root); - grunt.log.ok('Setting root to ' + cwd); - } else { - grunt.fail.fatal('Setting root to ' + root + ' failed - path does not exist'); - } - } - - var files = null; - if (grunt.option('files')) { - // Accept a comma separated list of files to process. - files = grunt.option('files').split(','); - } - +module.exports = function (grunt) { // Project configuration. grunt.initConfig({ - shifter: { - options: { - recursive: true, - paths: files ? files : [cwd] - } - } + pkg: grunt.file.readJSON("package.json"), + + // Configuration for uglify task to minify JS files. + uglify: { + build: { + files: [ + { + expand: true, + cwd: "amd/src", + src: "*.js", + dest: "amd/build", + ext: ".min.js", + }, + ], + }, + }, + + // Configuration for watch task to monitor changes in JS files. + watch: { + scripts: { + files: ["amd/src/**/*.js"], + tasks: ["uglify"], + options: { + spawn: false, + }, + }, + }, }); - /** - * Shifter task. Is configured with a path to a specific file or a directory, - * in the case of a specific file it will work out the right module to be built. - * - * Note that this task runs the invidiaul shifter jobs async (becase it spawns - * so be careful to to call done(). - */ - tasks.shifter = function() { - var done = this.async(), - options = grunt.config('shifter.options'); - - // Run the shifter processes one at a time to avoid confusing output. - async.eachSeries(options.paths, function(src, filedone) { - var args = []; - args.push(path.normalize(__dirname + '/node_modules/shifter/bin/shifter')); - - // Always ignore the node_modules directory. - args.push('--excludes', 'node_modules'); - - // Determine the most appropriate options to run with based upon the current location. - if (grunt.file.isMatch('**/yui/**/*.js', src)) { - // When passed a JS file, build our containing module (this happen with - // watch). - grunt.log.debug('Shifter passed a specific JS file'); - src = path.dirname(path.dirname(src)); - options.recursive = false; - } else if (grunt.file.isMatch('**/yui/src', src)) { - // When in a src directory --walk all modules. - grunt.log.debug('In a src directory'); - args.push('--walk'); - options.recursive = false; - } else if (grunt.file.isMatch('**/yui/src/*', src)) { - // When in module, only build our module. - grunt.log.debug('In a module directory'); - options.recursive = false; - } else if (grunt.file.isMatch('**/yui/src/*/js', src)) { - // When in module src, only build our module. - grunt.log.debug('In a source directory'); - src = path.dirname(src); - options.recursive = false; - } - - // Add the stderr option if appropriate - if (grunt.option('verbose')) { - args.push('--lint-stderr'); - } - - if (grunt.option('no-color')) { - args.push('--color=false'); - } - - var execShifter = function() { - - grunt.log.ok("Running shifter on " + src); - grunt.util.spawn({ - cmd: "node", - args: args, - opts: {cwd: src, stdio: 'inherit', env: process.env} - }, function(error, result, code) { - if (code) { - grunt.fail.fatal('Shifter failed with code: ' + code); - } else { - grunt.log.ok('Shifter build complete.'); - filedone(); - } - }); - }; - - // Actually run shifter. - if (!options.recursive) { - execShifter(); - } else { - // Check that there are yui modules otherwise shifter ends with exit code 1. - if (grunt.file.expand({cwd: src}, '**/yui/src/**/*.js').length > 0) { - args.push('--recursive'); - execShifter(); - } else { - grunt.log.ok('No YUI modules to build.'); - filedone(); - } - } - }, done); - }; - - // Register JS tasks. - grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter); + // Load the plugin that provides the "uglify" task. + grunt.loadNpmTasks("grunt-contrib-uglify"); + // Load the plugin that provides the "watch" task. + grunt.loadNpmTasks("grunt-contrib-watch"); - // Register the default task. - grunt.registerTask('default', ['shifter']); + // Default task(s). + grunt.registerTask("default", ["uglify", "watch"]); }; diff --git a/README.md b/README.md index 03ad426..92e01f0 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,39 @@ For the most up to date documentation for the Panopto Student Submission plugin ## Installation -1. Download the Moodle Panopto Student Submission zip file from the [github repository](https://github.com/Panopto/Moodle-Panopto-Student-Submission/releases). We will work with Moodle.org to add this into the app directory. Until then please use our github as the official release site. +1. Download the Moodle Panopto Student Submission zip file from the [github repository](https://github.com/Panopto/Moodle-Panopto-Student-Submission/releases). You can also download this plugin from the [official moodle.org page](https://moodle.org/plugins/mod_panoptosubmission). 2. Navigate to the target Moodle site and log in as an administrator -3. Navigate to Site Administration -> Plugins -> Install Plugins +3. Navigate to ```Site Administration -> Plugins -> Install Plugins``` 4. Drag the zip file into the drag & drop box and go through the installation process. -5. An LTI Tool for the Panopto server must be configured on the Moodle site. If one does not already exist for your Panopto site please navigate to Site administration -> Plugins -> Activity modules -> External tool -> Manage preconfigured tools -6. Click Add Preconfigured tool. +5. An LTI Tool for the Panopto server must be configured on the Moodle site. If one does not already exist for your Panopto site please navigate to ```Site Administration -> Plugins -> Activity modules -> External tool -> Manage preconfigured tools``` +6. Click ```Add Preconfigured tool``` 7. Input the following information - - Tool Name: [panoptoServer] Student Submission Tool - - Tool Url: https://[panoptoServer]/Panopto/LTI/LTI.aspx - - Consumer Key:[Identity Provider instance name] - - Shared secret: [Identity Provided application key] - - Custom Parameters: - ``` - panopto_student_submission_tool=true - panopto_single_selection=true - panopto_assignment_submission_content_item=true - use_panopto_sandbox=true - - This custom parameter will give students personal folders regardless of IdP setting. - ``` + + - For LTI 1.1: + - Tool Name: ```[panoptoServer] Course Embed Tool``` + - Tool Url: ```https://[panoptoServer]/Panopto/LTI/LTI.aspx``` + - Consumer Key: ```[Identity Provider > Instance Name]``` + - Shared secret: ```[Identity Provided > Application Key]``` + - Custom Parameters: + ``` + panopto_student_submission_tool=true + panopto_single_selection=true + panopto_assignment_submission_content_item=true + use_panopto_sandbox=true + - This custom parameter will give students personal folders regardless of IdP setting. + ``` + - For LTI 1.3: + - Tool Name: ```[panoptoServer] Course Embed Tool``` + - Url: ```https://[panoptoServer]/Panopto/LTI/LTI.aspx``` + - LTI version: ```LTI 1.3``` + - Client ID: ```[Identity Provider > LTI 1.3 Client Identifier]``` + - Public key type: ```Keyset URL``` + - Public keyset: ```[Identity Provider > LTI 1.3 Tool JWKS URL]``` + - Initiate login URL: ```[Identity Provider > LTI 1.3 Tool Login URL]``` + - Redirection URI(s): ```[Identity Provider > LTI 1.3 Tool Redirection URL]``` + 8. Save the LTI Tool ## Pre-Requisites -- The [Panopto block for Moodle](https://github.com/Panopto/Moodle-2.0-plugin-for-Panopto) is installed on the Moodle site. -- The target course must be provisioned with Panopto. +- The [Panopto block for Moodle](https://github.com/Panopto/Moodle-2.0-plugin-for-Panopto) is installed on the Moodle site with at least version 2022122000. +- The target course must be provisioned with Panopto. \ No newline at end of file diff --git a/amd/build/submissionpanel.min.js b/amd/build/submissionpanel.min.js new file mode 100644 index 0000000..c3254b5 --- /dev/null +++ b/amd/build/submissionpanel.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/modal_factory","core/str"],(l,r,i,m)=>{let u=null;var e=(t,e,a)=>{Promise.all([m.get_string("select_submission","panoptosubmission"),i.create({type:i.types.DEFAULT,body:``})]).then(([t,i])=>{i.setTitle(t),i.getRoot().addClass("mod-panoptosubmission-modal-custom-size"),i.getRoot().find(".modal-dialog").addClass("mod-panoptosubmission-modal-dialog-custom").css({width:a+"px","max-width":a+"px"}),i.getRoot().find(".modal-content").addClass("mod-panoptosubmission-modal-content-custom").css({height:e+"px","max-height":e+"px"}),i.getRoot().find(".modal-body").addClass("mod-panoptosubmission-modal-body-custom"),i.show(),document.body.panoptoWindow=i,document.body.addEventListener("sessionSelected",d.bind(this),!1)}).catch(r.exception)},d=t=>{l("input[id=submit_video]").removeAttr("disabled");var i=l("iframe[id=contentframe]"),e=l("div[id=contentcontainer]"),a=l("img[id=panoptothumbnail]"),d=l("a[id=panoptothumbnaillink]"),o=l("a[id=panoptosessiontitle]"),s=new URL(t.detail.ltiViewerUrl),n=s.searchParams;n.set("course",u),n.set("custom",decodeURI(t.detail.customData)),n.set("contentUrl",t.detail.contentUrl),s.search=n.toString(),l("input[id=sessiontitle]").attr("value",t.detail.title),l("input[id=source]").attr("value",t.detail.contentUrl),l("input[id=customdata]").attr("value",t.detail.customData),l("input[id=width]").attr("value",t.detail.width),l("input[id=height]").attr("value",t.detail.height),l("input[id=thumbnailsource]").attr("value",t.detail.thumbnailUrl),l("input[id=thumbnailwidth]").attr("value",t.detail.thumbnailWidth),l("input[id=thumbnailheight]").attr("value",t.detail.thumbnailHeight),o.text(t.detail.title),o.attr("href",s.toString()),d.attr("href",s.toString()),a.attr("src",t.detail.thumbnailUrl),a.attr("width",t.detail.thumbnailWidth),a.attr("height",t.detail.thumbnailHeight),i.attr("width",t.detail.width),i.attr("height",t.detail.height),i.hasClass("session-hidden")||i.attr("src",s.toString()),e.removeClass("no-session"),m.get_string("replacevideo","panoptosubmission").done(t=>{l("#id_add_video").val(t)}).fail(r.exception),l("#id_add_video").addClass("btn-secondary"),l("#submit_video").addClass("btn-primary"),l("#id_add_video").removeClass("btn-primary"),l("#submit_video").removeClass("btn-secondary"),document.body.panoptoWindow.destroy()};return{initsubmissionpanel:t=>{"0"!==t.addvidbtnid&&"0"!==t.ltilaunchurl&&0!==t.courseid&&0!==t.height&&0!==t.width&&(u=t.courseid,l("#"+t.addvidbtnid).on("click",()=>{e(t.ltilaunchurl,t.height,t.width)}))}}}); \ No newline at end of file diff --git a/amd/src/submissionpanel.js b/amd/src/submissionpanel.js new file mode 100644 index 0000000..55f673a --- /dev/null +++ b/amd/src/submissionpanel.js @@ -0,0 +1,184 @@ +// 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 . + +/** + * AMD module for displaying an LTI launch within a AMD panel. + * + * @package mod_panoptosubmission + * @copyright Panopto 2024 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define([ + "jquery", + "core/notification", + "core/modal_factory", + "core/str", +], ($, notification, ModalFactory, str) => +{ + let courseId = null; + + var init = (params) => + { + if ( "0" === params.addvidbtnid + || "0" === params.ltilaunchurl + || 0 === params.courseid + || 0 === params.height + || 0 === params.width) + { + return; + } + + courseId = params.courseid; + + let addVideoBtn = $("#" + params.addvidbtnid); + addVideoBtn.on("click", () => + { + open_panopto_window_callback( + params.ltilaunchurl, + params.height, + params.width + ); + }); + }; + + var open_panopto_window_callback = (url, height, width) => + { + // Modal custom size class. + let modalClass = "mod-panoptosubmission-modal-custom-size"; + + // Ensure unique class names for dynamic styling. + let modalDialogClass = "mod-panoptosubmission-modal-dialog-custom"; + let modalContentClass = "mod-panoptosubmission-modal-content-custom"; + let modalBodyClass = "mod-panoptosubmission-modal-body-custom"; + let iframeClass = "mod-panoptosubmission-iframe-custom"; + + Promise.all([ + str.get_string("select_submission", "panoptosubmission"), + ModalFactory.create({ + type: ModalFactory.types.DEFAULT, + body: ``, + }), + ]) + .then(([selectText, modal]) => + { + modal.setTitle(selectText); + modal.getRoot().addClass(modalClass); + modal + .getRoot() + .find(".modal-dialog") + .addClass(modalDialogClass) + .css({ + width: `${width}px`, + "max-width": `${width}px`, + }); + modal + .getRoot() + .find(".modal-content") + .addClass(modalContentClass) + .css({ + height: `${height}px`, + "max-height": `${height}px`, + }); + modal + .getRoot() + .find(".modal-body") + .addClass(modalBodyClass); + modal.show(); + + document.body.panoptoWindow = modal; + document.body.addEventListener( + "sessionSelected", + close_popup_callback.bind(this), + false + ); + }).catch(notification.exception); + }; + + var close_popup_callback = (closeEvent) => + { + $("input[id=submit_video]").removeAttr("disabled"); + + let iFrameNode = $("iframe[id=contentframe]"), + contentWrapperNode = $("div[id=contentcontainer]"), + thumbnailNode = $("img[id=panoptothumbnail]"), + thumbnailLinkNode = $("a[id=panoptothumbnaillink]"), + titleNode = $("a[id=panoptosessiontitle]"), + newSubmissionSource = new URL(closeEvent.detail.ltiViewerUrl), + searchParams = newSubmissionSource.searchParams; + + searchParams.set("course", courseId); + searchParams.set("custom", decodeURI(closeEvent.detail.customData)); + searchParams.set("contentUrl", closeEvent.detail.contentUrl); + + newSubmissionSource.search = searchParams.toString(); + + $("input[id=sessiontitle]").attr("value", closeEvent.detail.title); + $("input[id=source]").attr("value", closeEvent.detail.contentUrl); + $("input[id=customdata]").attr( + "value", + closeEvent.detail.customData + ); + $("input[id=width]").attr("value", closeEvent.detail.width); + $("input[id=height]").attr("value", closeEvent.detail.height); + $("input[id=thumbnailsource]").attr( + "value", + closeEvent.detail.thumbnailUrl + ); + $("input[id=thumbnailwidth]").attr( + "value", + closeEvent.detail.thumbnailWidth + ); + $("input[id=thumbnailheight]").attr( + "value", + closeEvent.detail.thumbnailHeight + ); + + titleNode.text(closeEvent.detail.title); + titleNode.attr("href", newSubmissionSource.toString()); + + thumbnailLinkNode.attr("href", newSubmissionSource.toString()); + thumbnailNode.attr("src", closeEvent.detail.thumbnailUrl); + thumbnailNode.attr("width", closeEvent.detail.thumbnailWidth); + thumbnailNode.attr("height", closeEvent.detail.thumbnailHeight); + + iFrameNode.attr("width", closeEvent.detail.width); + iFrameNode.attr("height", closeEvent.detail.height); + + if (!iFrameNode.hasClass("session-hidden")) + { + iFrameNode.attr("src", newSubmissionSource.toString()); + } + + contentWrapperNode.removeClass("no-session"); + + str.get_string("replacevideo", "panoptosubmission") + .done((replaceText) => + { + $("#id_add_video").val(replaceText); + }) + .fail(notification.exception); + + $("#id_add_video").addClass("btn-secondary"); + $("#submit_video").addClass("btn-primary"); + $("#id_add_video").removeClass("btn-primary"); + $("#submit_video").removeClass("btn-secondary"); + document.body.panoptoWindow.destroy(); + }; + + return { + initsubmissionpanel: init, + }; +}); diff --git a/backup/moodle2/backup_panoptosubmission_stepslib.php b/backup/moodle2/backup_panoptosubmission_stepslib.php index e8e3247..11e3a56 100644 --- a/backup/moodle2/backup_panoptosubmission_stepslib.php +++ b/backup/moodle2/backup_panoptosubmission_stepslib.php @@ -40,7 +40,7 @@ protected function define_structure() { $userinfo = $this->get_setting_value('userinfo'); // Define each element separated. - $columns = array( + $columns = [ 'course', 'name', 'intro', @@ -55,13 +55,13 @@ protected function define_structure() { 'sendstudentnotifications', 'grade', 'timecreated', - 'timemodified' - ); - $panoptosubmission = new backup_nested_element('panoptosubmission', array('id'), $columns); + 'timemodified', + ]; + $panoptosubmission = new backup_nested_element('panoptosubmission', ['id'], $columns); $issues = new backup_nested_element('submissions'); - $columns = array( + $columns = [ 'userid', 'entry_id', 'source', @@ -77,16 +77,16 @@ protected function define_structure() { 'mailed', 'timemarked', 'timecreated', - 'timemodified' - ); - $issue = new backup_nested_element('submission', array('id'), $columns); + 'timemodified', + ]; + $issue = new backup_nested_element('submission', ['id'], $columns); $panoptosubmission->add_child($issues); $issues->add_child($issue); - $panoptosubmission->set_source_table('panoptosubmission', array('id' => backup::VAR_ACTIVITYID)); + $panoptosubmission->set_source_table('panoptosubmission', ['id' => backup::VAR_ACTIVITYID]); if ($userinfo) { - $issue->set_source_table('panoptosubmission_submission', array('panactivityid' => backup::VAR_PARENTID)); + $issue->set_source_table('panoptosubmission_submission', ['panactivityid' => backup::VAR_PARENTID]); } $issue->annotate_ids('user', 'userid'); diff --git a/backup/moodle2/restore_panoptosubmission_activity_task.class.php b/backup/moodle2/restore_panoptosubmission_activity_task.class.php index 3dd47a3..966fef2 100644 --- a/backup/moodle2/restore_panoptosubmission_activity_task.class.php +++ b/backup/moodle2/restore_panoptosubmission_activity_task.class.php @@ -54,9 +54,9 @@ protected function define_my_steps() { * Decode contents for restore */ public static function define_decode_contents() { - $contents = array(); + $contents = []; - $contents[] = new restore_decode_content('panoptosubmission', array('intro'), 'panoptosubmission'); + $contents[] = new restore_decode_content('panoptosubmission', ['intro'], 'panoptosubmission'); return $contents; } @@ -65,7 +65,7 @@ public static function define_decode_contents() { * Decode rules for restore */ public static function define_decode_rules() { - $rules = array(); + $rules = []; $rules[] = new restore_decode_rule('PANOPTOSUBMISSIONVIEWBYID', '/mod/panoptosubmission/view.php?id=$1', 'course_module'); $rules[] = new restore_decode_rule('PANOPTOSUBMISSIONINDEX', '/mod/panoptosubmission/index.php?id=$1', 'course'); @@ -78,7 +78,7 @@ public static function define_decode_rules() { * log rules for restore */ public static function define_restore_log_rules() { - $rules = array(); + $rules = []; $rules[] = new restore_log_rule('panoptosubmission', 'add', 'view.php?id={course_module}', '{panoptosubmission}'); $rules[] = new restore_log_rule('panoptosubmission', 'update', 'view.php?id={course_module}', '{panoptosubmission}'); @@ -91,7 +91,7 @@ public static function define_restore_log_rules() { * Log rules for course during restore */ public static function define_restore_log_rules_for_course() { - $rules = array(); + $rules = []; $rules[] = new restore_log_rule('panoptosubmission', 'view all', 'index.php?id={course}', null); return $rules; diff --git a/backup/moodle2/restore_panoptosubmission_stepslib.php b/backup/moodle2/restore_panoptosubmission_stepslib.php index dc43ae2..cae5850 100644 --- a/backup/moodle2/restore_panoptosubmission_stepslib.php +++ b/backup/moodle2/restore_panoptosubmission_stepslib.php @@ -36,7 +36,7 @@ class restore_panoptosubmission_activity_structure_step extends restore_activity * @return object The structure object */ protected function define_structure() { - $paths = array(); + $paths = []; $userinfo = $this->get_setting_value('userinfo'); $paths[] = new restore_path_element('panoptosubmission', '/activity/panoptosubmission'); diff --git a/classes/event/assignment_details_viewed.php b/classes/event/assignment_details_viewed.php index 1ea696f..7f20323 100644 --- a/classes/event/assignment_details_viewed.php +++ b/classes/event/assignment_details_viewed.php @@ -65,15 +65,6 @@ public function get_description() { * @return string a url to the grade submission page */ public function get_url() { - return new \moodle_url('/mod/panoptosubmission/view.php', array('cmid' => $this->contextinstanceid)); - } - - /** - * returns an array of legacy log data - * @return array a array used to store the legacy log data - */ - public function get_legacy_logdata() { - return array($this->courseid, 'panoptosubmission', 'view assignment details', - $this->get_url(), $this->objectid, $this->contextinstanceid); + return new \moodle_url('/mod/panoptosubmission/view.php', ['id' => $this->contextinstanceid]); } } diff --git a/classes/event/assignment_submitted.php b/classes/event/assignment_submitted.php index 8457ea5..5fa8e89 100644 --- a/classes/event/assignment_submitted.php +++ b/classes/event/assignment_submitted.php @@ -65,15 +65,6 @@ public function get_description() { * @return string a url to the grade submission page */ public function get_url() { - return new \moodle_url('/mod/panoptosubmission/view.php', array('cmid' => $this->contextinstanceid)); - } - - /** - * returns an array of legacy log data - * @return array a array used to store the legacy log data - */ - public function get_legacy_logdata() { - return array($this->courseid, 'panoptosubmission', 'submit', - $this->get_url(), $this->objectid, $this->contextinstanceid); + return new \moodle_url('/mod/panoptosubmission/view.php', ['id' => $this->contextinstanceid]); } } diff --git a/classes/event/grade_submissions_page_viewed.php b/classes/event/grade_submissions_page_viewed.php index c00c05b..d5d84d2 100644 --- a/classes/event/grade_submissions_page_viewed.php +++ b/classes/event/grade_submissions_page_viewed.php @@ -65,15 +65,6 @@ public function get_description() { * @return string a url to the grade submission page */ public function get_url() { - return new \moodle_url('/mod/panoptosubmission/grade_submissions.php', array('cmid' => $this->contextinstanceid)); - } - - /** - * returns an array of legacy log data - * @return array a array used to store the legacy log data - */ - public function get_legacy_logdata() { - return array($this->courseid, 'panoptosumission', 'view submissions page', - $this->get_url(), $this->objectid, $this->contextinstanceid); + return new \moodle_url('/mod/panoptosubmission/grade_submissions.php', ['id' => $this->contextinstanceid]); } } diff --git a/classes/event/grades_updated.php b/classes/event/grades_updated.php index 097259e..b33cf83 100644 --- a/classes/event/grades_updated.php +++ b/classes/event/grades_updated.php @@ -64,15 +64,6 @@ public function get_description() { * @return string a url to the grade submission page */ public function get_url() { - return new \moodle_url('/mod/panoptosubmission/grade_submissions.php', array('cmid' => $this->contextinstanceid)); - } - - /** - * returns an array of legacy log data - * @return array a array used to store the legacy log data - */ - public function get_legacy_logdata() { - return array($this->courseid, 'panoptosubmission', 'update grades', - $this->get_url(), $this->contextinstanceid); + return new \moodle_url('/mod/panoptosubmission/grade_submissions.php', ['id' => $this->contextinstanceid]); } } diff --git a/classes/event/single_submission_page_viewed.php b/classes/event/single_submission_page_viewed.php index 1707f4c..cbca73b 100644 --- a/classes/event/single_submission_page_viewed.php +++ b/classes/event/single_submission_page_viewed.php @@ -65,15 +65,6 @@ public function get_description() { * @return string a url to the grade submission page */ public function get_url() { - return new \moodle_url('/mod/panoptosubmission/single_submission.php', array('cmid' => $this->contextinstanceid)); - } - - /** - * returns an array of legacy log data - * @return array a array used to store the legacy log data - */ - public function get_legacy_logdata() { - return array($this->courseid, 'panoptosubmission', 'view submission page', - $this->get_url(), $this->objectid, $this->contextinstanceid); + return new \moodle_url('/mod/panoptosubmission/single_submission.php', ['id' => $this->contextinstanceid]); } } diff --git a/classes/grades/gradeitems.php b/classes/grades/gradeitems.php index 310fdd4..c7eb738 100644 --- a/classes/grades/gradeitems.php +++ b/classes/grades/gradeitems.php @@ -26,8 +26,8 @@ namespace mod_panoptosubmission\grades; -use \core_grades\local\gradeitem\itemnumber_mapping; -use \core_grades\local\gradeitem\advancedgrading_mapping; +use core_grades\local\gradeitem\itemnumber_mapping; +use core_grades\local\gradeitem\advancedgrading_mapping; /** * Grade item mappings for the activity. diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index 7fee0a7..89748ea 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -43,14 +43,14 @@ class provider implements \core_privacy\local\metadata\provider, * @param collection $collection the object used to store and return the privacy definitions * @return returns the collection that includes the new privacy definitions */ - public static function get_metadata(collection $collection) : collection { + public static function get_metadata(collection $collection): collection { $collection->add_external_location_link( 'panoptosubmission_submission', [ 'userid' => 'privacy:metadata:panoptosubmission_submission:userid', 'username' => 'privacy:metadata:panoptosubmission_submission:username', - 'email' => 'privacy:metadata:panoptosubmission_submission:email' + 'email' => 'privacy:metadata:panoptosubmission_submission:email', ], 'privacy:metadata:panoptosubmission_submission' ); @@ -68,7 +68,7 @@ public static function get_metadata(collection $collection) : collection { 'mailed' => 'privacy:metadata:panoptosubmission_submission:mailed', 'timemarked' => 'privacy:metadata:panoptosubmission_submission:timemarked', 'timecreated' => 'privacy:metadata:panoptosubmission_submission:timecreated', - 'timemodified' => 'privacy:metadata:panoptosubmission_submission:timemodified' + 'timemodified' => 'privacy:metadata:panoptosubmission_submission:timemodified', ], 'privacy:metadata:panoptosubmission_submission' ); @@ -101,7 +101,7 @@ public static function export_user_preferences(int $userid) { 'panoptosubmission_group_filter' => get_string( 'privacy:metadata:panoptosubmissiongroupfilter', 'mod_panoptosubmission'), 'panoptosubmission_perpage' => get_string('privacy:metadata:panoptosubmissionperpage', 'mod_panoptosubmission'), - 'panoptosubmission_quickgrade' => get_string('privacy:metadata:panoptosubmissionquickgrade', 'mod_panoptosubmission') + 'panoptosubmission_quickgrade' => get_string('privacy:metadata:panoptosubmissionquickgrade', 'mod_panoptosubmission'), ]; foreach ($assignmentpreferences as $key => $preferencestring) { @@ -120,7 +120,7 @@ public static function export_user_preferences(int $userid) { * @param int $userid The user to search. * @return contextlist $contextlist The list of contexts used in this plugin. */ - public static function get_contexts_for_userid(int $userid) : contextlist { + public static function get_contexts_for_userid(int $userid): contextlist { $contextlist = new \core_privacy\local\request\contextlist(); $sql = "SELECT DISTINCT ctx.id FROM {context} ctx " . @@ -135,7 +135,7 @@ public static function get_contexts_for_userid(int $userid) : contextlist { 'modulename' => 'panoptosubmission', 'contextlevel' => CONTEXT_MODULE, 'userid' => $userid, - 'teacher' => $userid + 'teacher' => $userid, ]; $contextlist->add_from_sql($sql, $params); @@ -158,7 +158,7 @@ public static function get_users_in_context(userlist $userlist) { $params = [ 'modulename' => 'panoptosubmission', 'contextlevel' => CONTEXT_MODULE, - 'contextid' => $context->id + 'contextid' => $context->id, ]; $sql = "SELECT s.userid FROM {panoptosubmission_submission} s " . @@ -218,16 +218,14 @@ public static function export_user_data(approved_contextlist $contextlist) { $controller = $gradingmanager->get_active_controller(); foreach ($submissionsdata as $submissiondata) { // Default subcontext path to export assignment submissions submitted by the user. - $subcontexts = [ - get_string('privacy:submissionpath', 'mod_panoptosubmission') - ]; + $subcontexts = [get_string('privacy:submissionpath', 'mod_panoptosubmission')]; if ($teacher == true) { if ($submissiondata->teacher == $user->id) { // Export panoptosubmission submissions that have been marked by the user. $subcontexts = [ get_string('privacy:markedsubmissionspath', 'mod_panoptosubmission'), - transform::user($submissiondata->userid) + transform::user($submissiondata->userid), ]; } } @@ -271,6 +269,10 @@ public static function delete_data_for_all_users_in_context(\context $context) { if (isset($controller)) { \core_grading\privacy\provider::delete_instance_data($context); } + + // Delete all panoptosubmission files. + $fs = get_file_storage(); + $fs->delete_area_files($context->id, STUDENTSUBMISSION_FILE_COMPONENT, STUDENTSUBMISSION_FILE_FILEAREA); } /** @@ -363,7 +365,7 @@ protected static function get_panoptosubmission_submissions_by_contextlist($cont $params = [ 'contextlevel' => CONTEXT_MODULE, 'modulename' => 'panoptosubmission', - 'userid' => $userid + 'userid' => $userid, ]; $sql = "SELECT s.id as id, " . @@ -401,7 +403,7 @@ protected static function get_panoptosubmission_by_context($context) { $params = [ 'modulename' => 'panoptosubmission', 'contextmodule' => CONTEXT_MODULE, - 'contextid' => $context->id + 'contextid' => $context->id, ]; $sql = "SELECT a.id, " . @@ -432,7 +434,7 @@ protected static function get_panoptosubmission_output($panoptosubmissiondata) { 'name' => $panoptosubmissiondata->name, 'intro' => $panoptosubmissiondata->intro, 'grade' => $panoptosubmissiondata->grade, - 'timemodified' => transform::datetime($panoptosubmissiondata->timemodified) + 'timemodified' => transform::datetime($panoptosubmissiondata->timemodified), ]; if ($panoptosubmissiondata->timeavailable != 0) { @@ -463,7 +465,7 @@ protected static function has_marked_panoptosubmission_submissions($panoptosubmi $params = [ 'panactivityid' => $panoptosubmissionid, - 'teacher' => $userid + 'teacher' => $userid, ]; $sql = "SELECT count(s.id) as nomarked " . @@ -491,7 +493,7 @@ protected static function get_panoptosubmission_submissions_by_panoptosubmission $params = [ 'panactivityid' => $panoptosubmissionid, - 'userid' => $userid + 'userid' => $userid, ]; $sql = "SELECT s.id as id, " . @@ -530,7 +532,7 @@ protected static function get_panoptosubmission_submission_output($submissiondat 'source' => $submissiondata->source, 'grade' => $submissiondata->grade, 'submissioncomment' => $submissiondata->submissioncomment, - 'teacher' => transform::user($submissiondata->teacher) + 'teacher' => transform::user($submissiondata->teacher), ]; if ($submissiondata->timecreated != 0) { diff --git a/classes/renderable/panoptosubmission_course_index_summary.php b/classes/renderable/panoptosubmission_course_index_summary.php index 9bf1fd4..17df205 100644 --- a/classes/renderable/panoptosubmission_course_index_summary.php +++ b/classes/renderable/panoptosubmission_course_index_summary.php @@ -27,8 +27,8 @@ */ class panoptosubmission_course_index_summary implements renderable { /** @var array activities A list of course modules and their status or submission counts depending on the user capabilities */ - public $activities = array(); - /** @var boolean usesections True if the parent course supports sections */ + public $activities = []; + /** @var bool usesections True if the parent course supports sections */ public $usesections = false; /** @var string courseformat The current course format name */ public $courseformatname = ''; @@ -45,7 +45,7 @@ public function __construct($usesections, $courseformatname) { } /** - * Adds information for an activity on the acitivity index page + * Adds information for an activity on the activity index page * * @param int $cmid The course module id of the activity * @param string $cmname The name of the activity @@ -56,13 +56,13 @@ public function __construct($usesections, $courseformatname) { * @param string $gradeinfo The current users grade if the activity has been graded. */ public function add_assign_info($cmid, $cmname, $sectionname, $timedue, $submissioninfo, $gradeinfo) { - $this->activities[] = array( + $this->activities[] = [ 'cmid' => $cmid, 'cmname' => $cmname, 'sectionname' => $sectionname, 'timedue' => $timedue, 'submissioninfo' => $submissioninfo, - 'gradeinfo' => $gradeinfo - ); + 'gradeinfo' => $gradeinfo, + ]; } } diff --git a/classes/renderable/panoptosubmission_grading_summary.php b/classes/renderable/panoptosubmission_grading_summary.php index 4356f36..7572b03 100644 --- a/classes/renderable/panoptosubmission_grading_summary.php +++ b/classes/renderable/panoptosubmission_grading_summary.php @@ -46,11 +46,11 @@ class panoptosubmission_grading_summary implements renderable { public $timelimit = 0; /** @var int coursemoduleid - The submission course module id */ public $coursemoduleid = 0; - /** @var boolean relativedatesmode - Is the course a relative dates mode course or not */ + /** @var bool relativedatesmode - Is the course a relative dates mode course or not */ public $courserelativedatesmode = false; /** @var int coursestartdate - start date of the course as a unix timestamp*/ public $coursestartdate; - /** @var boolean isvisible - Is the submission's context module visible to students? */ + /** @var bool isvisible - Is the submission's context module visible to students? */ public $isvisible = true; /** diff --git a/contentitem.php b/contentitem.php index 848d739..87b79c4 100644 --- a/contentitem.php +++ b/contentitem.php @@ -78,7 +78,7 @@ $returnurlparams = [ 'course' => $course->id, 'id' => $toolid, - 'sesskey' => sesskey() + 'sesskey' => sesskey(), ]; $returnurl = new \moodle_url(STUDENT_SUBMISSION_PATH, $returnurlparams); diff --git a/contentitem_return.php b/contentitem_return.php index 21ad092..1ea687a 100644 --- a/contentitem_return.php +++ b/contentitem_return.php @@ -95,7 +95,7 @@ $title = ""; $itemtitle = $contentitems->{'@graph'}[0]->title; if (!empty($itemtitle)) { - $invalidcharacters = array("$", "%", "#", "<", ">"); + $invalidcharacters = ["$", "%", "#", "<", ">"]; $cleantitle = str_replace($invalidcharacters, "", $itemtitle); $title = is_string($cleantitle) ? $cleantitle : $title; } @@ -127,32 +127,33 @@ ?>