diff --git a/lang/en/admin.php b/lang/en/admin.php index e3fd072f6990a..b3d53cce08175 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -1169,6 +1169,7 @@ $string['user'] = 'User'; $string['userbulk'] = 'Bulk user actions'; $string['userbulkdownload'] = 'Export users as'; +$string['userimagesdisabled'] = 'Profile user images are disabled'; $string['userlist'] = 'Browse list of users'; $string['userdefaultpreferences'] = 'User default preferences'; $string['userpreference'] = 'User preference'; diff --git a/lib/db/services.php b/lib/db/services.php index 8fc5595d5e4f4..9ba895e6c45ca 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -896,7 +896,15 @@ 'type' => 'read', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), - + 'core_user_update_picture' => array( + 'classname' => 'core_user_external', + 'methodname' => 'update_picture', + 'classpath' => 'user/externallib.php', + 'description' => 'Update or delete the user picture in the site', + 'type' => 'write', + 'capabilities' => 'moodle/user:editownprofile, moodle/user:editprofile', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), // Competencies functions. 'core_competency_create_competency_framework' => array( 'classname' => 'core_competency\external', diff --git a/user/externallib.php b/user/externallib.php index b8216ed607de0..933b6da06eaa5 100644 --- a/user/externallib.php +++ b/user/externallib.php @@ -1456,4 +1456,102 @@ public static function get_user_preferences_returns() { ) ); } + + /** + * Returns description of method parameters + * + * @return external_function_parameters + * @since Moodle 3.2 + */ + public static function update_picture_parameters() { + return new external_function_parameters( + array( + 'draftitemid' => new external_value(PARAM_INT, 'Id of the user draft file to use as image'), + 'delete' => new external_value(PARAM_BOOL, 'If we should delete the user picture', VALUE_DEFAULT, false), + 'userid' => new external_value(PARAM_INT, 'Id of the user, 0 for current user', VALUE_DEFAULT, 0) + ) + ); + } + + /** + * Update or delete the user picture in the site + * + * @param int $draftitemid id of the user draft file to use as image + * @param bool $delete if we should delete the user picture + * @param int $userid id of the user, 0 for current user + * @return array warnings and success status + * @since Moodle 3.2 + * @throws moodle_exception + */ + public static function update_picture($draftitemid, $delete = false, $userid = 0) { + global $CFG, $USER, $PAGE; + + $params = self::validate_parameters( + self::update_picture_parameters(), + array( + 'draftitemid' => $draftitemid, + 'delete' => $delete, + 'userid' => $userid + ) + ); + + $context = context_system::instance(); + self::validate_context($context); + + if (!empty($CFG->disableuserimages)) { + throw new moodle_exception('userimagesdisabled', 'admin'); + } + + if (empty($params['userid']) or $params['userid'] == $USER->id) { + $user = $USER; + require_capability('moodle/user:editownprofile', $context); + } else { + $user = core_user::get_user($params['userid'], '*', MUST_EXIST); + core_user::require_active_user($user); + $personalcontext = context_user::instance($user->id); + + require_capability('moodle/user:editprofile', $personalcontext); + if (is_siteadmin($user) and !is_siteadmin($USER)) { // Only admins may edit other admins. + throw new moodle_exception('useradmineditadmin'); + } + } + + // Load the appropriate auth plugin. + $userauth = get_auth_plugin($user->auth); + if (is_mnet_remote_user($user) or !$userauth->can_edit_profile() or $userauth->edit_profile_url()) { + throw new moodle_exception('noprofileedit', 'auth'); + } + + $filemanageroptions = array('maxbytes' => $CFG->maxbytes, 'subdirs' => 0, 'maxfiles' => 1, 'accepted_types' => 'web_image'); + $user->deletepicture = $params['delete']; + $user->imagefile = $params['draftitemid']; + $success = core_user::update_picture($user, $filemanageroptions); + + $result = array( + 'success' => $success, + 'warnings' => array(), + ); + if ($success) { + $userpicture = new user_picture(core_user::get_user($user->id)); + $userpicture->size = 1; // Size f1. + $result['profileimageurl'] = $userpicture->get_url($PAGE)->out(false); + } + return $result; + } + + /** + * Returns description of method result value + * + * @return external_description + * @since Moodle 3.2 + */ + public static function update_picture_returns() { + return new external_single_structure( + array( + 'success' => new external_value(PARAM_BOOL, 'True if the image was updated, false otherwise.'), + 'profileimageurl' => new external_value(PARAM_URL, 'New profile user image url', VALUE_OPTIONAL), + 'warnings' => new external_warnings() + ) + ); + } } diff --git a/user/tests/externallib_test.php b/user/tests/externallib_test.php index f31bf76979b48..e0920b74a4f62 100644 --- a/user/tests/externallib_test.php +++ b/user/tests/externallib_test.php @@ -854,4 +854,69 @@ public function test_get_user_preferences() { $result = core_user_external::get_user_preferences('', $user->id); } + /** + * Test update_picture + */ + public function test_update_picture() { + global $DB, $USER; + + $this->resetAfterTest(true); + + $user = self::getDataGenerator()->create_user(); + self::setUser($user); + + $context = context_user::instance($USER->id); + $contextid = $context->id; + $filename = "reddot.png"; + $filecontent = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38" + . "GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; + + // Call the files api to create a file. + $draftfile = core_files_external::upload($contextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null); + $draftid = $draftfile['itemid']; + + // Change user profile image. + $result = core_user_external::update_picture($draftid); + $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); + $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); + // The new revision is in the url for the user. + $this->assertContains($picture, $result['profileimageurl']); + // Check expected URL for serving the image. + $this->assertContains("/$contextid/user/icon", $result['profileimageurl']); + + // Delete image. + $result = core_user_external::update_picture(0, true); + $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); + $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); + // No picture. + $this->assertEquals(0, $picture); + + // Add again the user profile image (as admin). + $this->setAdminUser(); + + $context = context_user::instance($USER->id); + $admincontextid = $context->id; + $draftfile = core_files_external::upload($admincontextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null); + $draftid = $draftfile['itemid']; + + $result = core_user_external::update_picture($draftid, false, $user->id); + $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); + // The new revision is in the url for the user. + $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); + $this->assertContains($picture, $result['profileimageurl']); + $this->assertContains("/$contextid/user/icon", $result['profileimageurl']); + } + + /** + * Test update_picture disabled + */ + public function test_update_picture_disabled() { + global $CFG; + $this->resetAfterTest(true); + $CFG->disableuserimages = true; + + $this->setAdminUser(); + $this->expectException('moodle_exception'); + core_user_external::update_picture(0); + } } diff --git a/version.php b/version.php index a965a61000aab..dbe9e01274c24 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2016092300.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2016092300.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.