Skip to content

Commit

Permalink
MDL-56092 auth_email: New WS auth_email_signup_user
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyva committed Oct 4, 2016
1 parent 4e2f7e0 commit e66a45d
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 4 deletions.
174 changes: 174 additions & 0 deletions auth/email/classes/external.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,178 @@ public static function get_signup_settings_returns() {
)
);
}

/**
* Describes the parameters for signup_user.
*
* @return external_external_function_parameters
* @since Moodle 3.2
*/
public static function signup_user_parameters() {
return new external_function_parameters(
array(
'username' => new external_value(core_user::get_property_type('username'), 'Username'),
'password' => new external_value(core_user::get_property_type('password'), 'Plain text password'),
'firstname' => new external_value(core_user::get_property_type('firstname'), 'The first name(s) of the user'),
'lastname' => new external_value(core_user::get_property_type('lastname'), 'The family name of the user'),
'email' => new external_value(core_user::get_property_type('email'), 'A valid and unique email address'),
'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user', VALUE_DEFAULT, ''),
'country' => new external_value(core_user::get_property_type('country'), 'Home country code', VALUE_DEFAULT, ''),
'recaptchachallengehash' => new external_value(PARAM_RAW, 'Recaptcha challenge hash', VALUE_DEFAULT, ''),
'recaptcharesponse' => new external_value(PARAM_NOTAGS, 'Recaptcha response', VALUE_DEFAULT, ''),
'customprofilefields' => new external_multiple_structure(
new external_single_structure(
array(
'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field'),
'name' => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
'value' => new external_value(PARAM_RAW, 'Custom field value, can be an encoded json if required')
)
), 'User custom fields (also known as user profile fields)', VALUE_DEFAULT, array()
)
)
);
}

/**
* Get the signup required settings and profile fields.
*
* @param string $username username
* @param string $password plain text password
* @param string $firstname the first name(s) of the user
* @param string $lastname the family name of the user
* @param string $email a valid and unique email address
* @param string $city home city of the user
* @param string $country home country code
* @param string $recaptchachallengehash recaptcha challenge hash
* @param string $recaptcharesponse recaptcha response
* @param array $customprofilefields user custom fields (also known as user profile fields)
* @return array settings and possible warnings
* @since Moodle 3.2
* @throws moodle_exception
* @throws invalid_parameter_exception
*/
public static function signup_user($username, $password, $firstname, $lastname, $email, $city = '', $country = '',
$recaptchachallengehash = '', $recaptcharesponse = '', $customprofilefields = array()) {
global $CFG, $PAGE;

$warnings = array();
$params = self::validate_parameters(
self::signup_user_parameters(),
array(
'username' => $username,
'password' => $password,
'firstname' => $firstname,
'lastname' => $lastname,
'email' => $email,
'city' => $city,
'country' => $country,
'recaptchachallengehash' => $recaptchachallengehash,
'recaptcharesponse' => $recaptcharesponse,
'customprofilefields' => $customprofilefields,
)
);

// We need this to make work the format text functions.
$context = context_system::instance();
$PAGE->set_context($context);

self::check_signup_enabled();

// Validate profile fields param types.
$allowedfields = profile_get_signup_fields();
$fieldproperties = array();
$fieldsrequired = array();
foreach ($allowedfields as $field) {
$fieldproperties[$field->object->inputname] = $field->object->get_field_properties();
if ($field->object->is_required()) {
$fieldsrequired[$field->object->inputname] = true;
}
}

foreach ($params['customprofilefields'] as $profilefield) {
if (!array_key_exists($profilefield['name'], $fieldproperties)) {
throw new invalid_parameter_exception('Invalid field' . $profilefield['name']);
}
list($type, $allownull) = $fieldproperties[$profilefield['name']];
validate_param($profilefield['value'], $type, $allownull);
// Remove from the potential required list.
if (isset($fieldsrequired[$profilefield['name']])) {
unset($fieldsrequired[$profilefield['name']]);
}
}
if (!empty($fieldsrequired)) {
throw new invalid_parameter_exception('Missing required parameters: ' . implode(',', array_keys($fieldsrequired)));
}

// Validate the data sent.
$data = $params;
$data['email2'] = $data['email'];
unset($data['recaptcharesponse']);
unset($data['customprofilefields']);
// Add profile fields data.
foreach ($params['customprofilefields'] as $profilefield) {
// First, check if the value is a json (some profile fields like text area uses an array for sending data).
$datadecoded = json_decode($profilefield['value'], true);
if (is_array($datadecoded) && (json_last_error() == JSON_ERROR_NONE)) {
$data[$profilefield['name']] = $datadecoded;
} else {
$data[$profilefield['name']] = $profilefield['value'];
}
}

$errors = signup_validate_data($data, array());

// Validate recaptcha.
if (signup_captcha_enabled()) {
require_once($CFG->libdir . '/recaptchalib.php');
$response = recaptcha_check_answer($CFG->recaptchaprivatekey, getremoteaddr(), $params['recaptchachallengehash'],
$params['recaptcharesponse'], true);
if (!$response->is_valid) {
$errors['recaptcharesponse'] = $response->error;
}
}

if (!empty($errors)) {
foreach ($errors as $itemname => $message) {
$warnings[] = array(
'item' => $itemname,
'itemid' => 0,
'warningcode' => 'fielderror',
'message' => s($message)
);
}
$result = array(
'success' => false,
'warnings' => $warnings,
);
} else {
// Save the user.
$user = signup_setup_new_user((object) $data);

$authplugin = get_auth_plugin('email');
$authplugin->user_signup($user, false);

$result = array(
'success' => true,
'warnings' => array(),
);
}
return $result;
}

