mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-09 06:27:21 -04:00
a
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Hook listener for filter_mediacms navigation hooks (Moodle 4.3+)
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace filter_mediacms;
|
||||
|
||||
/**
|
||||
* Extends the primary (top) navigation bar with a My Media link.
|
||||
*/
|
||||
class hook_listener {
|
||||
|
||||
/**
|
||||
* Called by the \core\hook\navigation\primary_extend hook.
|
||||
* Adds the My Media link to the primary nav bar when placement = 'top'.
|
||||
*/
|
||||
public static function extend_primary_navigation(
|
||||
\core\hook\navigation\primary_extend $hook
|
||||
): void {
|
||||
$placement = get_config('filter_mediacms', 'mymedia_placement');
|
||||
if ($placement !== 'top') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = new \moodle_url('/filter/mediacms/my_media.php');
|
||||
$node = \navigation_node::create(
|
||||
get_string('mymedia', 'filter_mediacms'),
|
||||
$url,
|
||||
\navigation_node::TYPE_CUSTOM,
|
||||
null,
|
||||
'mediacms_mymedia',
|
||||
new \pix_icon('i/media', '')
|
||||
);
|
||||
|
||||
$primarynav = $hook->get_primarynav();
|
||||
if ($primarynav === null) {
|
||||
return;
|
||||
}
|
||||
$primarynav->add_node($node);
|
||||
}
|
||||
}
|
||||
13
lms-plugins/mediacms-moodle/filter/mediacms/db/hooks.php
Normal file
13
lms-plugins/mediacms-moodle/filter/mediacms/db/hooks.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* Hook registrations for filter_mediacms.
|
||||
* Primary navigation is handled via extend_navigation() in lib.php instead.
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$callbacks = [];
|
||||
@@ -17,3 +17,13 @@ $string['iframeheight_desc'] = 'Default height for embedded videos (pixels).';
|
||||
$string['enableautoconvert'] = 'Auto-convert URLs';
|
||||
$string['enableautoconvert_desc'] = 'Automatically convert MediaCMS URLs (e.g., /view?m=xyz) in text to embedded players.';
|
||||
$string['privacy:metadata'] = 'The MediaCMS filter does not store any personal data.';
|
||||
|
||||
// My Media page.
|
||||
$string['mymedia'] = 'My Media';
|
||||
$string['mymedia_placement'] = 'My Media link placement';
|
||||
$string['mymedia_placement_desc'] = 'Where to display the My Media link in the Moodle interface.';
|
||||
$string['mymedia_placement_top'] = 'Top navigation';
|
||||
$string['mymedia_placement_user'] = 'User navigation';
|
||||
$string['notconfigured'] = 'MediaCMS is not fully configured. Please set the MediaCMS URL and LTI Tool in Site Administration → Plugins → Filters → MediaCMS.';
|
||||
$string['ltitoolnotfound'] = 'The configured LTI tool could not be found. Please check the MediaCMS filter settings.';
|
||||
$string['cannotcreatedummyactivity'] = 'Could not create the MediaCMS launcher activity. Please check course permissions.';
|
||||
|
||||
@@ -11,65 +11,10 @@ require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/lib.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
require_once($CFG->dirroot . '/course/modlib.php');
|
||||
require_once(__DIR__ . '/locallib.php');
|
||||
|
||||
global $SITE, $DB, $PAGE, $OUTPUT, $CFG;
|
||||
|
||||
/**
|
||||
* Find first LTI activity for the MediaCMS tool, or create dummy if none exists
|
||||
*/
|
||||
function filter_mediacms_get_dummy_activity($courseid, $typeid) {
|
||||
global $DB;
|
||||
|
||||
// Find any existing LTI activity with this tool
|
||||
$sql = "SELECT cm.id
|
||||
FROM {course_modules} cm
|
||||
JOIN {modules} m ON m.id = cm.module
|
||||
JOIN {lti} lti ON lti.id = cm.instance
|
||||
WHERE cm.course = :courseid
|
||||
AND m.name = 'lti'
|
||||
AND lti.typeid = :typeid
|
||||
AND cm.deletioninprogress = 0
|
||||
LIMIT 1";
|
||||
|
||||
$existing = $DB->get_record_sql($sql, ['courseid' => $courseid, 'typeid' => $typeid]);
|
||||
if ($existing) {
|
||||
// Ensure it's accessible (fix if created with visible=0)
|
||||
$cm = get_coursemodule_from_id('lti', $existing->id, 0, false, IGNORE_MISSING);
|
||||
if ($cm && !$cm->visible) {
|
||||
set_coursemodule_visible($existing->id, 1);
|
||||
}
|
||||
return $existing->id;
|
||||
}
|
||||
|
||||
// No existing activity - create dummy in stealth mode (accessible but completely hidden)
|
||||
$moduleinfo = new stdClass();
|
||||
$moduleinfo->course = $courseid;
|
||||
$moduleinfo->module = $DB->get_field('modules', 'id', ['name' => 'lti']);
|
||||
$moduleinfo->modulename = 'lti';
|
||||
$moduleinfo->section = 0;
|
||||
$moduleinfo->visible = 1; // Accessible to all
|
||||
$moduleinfo->visibleoncoursepage = 0; // Hidden from course page
|
||||
$moduleinfo->availability = null; // No restrictions
|
||||
$moduleinfo->showdescription = 0; // Don't show description
|
||||
$moduleinfo->name = 'MediaCMS Filter Launcher';
|
||||
$moduleinfo->intro = ''; // Empty intro
|
||||
$moduleinfo->introformat = FORMAT_HTML;
|
||||
$moduleinfo->typeid = $typeid;
|
||||
$moduleinfo->instructorchoiceacceptgrades = 0;
|
||||
$moduleinfo->grade = 0;
|
||||
$moduleinfo->instructorchoicesendname = 1;
|
||||
$moduleinfo->instructorchoicesendemailaddr = 1;
|
||||
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
|
||||
$moduleinfo->instructorcustomparameters = '';
|
||||
|
||||
$result = add_moduleinfo($moduleinfo, get_course($courseid));
|
||||
|
||||
// Additionally hide from activity navigation by setting it as orphaned
|
||||
set_coursemodule_visible($result->coursemodule, 1, 0); // visible but not on course page
|
||||
|
||||
return $result->coursemodule;
|
||||
}
|
||||
|
||||
require_login();
|
||||
|
||||
$mediatoken = required_param('token', PARAM_ALPHANUMEXT);
|
||||
|
||||
72
lms-plugins/mediacms-moodle/filter/mediacms/lib.php
Normal file
72
lms-plugins/mediacms-moodle/filter/mediacms/lib.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Navigation callbacks for filter_mediacms
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Add My Media to the global / flat navigation (nav drawer).
|
||||
* Fires on every page when placement is set to 'top'.
|
||||
* In Moodle 4.x Boost the nav drawer is opened via the hamburger icon
|
||||
* and the node appears as a top-level item alongside Home / My courses.
|
||||
*/
|
||||
function filter_mediacms_extend_navigation(global_navigation $navigation): void {
|
||||
$placement = get_config('filter_mediacms', 'mymedia_placement');
|
||||
if ($placement !== 'top') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = new moodle_url('/filter/mediacms/my_media.php');
|
||||
$node = navigation_node::create(
|
||||
get_string('mymedia', 'filter_mediacms'),
|
||||
$url,
|
||||
navigation_node::TYPE_CUSTOM,
|
||||
null,
|
||||
'mediacms_mymedia',
|
||||
new pix_icon('i/media', '')
|
||||
);
|
||||
// showinflatnavigation = true makes it visible in the Boost nav drawer.
|
||||
$node->showinflatnavigation = true;
|
||||
$navigation->add_node($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add My Media to the user account / settings navigation.
|
||||
* Fires when placement is set to 'user'.
|
||||
* In Moodle 4.x Boost this section is reachable via avatar → Preferences.
|
||||
*/
|
||||
function filter_mediacms_extend_navigation_user_settings(
|
||||
navigation_node $navigation,
|
||||
stdClass $user,
|
||||
context_user $usercontext,
|
||||
stdClass $course,
|
||||
context_course $coursecontext
|
||||
): void {
|
||||
$placement = get_config('filter_mediacms', 'mymedia_placement');
|
||||
if ($placement !== 'user') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = new moodle_url('/filter/mediacms/my_media.php');
|
||||
$navigation->add(
|
||||
get_string('mymedia', 'filter_mediacms'),
|
||||
$url,
|
||||
navigation_node::TYPE_SETTING,
|
||||
null,
|
||||
'mediacms_mymedia',
|
||||
new pix_icon('i/media', '')
|
||||
);
|
||||
}
|
||||
67
lms-plugins/mediacms-moodle/filter/mediacms/locallib.php
Normal file
67
lms-plugins/mediacms-moodle/filter/mediacms/locallib.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* Local helper functions for filter_mediacms
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Find the first LTI activity for the MediaCMS tool in a course, or create a
|
||||
* hidden dummy one if none exists.
|
||||
*
|
||||
* @param int $courseid
|
||||
* @param int $typeid LTI tool type ID
|
||||
* @return int course-module ID
|
||||
*/
|
||||
function filter_mediacms_get_dummy_activity($courseid, $typeid) {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT cm.id
|
||||
FROM {course_modules} cm
|
||||
JOIN {modules} m ON m.id = cm.module
|
||||
JOIN {lti} lti ON lti.id = cm.instance
|
||||
WHERE cm.course = :courseid
|
||||
AND m.name = 'lti'
|
||||
AND lti.typeid = :typeid
|
||||
AND cm.deletioninprogress = 0
|
||||
LIMIT 1";
|
||||
|
||||
$existing = $DB->get_record_sql($sql, ['courseid' => $courseid, 'typeid' => $typeid]);
|
||||
if ($existing) {
|
||||
$cm = get_coursemodule_from_id('lti', $existing->id, 0, false, IGNORE_MISSING);
|
||||
if ($cm && !$cm->visible) {
|
||||
set_coursemodule_visible($existing->id, 1);
|
||||
}
|
||||
return $existing->id;
|
||||
}
|
||||
|
||||
// Create a stealth dummy activity (accessible but hidden from the course page).
|
||||
$moduleinfo = new stdClass();
|
||||
$moduleinfo->course = $courseid;
|
||||
$moduleinfo->module = $DB->get_field('modules', 'id', ['name' => 'lti']);
|
||||
$moduleinfo->modulename = 'lti';
|
||||
$moduleinfo->section = 0;
|
||||
$moduleinfo->visible = 1;
|
||||
$moduleinfo->visibleoncoursepage = 0;
|
||||
$moduleinfo->availability = null;
|
||||
$moduleinfo->showdescription = 0;
|
||||
$moduleinfo->name = 'MediaCMS Filter Launcher';
|
||||
$moduleinfo->intro = '';
|
||||
$moduleinfo->introformat = FORMAT_HTML;
|
||||
$moduleinfo->typeid = $typeid;
|
||||
$moduleinfo->instructorchoiceacceptgrades = 0;
|
||||
$moduleinfo->grade = 0;
|
||||
$moduleinfo->instructorchoicesendname = 1;
|
||||
$moduleinfo->instructorchoicesendemailaddr = 1;
|
||||
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
|
||||
$moduleinfo->instructorcustomparameters = '';
|
||||
|
||||
$result = add_moduleinfo($moduleinfo, get_course($courseid));
|
||||
set_coursemodule_visible($result->coursemodule, 1, 0);
|
||||
|
||||
return $result->coursemodule;
|
||||
}
|
||||
78
lms-plugins/mediacms-moodle/filter/mediacms/lti_launch.php
Normal file
78
lms-plugins/mediacms-moodle/filter/mediacms/lti_launch.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* My Media LTI launch page — runs inside the iframe from my_media.php.
|
||||
*
|
||||
* Builds custom_publishdata (enrolled courses + roles) and initiates
|
||||
* the LTI 1.3 OIDC login flow, outputting the auto-submit form directly.
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/lib.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
require_once($CFG->dirroot . '/course/modlib.php');
|
||||
require_once(__DIR__ . '/locallib.php');
|
||||
|
||||
global $SITE, $DB, $CFG, $USER;
|
||||
|
||||
require_login();
|
||||
|
||||
$mediacmsurl = get_config('filter_mediacms', 'mediacmsurl');
|
||||
$ltitoolid = get_config('filter_mediacms', 'ltitoolid');
|
||||
|
||||
if (empty($mediacmsurl) || empty($ltitoolid)) {
|
||||
throw new moodle_exception('notconfigured', 'filter_mediacms');
|
||||
}
|
||||
|
||||
$type = $DB->get_record('lti_types', ['id' => $ltitoolid]);
|
||||
if (!$type) {
|
||||
throw new moodle_exception('ltitoolnotfound', 'filter_mediacms');
|
||||
}
|
||||
|
||||
// Build custom_publishdata: all courses the user is enrolled in + role.
|
||||
$enrolled_courses = enrol_get_users_courses($USER->id, true, ['id', 'shortname', 'fullname']);
|
||||
|
||||
$publish_data = [];
|
||||
foreach ($enrolled_courses as $enrolled_course) {
|
||||
if ((int)$enrolled_course->id === SITEID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$course_context = context_course::instance($enrolled_course->id);
|
||||
$roles = get_user_roles($course_context, $USER->id, false);
|
||||
|
||||
$role_shortname = 'student';
|
||||
if (!empty($roles)) {
|
||||
$role = reset($roles);
|
||||
$role_shortname = $role->shortname;
|
||||
}
|
||||
|
||||
$publish_data[] = [
|
||||
'id' => (int)$enrolled_course->id,
|
||||
'shortname' => $enrolled_course->shortname,
|
||||
'fullname' => $enrolled_course->fullname,
|
||||
'role' => $role_shortname,
|
||||
];
|
||||
}
|
||||
|
||||
$publishdata_b64 = base64_encode(json_encode($publish_data));
|
||||
|
||||
try {
|
||||
$dummy_cmid = filter_mediacms_get_dummy_activity(SITEID, $type->id);
|
||||
} catch (Exception $e) {
|
||||
throw new moodle_exception('cannotcreatedummyactivity', 'filter_mediacms');
|
||||
}
|
||||
|
||||
$cm = get_coursemodule_from_id('lti', $dummy_cmid, 0, false, MUST_EXIST);
|
||||
$instance = $DB->get_record('lti', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
|
||||
$instance->instructorcustomparameters = 'publishdata=' . $publishdata_b64;
|
||||
$instance->name = 'MediaCMS My Media';
|
||||
|
||||
$typeconfig = lti_get_type_type_config($type->id);
|
||||
$content = lti_initiate_login($SITE->id, $dummy_cmid, $instance, $typeconfig, null, $instance->name);
|
||||
|
||||
echo $content;
|
||||
38
lms-plugins/mediacms-moodle/filter/mediacms/my_media.php
Normal file
38
lms-plugins/mediacms-moodle/filter/mediacms/my_media.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* My Media page — renders the Moodle shell with an LTI iframe.
|
||||
*
|
||||
* @package filter_mediacms
|
||||
* @copyright 2026 MediaCMS
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
|
||||
global $SITE, $PAGE, $OUTPUT, $USER;
|
||||
|
||||
require_login();
|
||||
|
||||
$context = context_system::instance();
|
||||
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_url(new moodle_url('/filter/mediacms/my_media.php'));
|
||||
$PAGE->set_course($SITE);
|
||||
$PAGE->set_pagelayout('mydashboard');
|
||||
$PAGE->set_title(get_string('mymedia', 'filter_mediacms'));
|
||||
$PAGE->set_heading(get_string('mymedia', 'filter_mediacms'));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$attr = [
|
||||
'id' => 'contentframe',
|
||||
'src' => (new moodle_url('/filter/mediacms/lti_launch.php'))->out(false),
|
||||
'width' => '100%',
|
||||
'height' => '600px',
|
||||
'allowfullscreen' => 'true',
|
||||
'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *;',
|
||||
'style' => 'border:none;display:block;',
|
||||
];
|
||||
echo html_writer::tag('iframe', '', $attr);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
@@ -39,4 +39,16 @@ if ($ADMIN->fulltree) {
|
||||
0,
|
||||
$ltioptions
|
||||
));
|
||||
|
||||
// My Media link placement.
|
||||
$settings->add(new admin_setting_configselect(
|
||||
'filter_mediacms/mymedia_placement',
|
||||
get_string('mymedia_placement', 'filter_mediacms'),
|
||||
get_string('mymedia_placement_desc', 'filter_mediacms'),
|
||||
'top',
|
||||
[
|
||||
'top' => get_string('mymedia_placement_top', 'filter_mediacms'),
|
||||
'user' => get_string('mymedia_placement_user', 'filter_mediacms'),
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user