Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-63131

Web services: Callback to allow web service overrides

    XMLWordPrintable

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 3.6
    • Fix Version/s: 3.6
    • Component/s: Web Services
    • Labels:
    • Testing Instructions:
      Hide
      1. Log in as admin.
      2. Create a new course with short name SNEAKY.
      3. Ensure the Moodle mobile web service is enabled (Site administration / Mobile app / Mobile settings).
      4. Go to Site administration / Plugins / Web services / Manage tokens.
      5. Add a new token (or use existing one if there) for yourself, on the 'Moodle mobile web service' service.
      6. Use the token, and your server address in the following URL: https://MY.SERVER.NAME/webservice/rest/server.php?moodlewsrestformat=json&wstoken=MYTOKEN&wsfunction=core_course_get_courses
        1. EXPECTED: The resulting JSON should include all the courses you have access to (i.e. all of them, since you're admin), including the SNEAKY course that you just created.
      7. Edit source code mod/page/lib.php and paste in the following into the end of the file:

        function mod_page_override_webservice_execution($function, $params) {
            // Check if it's the function we want to override.
            if ($function->name === 'core_course_get_courses') {
                // Call the original function.
                $result = call_user_func_array([$function->classname, $function->methodname], $params);
                // Get rid of a specific course from the results
                foreach ($result as $index => $course) {
                    if ($course['shortname'] === 'SNEAKY') {
                        unset($result[$index]);
                    }
                }
                $result = array_values($result);
                return $result;
            }
         
            return false;
        }
        

      8. Purge caches (site administration / Developer / Purge caches).
      9. Reload the web service URL with the token in from above.
        1. EXPECTED: The resulting JSON should be the same as before except that the SNEAKY course should not be included.
      10. Edit source code mod/page/lib.php and replace the function you just added with:

        function mod_page_override_webservice_execution($function, $params) {
            // Check if it's the AJAX function that fetches notifications.
            if ($function->name === 'core_fetch_notifications') {
                // Call the original function.
                $result = call_user_func_array([$function->classname, $function->methodname], $params);
         
                // Add an extra notification.
                $result[] = [
                    'template' => 'core/notification_info',
                    'variables' => ['message' => 'The time is: ' . date('H:i:s'), 'extraclasses' => '',
                        'closebutton' => false, 'announce' => true]
                ];
                return $result;
            }
         
            return false;
        }
        

      11. View any Moodle page, such as the admin page.
        1. EXPECTED: A few seconds after any page loads, a notification should appear that gives the current time.
      Show
      Log in as admin. Create a new course with short name SNEAKY. Ensure the Moodle mobile web service is enabled (Site administration / Mobile app / Mobile settings). Go to Site administration / Plugins / Web services / Manage tokens. Add a new token (or use existing one if there) for yourself, on the 'Moodle mobile web service' service. Use the token, and your server address in the following URL: https://MY.SERVER.NAME/webservice/rest/server.php?moodlewsrestformat=json&wstoken=MYTOKEN&wsfunction=core_course_get_courses EXPECTED: The resulting JSON should include all the courses you have access to (i.e. all of them, since you're admin), including the SNEAKY course that you just created. Edit source code mod/page/lib.php and paste in the following into the end of the file: function mod_page_override_webservice_execution($function, $params) { // Check if it's the function we want to override. if ($function->name === 'core_course_get_courses') { // Call the original function. $result = call_user_func_array([$function->classname, $function->methodname], $params); // Get rid of a specific course from the results foreach ($result as $index => $course) { if ($course['shortname'] === 'SNEAKY') { unset($result[$index]); } } $result = array_values($result); return $result; }   return false; } Purge caches (site administration / Developer / Purge caches). Reload the web service URL with the token in from above. EXPECTED: The resulting JSON should be the same as before except that the SNEAKY course should not be included. Edit source code mod/page/lib.php and replace the function you just added with: function mod_page_override_webservice_execution($function, $params) { // Check if it's the AJAX function that fetches notifications. if ($function->name === 'core_fetch_notifications') { // Call the original function. $result = call_user_func_array([$function->classname, $function->methodname], $params);   // Add an extra notification. $result[] = [ 'template' => 'core/notification_info', 'variables' => ['message' => 'The time is: ' . date('H:i:s'), 'extraclasses' => '', 'closebutton' => false, 'announce' => true] ]; return $result; }   return false; } View any Moodle page, such as the admin page. EXPECTED: A few seconds after any page loads, a notification should appear that gives the current time.
    • Affected Branches:
      MOODLE_36_STABLE
    • Fixed Branches:
      MOODLE_36_STABLE
    • Pull Master Branch:
      MDL-63131-master

      Description

      There are lots of ways, with differing degrees of evilness, to override behaviour in a Moodle website in order to customise it to suit a specific institution, without making changes to core code. For example you can use a theme with custom renderers. However, sometimes we want to override behaviour of core web services and there is currently (I think) no mechanism for that.

      Primarily we want to do this to affect the mobile app but there could be other uses.

      I propose a simple callback which will allow a local plugin (or any plugin) to override any web service function call and change the results or do something different.

      Here is an example (this is basically what we want to do with it) that removes a specific course from the list of enrolled courses. To make it easier to test, I've put this example in mod/page/lib.php, but in reality this code would probably go within a local plugin.

      function mod_page_override_webservice_execution($function, $params) {
          // Check if it's the function we want to override.
          if ($function->name === 'core_course_get_courses') {
              // Call the original function.
              $result = call_user_func_array([$function->classname, $function->methodname], $params);
              // Get rid of a specific course from the results
              foreach ($result as $index => $course) {
                  if ($course['shortname'] === 'SNEAKY') {
                      unset($result[$index]);
                  }
              }
              $result = array_values($result);
              return $result;
          }
       
          return false;
      }
      

      Making this sort of change will have unintended consequences within the mobile app; it's obviously not a 'recommended' thing to do. But it's still good for us to have a way to hook in so we can do it.

      This second (silly) example demonstrates that it also works for AJAX functions such as the one to fetch notifications.

      function mod_page_override_webservice_execution($function, $params) {
          // Check if it's the AJAX function that fetches notifications.
          if ($function->name === 'core_fetch_notifications') {
              // Call the original function.
              $result = call_user_func_array([$function->classname, $function->methodname], $params);
       
              // Add an extra notification.
              $result[] = [
                  'template' => 'core/notification_info',
                  'variables' => ['message' => 'The time is: ' . date('H:i:s'), 'extraclasses' => '',
                      'closebutton' => false, 'announce' => true]
              ];
              return $result;
          }
       
          return false;
      }
      

      Note: If implemented, I'll have to document this at https://docs.moodle.org/dev/Callbacks

      Discussion thread: https://moodle.org/mod/forum/discuss.php?d=374617

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              9 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Fix Release Date:
                3/Dec/18

                Time Tracking

                Estimated:
                Original Estimate - 0 minutes
                0m
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 23 minutes
                23m