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

Webservice core_user_create_users is not extendable

XMLWordPrintable

    • MOODLE_38_STABLE
    • Hide

      Duplicate hundreds of lines of code...

      • core_user_external::create_users_parameters
      • core_user_external::create_users
      • core_user_external::update_users_parameters
      • core_user_external::update_users
      Show
      Duplicate hundreds of lines of code... core_user_external::create_users_parameters core_user_external::create_users core_user_external::update_users_parameters core_user_external::update_users
    • Hide

      1. Create a webservice custom plugin, that extend core_user_external. Example:

      // Example: local/mywebservices/version.php
      defined('MOODLE_INTERNAL') || die();
      $plugin->version = 2020022416;
      $plugin->requires = 2018051709;
      $plugin->component = 'local_mywebservices';
      $plugin->maturity = MATURITY_BETA;
       
       
      // Example: local/mywebservices/db/services.php
      $functions = array(
          'local_mywebservices_create_users' => array(
              'classname'    => 'local_mywebservices_external',
              'methodname'   => 'create_users',
              'classpath'    => 'local/mywebservices/class/external.php',
              'description'  => 'Create users (including phone1).',
              'type'         => 'write',
              'capabilities' => 'moodle/user:create'
          )
      );
       
       
      // Example: local/mywebservices/class/external.php
      class local_mywebservices_external extends core_user_external {
          public static function create_users_parameters() {
              $parameters = parent::create_users_parameters();
              $parameters->keys['users']->content->keys['phone1'] = new external_value(
                  core_user::get_property_type('phone1'),
                  'The phone number of the user',
                  VALUE_OPTIONAL);
              return $parameters;
          }
      }
      

      2. Enable webservices and create a webservice user and token in the administration, to allow the use of the custom webservice. (https://docs.moodle.org/38/en/Using_web_services). The user related to the token must have the capabilities to create and update users, as we want to extend the webservices core_user_create_users and core_user_update_users.

      3. Call your custom webservice. Example:

      POST /webservice/rest/server.php?moodlewsrestformat=json&wstoken=TOKEN&wsfunction=local_mywebservices_create_users HTTP/1.1
      Host: mdl-local.docker.test
      Content-Type: application/x-www-form-urlencoded
      Authorization: Basic d3M6d3M=
       
      users%5B0%5D%5Busername%5D=test-username&users%5B0%5D%5Bpassword%5D=test-password-123&users%5B0%5D%5Bfirstname%5D=test-firstame&users%5B0%5D%5Blastname%5D=test-lastname&users%5B0%5D%5Bemail%5D=test-email%40example.com&users%5B0%5D%5Bphone1%5D=0123456789

      As for the webservices we are extending, the request must be POST.
      Any post webform and application to forge POST request can do the job. I personally like postman to do testing.

      Without the correction:
      Notice that the webservice returns an "invalid parameters error"

      With the correction
      Notice that new optional field (phone1) of the new created user is filled.

      Same process for update.

      Show
      1. Create a webservice custom plugin, that extend core_user_external . Example: // Example: local/mywebservices/version.php defined('MOODLE_INTERNAL') || die(); $plugin->version = 2020022416; $plugin->requires = 2018051709; $plugin->component = 'local_mywebservices'; $plugin->maturity = MATURITY_BETA;     // Example: local/mywebservices/db/services.php $functions = array( 'local_mywebservices_create_users' => array( 'classname' => 'local_mywebservices_external', 'methodname' => 'create_users', 'classpath' => 'local/mywebservices/class/external.php', 'description' => 'Create users (including phone1).', 'type' => 'write', 'capabilities' => 'moodle/user:create' ) );     // Example: local/mywebservices/class/external.php class local_mywebservices_external extends core_user_external { public static function create_users_parameters() { $parameters = parent::create_users_parameters(); $parameters->keys['users']->content->keys['phone1'] = new external_value( core_user::get_property_type('phone1'), 'The phone number of the user', VALUE_OPTIONAL); return $parameters; } } 2. Enable webservices and create a webservice user and token in the administration, to allow the use of the custom webservice. ( https://docs.moodle.org/38/en/Using_web_services ). The user related to the token must have the capabilities to create and update users, as we want to extend the webservices core_user_create_users and core_user_update_users. 3. Call your custom webservice. Example: POST /webservice/rest/server.php?moodlewsrestformat=json&wstoken=TOKEN&wsfunction=local_mywebservices_create_users HTTP/1.1 Host: mdl-local.docker.test Content-Type: application/x-www-form-urlencoded Authorization: Basic d3M6d3M=   users%5B0%5D%5Busername%5D=test-username&users%5B0%5D%5Bpassword%5D=test-password-123&users%5B0%5D%5Bfirstname%5D=test-firstame&users%5B0%5D%5Blastname%5D=test-lastname&users%5B0%5D%5Bemail%5D=test-email%40example.com&users%5B0%5D%5Bphone1%5D=0123456789 As for the webservices we are extending, the request must be POST. Any post webform and application to forge POST request can do the job. I personally like postman to do testing. Without the correction: Notice that the webservice returns an "invalid parameters error" With the correction Notice that new optional field (phone1) of the new created user is filled. Same process for update.

      I created a plugin to have custom external webservices to create and update users with additional fields (such as optional phone1, department, institution, ...).

      To do that, extending the class \core_user_external and overriding the method \core_user_external::create_users_parameters seems the right, good enough solution.
      (user/externallib.php)

      But the methods create_users and update_users do calls with self to:

      • self::create_users_parameters()
      • self::update_users_parameters()

      Instead, they should call these methods with static:

      • static::create_users_parameters()
      • static::update_users_parameters()

      This way, the extended method wouldn't be dead code.

      Looks like a simple mistake, or just something that was not anticipated.
      I tested the fix, and everything works perfect with it.

      Diff: https://github.com/moodle/moodle/compare/master...liip-elearning:MDL-68034

            Unassigned Unassigned
            mcornut Cornut Matthieu
            Sara Arjona (@sarjona) Sara Arjona (@sarjona)
            Votes:
            5 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 35 minutes
                35m

                  Error rendering 'clockify-timesheets-time-tracking-reports:timer-sidebar'. Please contact your Jira administrators.