-
-
Notifications
You must be signed in to change notification settings - Fork 0
TD-5858: 2 new end points are created for MyLearning page redesign. #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Parent:
Ci
sarathlal-sarangadharan
merged 1 commit into
CI
from
Develop/Features/TD-5858-Moodle-API-for-Accessing-Recent-Activitys-in-my-Learning-Activity-Page-Unified-Platform
Aug 5, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?php | ||
| $functions = array( | ||
| 'mylearningservice_get_recent_courses' => array( | ||
| 'classname' => 'mylearningservice_external', | ||
| 'methodname' => 'get_recent_courses', | ||
| 'classpath' => 'local/mylearningservice/externallib.php', | ||
| 'description' => 'Get courses a user was enrolled in within the last 6 months', | ||
| 'type' => 'read', | ||
| 'ajax' => true, | ||
| 'capabilities' => 'moodle/course:view', | ||
| ), | ||
| ); | ||
| $services = array( | ||
| 'Get Recent Courses' => array( | ||
| 'functions' => array( | ||
|
|
||
| 'mylearningservice_get_recent_courses' | ||
| ), | ||
| 'restrictedusers' => 0, | ||
| 'enabled' => 1, | ||
| // This field os optional, but requried if the `restrictedusers` value is | ||
| // set, so as to allow configuration via the Web UI. | ||
| 'shortname' => 'GetRecentCourses', | ||
|
|
||
| // Whether to allow file downloads. | ||
| 'downloadfiles' => 0, | ||
|
|
||
| // Whether to allow file uploads. | ||
| 'uploadfiles' => 0, | ||
| ) | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| <?php | ||
| defined('MOODLE_INTERNAL') || die(); | ||
|
|
||
| require_once("$CFG->libdir/externallib.php"); | ||
|
|
||
| class mylearningservice_external extends external_api { | ||
| public static function get_recent_courses_parameters() { | ||
| return new external_function_parameters( | ||
| array( | ||
| 'userid' => new external_value(PARAM_INT, 'User ID'), | ||
| // Allow omission by setting VALUE_DEFAULT and defaulting to 0 (meaning no limit) | ||
| 'months' => new external_value(PARAM_INT, 'Number of past months to include', VALUE_DEFAULT, 0), | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| public static function get_recent_courses($userid, $months = 0) { | ||
| global $CFG, $USER, $DB, $OUTPUT; | ||
|
|
||
| require_once($CFG->dirroot . '/course/lib.php'); | ||
| require_once($CFG->dirroot . '/user/lib.php'); | ||
| require_once($CFG->libdir . '/completionlib.php'); | ||
|
|
||
| // Do basic automatic PARAM checks on incoming data, using params description | ||
| // If any problems are found then exceptions are thrown with helpful error messages | ||
| $returnusercount = true; | ||
|
|
||
| $courses = enrol_get_users_courses($userid, true, '*'); | ||
| $result = array(); | ||
|
|
||
| // Get user data including last access to courses. | ||
| $user = get_complete_user_data('id', $userid); | ||
| $sameuser = $USER->id == $userid; | ||
|
|
||
| // Retrieve favourited courses (starred). | ||
| $favouritecourseids = array(); | ||
| if ($sameuser) { | ||
| $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid)); | ||
| $favourites = $ufservice->find_favourites_by_type('core_course', 'courses'); | ||
|
|
||
| if ($favourites) { | ||
| $favouritecourseids = array_flip(array_map( | ||
| function($favourite) { | ||
| return $favourite->itemid; | ||
| }, $favourites)); | ||
| } | ||
| } | ||
| if(!empty($months)) | ||
| { | ||
| $sixmonthsago = strtotime("-{$months} months"); // Calculate 6 months ago | ||
| } | ||
|
|
||
| foreach ($courses as $course) { | ||
|
|
||
| $enrolrecords = $DB->get_records_sql(" | ||
| SELECT ue.timestart,ue.timeend | ||
| FROM {user_enrolments} ue | ||
| JOIN {enrol} e ON ue.enrolid = e.id | ||
| WHERE ue.userid = :userid AND e.courseid = :courseid | ||
| ORDER BY ue.timestart DESC | ||
| ", [ | ||
| 'userid' => $userid, | ||
| 'courseid' => $course->id, | ||
| ]); | ||
|
|
||
| // Get the first record's timestart (most recent) | ||
| $enroltime = 0; | ||
| if (!empty($enrolrecords)) { | ||
| $firstrecord = reset($enrolrecords); // Gets first item | ||
| $enroltime = (int)$firstrecord->timestart; | ||
| $enrolendtime=(int)$firstrecord->timeend; | ||
| } | ||
| if(!empty($months)) | ||
| { | ||
| if ($enroltime && (int)$enroltime < $sixmonthsago) { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| $context = context_course::instance($course->id, IGNORE_MISSING); | ||
| try { | ||
| self::validate_context($context); | ||
| } catch (Exception $e) { | ||
| // current user can not access this course, sorry we can not disclose who is enrolled in this course! | ||
| continue; | ||
| } | ||
|
|
||
| // If viewing details of another user, then we must be able to view participants as well as profile of that user. | ||
| if (!$sameuser && (!course_can_view_participants($context) || !user_can_view_profile($user, $course))) { | ||
| continue; | ||
| } | ||
|
|
||
| if ($returnusercount) { | ||
| list($enrolledsqlselect, $enrolledparams) = get_enrolled_sql($context); | ||
| $enrolledsql = "SELECT COUNT('x') FROM ($enrolledsqlselect) enrolleduserids"; | ||
| $enrolledusercount = $DB->count_records_sql($enrolledsql, $enrolledparams); | ||
| } | ||
|
|
||
| $displayname = \core_external\util::format_string(get_course_display_name_for_list($course), $context); | ||
| list($course->summary, $course->summaryformat) = | ||
| \core_external\util::format_text($course->summary, $course->summaryformat, $context, 'course', 'summary', null); | ||
| $course->fullname = \core_external\util::format_string($course->fullname, $context); | ||
| $course->shortname = \core_external\util::format_string($course->shortname, $context); | ||
|
|
||
|
|
||
| $progress = null; | ||
| $completed = null; | ||
| $completionhascriteria = false; | ||
| $completionusertracked = false; | ||
|
|
||
| // Return only private information if the user should be able to see it. | ||
| if ($sameuser || completion_can_view_data($userid, $course)) { | ||
| if ($course->enablecompletion) { | ||
| $completion = new completion_info($course); | ||
| $completed = $completion->is_course_complete($userid); | ||
| $completionhascriteria = $completion->has_criteria(); | ||
| $completionusertracked = $completion->is_tracked_user($userid); | ||
| $progress = \core_completion\progress::get_course_progress_percentage($course, $userid); | ||
|
|
||
| $activities = $completion->get_activities(); | ||
| $totalactivities = count($activities); | ||
| $completedactivities = 0; | ||
| foreach ($activities as $cm) { | ||
| $data = $completion->get_data($cm, false, $userid); | ||
| if ($data->completionstate == COMPLETION_COMPLETE || $data->completionstate == COMPLETION_COMPLETE_PASS) { | ||
| $completedactivities++; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| $lastaccess = null; | ||
| // Check if last access is a hidden field. | ||
| $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); | ||
| $canviewlastaccess = $sameuser || !isset($hiddenfields['lastaccess']); | ||
| if (!$canviewlastaccess) { | ||
| $canviewlastaccess = has_capability('moodle/course:viewhiddenuserfields', $context); | ||
| } | ||
|
|
||
| if ($canviewlastaccess && isset($user->lastcourseaccess[$course->id])) { | ||
| $lastaccess = $user->lastcourseaccess[$course->id]; | ||
| } | ||
|
|
||
| $hidden = false; | ||
| if ($sameuser) { | ||
| $hidden = boolval(get_user_preferences('block_myoverview_hidden_course_' . $course->id, 0)); | ||
| } | ||
|
|
||
| // Retrieve course overview used files. | ||
| $courselist = new core_course_list_element($course); | ||
| $overviewfiles = array(); | ||
| foreach ($courselist->get_course_overviewfiles() as $file) { | ||
| $fileurl = moodle_url::make_webservice_pluginfile_url($file->get_contextid(), $file->get_component(), | ||
| $file->get_filearea(), null, $file->get_filepath(), | ||
| $file->get_filename())->out(false); | ||
| $overviewfiles[] = array( | ||
| 'filename' => $file->get_filename(), | ||
| 'fileurl' => $fileurl, | ||
| 'filesize' => $file->get_filesize(), | ||
| 'filepath' => $file->get_filepath(), | ||
| 'mimetype' => $file->get_mimetype(), | ||
| 'timemodified' => $file->get_timemodified(), | ||
| ); | ||
| } | ||
|
|
||
| $courseimage = \core_course\external\course_summary_exporter::get_course_image($course); | ||
| if (!$courseimage) { | ||
| $courseimage = $OUTPUT->get_generated_url_for_course($context); | ||
| } | ||
| $hascertificate = $DB->record_exists('customcert', ['course' => $course->id]); | ||
| $courseresult = [ | ||
| 'id' => $course->id, | ||
| 'shortname' => $course->shortname, | ||
| 'fullname' => $course->fullname, | ||
| 'displayname' => $displayname, | ||
| 'idnumber' => $course->idnumber, | ||
| 'visible' => $course->visible, | ||
| 'summary' => $course->summary, | ||
| 'summaryformat' => $course->summaryformat, | ||
| 'format' => $course->format, | ||
| 'courseimage' => $courseimage, | ||
| 'showgrades' => $course->showgrades, | ||
| 'lang' => clean_param($course->lang, PARAM_LANG), | ||
| 'enablecompletion' => $course->enablecompletion, | ||
| 'completionhascriteria' => $completionhascriteria, | ||
| 'completionusertracked' => $completionusertracked, | ||
| 'category' => $course->category, | ||
| 'progress' => $progress, | ||
| 'completed' => $completed, | ||
| 'startdate' => $enroltime, | ||
| 'enddate' => $enrolendtime, | ||
| 'marker' => $course->marker, | ||
| 'lastaccess' => $lastaccess, | ||
| 'isfavourite' => isset($favouritecourseids[$course->id]), | ||
| 'hidden' => $hidden, | ||
| 'overviewfiles' => $overviewfiles, | ||
| 'showactivitydates' => $course->showactivitydates, | ||
| 'showcompletionconditions' => $course->showcompletionconditions, | ||
| 'timemodified' => $course->timemodified, | ||
| 'certificateenabled'=>$hascertificate, | ||
| 'totalactivities' => $totalactivities, | ||
| 'completedactivities'=>$completedactivities | ||
|
|
||
| ]; | ||
| if ($returnusercount) { | ||
| $courseresult['enrolledusercount'] = $enrolledusercount; | ||
| } | ||
| $result[] = $courseresult; | ||
| } | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| public static function get_recent_courses_returns() { | ||
| return new external_multiple_structure( | ||
| new external_single_structure( | ||
| array( | ||
| 'id' => new external_value(PARAM_INT, 'id of course'), | ||
| 'shortname' => new external_value(PARAM_RAW, 'short name of course'), | ||
| 'fullname' => new external_value(PARAM_RAW, 'long name of course'), | ||
| 'displayname' => new external_value(PARAM_RAW, 'course display name for lists.', VALUE_OPTIONAL), | ||
| 'enrolledusercount' => new external_value(PARAM_INT, 'Number of enrolled users in this course', | ||
| VALUE_OPTIONAL), | ||
| 'idnumber' => new external_value(PARAM_RAW, 'id number of course'), | ||
| 'visible' => new external_value(PARAM_INT, '1 means visible, 0 means not yet visible course'), | ||
| 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL), | ||
| 'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL), | ||
| 'format' => new external_value(PARAM_PLUGIN, 'course format: weeks, topics, social, site', VALUE_OPTIONAL), | ||
| 'courseimage' => new external_value(PARAM_URL, 'The course image URL', VALUE_OPTIONAL), | ||
| 'showgrades' => new external_value(PARAM_BOOL, 'true if grades are shown, otherwise false', VALUE_OPTIONAL), | ||
| 'lang' => new external_value(PARAM_LANG, 'forced course language', VALUE_OPTIONAL), | ||
| 'enablecompletion' => new external_value(PARAM_BOOL, 'true if completion is enabled, otherwise false', | ||
| VALUE_OPTIONAL), | ||
| 'completionhascriteria' => new external_value(PARAM_BOOL, 'If completion criteria is set.', VALUE_OPTIONAL), | ||
| 'completionusertracked' => new external_value(PARAM_BOOL, 'If the user is completion tracked.', VALUE_OPTIONAL), | ||
| 'category' => new external_value(PARAM_INT, 'course category id', VALUE_OPTIONAL), | ||
| 'progress' => new external_value(PARAM_FLOAT, 'Progress percentage', VALUE_OPTIONAL), | ||
| 'completed' => new external_value(PARAM_BOOL, 'Whether the course is completed.', VALUE_OPTIONAL), | ||
| 'startdate' => new external_value(PARAM_INT, 'Timestamp when the course start', VALUE_OPTIONAL), | ||
| 'enddate' => new external_value(PARAM_INT, 'Timestamp when the course end', VALUE_OPTIONAL), | ||
| 'marker' => new external_value(PARAM_INT, 'Course section marker.', VALUE_OPTIONAL), | ||
| 'lastaccess' => new external_value(PARAM_INT, 'Last access to the course (timestamp).', VALUE_OPTIONAL), | ||
| 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this course a favourite.', VALUE_OPTIONAL), | ||
| 'hidden' => new external_value(PARAM_BOOL, 'If the user hide the course from the dashboard.', VALUE_OPTIONAL), | ||
| 'overviewfiles' => new external_files('Overview files attached to this course.', VALUE_OPTIONAL), | ||
| 'showactivitydates' => new external_value(PARAM_BOOL, 'Whether the activity dates are shown or not'), | ||
| 'showcompletionconditions' => new external_value(PARAM_BOOL, 'Whether the activity completion conditions are shown or not'), | ||
| 'timemodified' => new external_value(PARAM_INT, 'Last time course settings were updated (timestamp).', | ||
| VALUE_OPTIONAL), | ||
| 'certificateenabled' => new external_value(PARAM_BOOL, 'Whether the course has certificate.', VALUE_OPTIONAL), | ||
| 'totalactivities' => new external_value(PARAM_INT, 'total activities', VALUE_OPTIONAL), | ||
| 'completedactivities' => new external_value(PARAM_INT, 'completed activities count', VALUE_OPTIONAL), | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <?php | ||
| $string['pluginname'] = 'Recent Courses Service'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <?php | ||
| defined('MOODLE_INTERNAL') || die(); | ||
|
|
||
| $plugin->component = 'local_mylearningservice'; | ||
| $plugin->version = 2025073100; | ||
| $plugin->requires = 2024100290; | ||
| $plugin->maturity = MATURITY_STABLE; | ||
| $plugin->release = '1.0'; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.