/**
* Describes the signup_user return value.
*
* @return external_single_structure
* @since Moodle 3.2
*/
public static function signup_user_returns() {

return new external_single_structure(
array(
'success' => new external_value(PARAM_BOOL, 'True if the user was created false otherwise'),
'warnings' => new external_warnings(),
)
);
}
}
8 changes: 8 additions & 0 deletions auth/email/db/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,13 @@
'ajax' => true,
'loginrequired' => false,
),
'auth_email_signup_user' => array(
'classname' => 'auth_email_external',
'methodname' => 'signup_user',
'description' => 'Adds a new user (pendingto be confirmed) in the site.',
'type' => 'write',
'ajax' => true,
'loginrequired' => false,
),
);

76 changes: 73 additions & 3 deletions auth/email/tests/external_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ public function setUp() {
$CFG->registerauth = 'email';

$categoryid = $DB->insert_record('user_info_category', array('name' => 'Cat 1', 'sortorder' => 1));
$field = $DB->insert_record('user_info_field', array(
$this->field1 = $DB->insert_record('user_info_field', array(
'shortname' => 'frogname', 'name' => 'Name of frog', 'categoryid' => $categoryid,
'datatype' => 'text', 'signup' => 1, 'visible' => 1));
'datatype' => 'text', 'signup' => 1, 'visible' => 1, 'required' => 1));
$this->field2 = $DB->insert_record('user_info_field', array(
'shortname' => 'sometext', 'name' => 'Some text in textarea', 'categoryid' => $categoryid,
'datatype' => 'textarea', 'signup' => 1, 'visible' => 1, 'required' => 1));
}

public function test_get_signup_settings() {
Expand All @@ -73,8 +76,75 @@ public function test_get_signup_settings() {
$this->assertEquals(print_password_policy(), $result['passwordpolicy']);
$this->assertNotContains('recaptchachallengehash', $result);
$this->assertNotContains('recaptchachallengeimage', $result);
$this->assertCount(1, $result['profilefields']);
$this->assertCount(2, $result['profilefields']);
$this->assertEquals('text', $result['profilefields'][0]['datatype']);
$this->assertEquals('textarea', $result['profilefields'][1]['datatype']);
}

public function test_signup_user() {
global $DB;

$username = 'pepe';
$password = 'abcdefAª.ªª!!3';
$firstname = 'Pepe';
$lastname = 'Pérez';
$email = '[email protected]';
$city = 'Bcn';
$country = 'ES';
$customprofilefields = array(
array(
'type' => 'text',
'name' => 'profile_field_frogname',
'value' => 'random text',
),
array(
'type' => 'textarea',
'name' => 'profile_field_sometext',
'value' => json_encode(
array(
'text' => 'blah blah',
'format' => FORMAT_HTML
)
),
)
);

// Create new user.
$result = auth_email_external::signup_user($username, $password, $firstname, $lastname, $email, $city, $country,
'', '', $customprofilefields);
$result = external_api::clean_returnvalue(auth_email_external::signup_user_returns(), $result);
$this->assertTrue($result['success']);
$this->assertEmpty($result['warnings']);
$user = $DB->get_record('user', array('username' => $username));
$this->assertEquals($firstname, $user->firstname);
$this->assertEquals($lastname, $user->lastname);
$this->assertEquals($email, $user->email);
$this->assertEquals($city, $user->city);
$this->assertEquals($country, $user->country);
$this->assertEquals(0, $user->confirmed);
$this->assertEquals(current_language(), $user->lang);
$this->assertEquals('email', $user->auth);
$infofield = $DB->get_record('user_info_data', array('userid' => $user->id, 'fieldid' => $this->field1));
$this->assertEquals($customprofilefields[0]['value'], $infofield->data);
$infofield = $DB->get_record('user_info_data', array('userid' => $user->id, 'fieldid' => $this->field2));
$this->assertEquals(json_decode($customprofilefields[1]['value'])->text, $infofield->data);

// Try to create a user with the same username, email and password. We ommit also the profile fields.
$password = 'abc';
$result = auth_email_external::signup_user($username, $password, $firstname, $lastname, $email, $city, $country,
'', '', $customprofilefields);
$result = external_api::clean_returnvalue(auth_email_external::signup_user_returns(), $result);
$this->assertFalse($result['success']);
$this->assertCount(3, $result['warnings']);
$expectederrors = array('username', 'email', 'password');
$finalerrors = [];
foreach ($result['warnings'] as $warning) {
$finalerrors[] = $warning['item'];
}
$this->assertEquals($expectederrors, $finalerrors);

// Do not pass the required profile fields.
$this->expectException('invalid_parameter_exception');
$result = auth_email_external::signup_user($username, $password, $firstname, $lastname, $email, $city, $country);
}
}
2 changes: 1 addition & 1 deletion auth/email/version.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@

defined('MOODLE_INTERNAL') || die;

$plugin->version = 2016052301; // The current plugin version (Date: YYYYMMDDXX)
$plugin->version = 2016052302; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2016051900; // Requires this Moodle version
$plugin->component = 'auth_email'; // Full name of the plugin (used for diagnostics)

0 comments on commit e66a45d

Please sign in to comment.