From 5407c5b0f4fbd76cfbcd07ca5c5bf08fe5313e9a Mon Sep 17 00:00:00 2001 From: Russell Smith Date: Thu, 15 Oct 2015 19:34:58 +1100 Subject: [PATCH] MDL-51789 users: Allow picture update from webservices. useredit_update_picture as moved to user_update_picture as it's more general. It was also moved to user/lib.php so it can be used by both webservices and edit without more include files. --- lib/classes/user.php | 61 +++++++++++++++++++++++++++++++++ user/edit.php | 2 +- user/editadvanced.php | 2 +- user/editlib.php | 57 ++++-------------------------- user/externallib.php | 24 +++++++++++++ user/tests/externallib_test.php | 31 +++++++++++++++++ 6 files changed, 125 insertions(+), 52 deletions(-) diff --git a/lib/classes/user.php b/lib/classes/user.php index a730cc07a369d..5a94658ed47ef 100644 --- a/lib/classes/user.php +++ b/lib/classes/user.php @@ -278,6 +278,67 @@ public static function require_active_user($user, $checksuspended = false, $chec } } + /** + * Updates the provided users profile picture based upon the expected fields returned from the edit or edit_advanced forms. + * + * @param stdClass $usernew An object that contains some information about the user being updated + * @param array $filemanageroptions + * @return bool True if the user was updated, false if it stayed the same. + */ + public static function update_picture(stdClass $usernew, $filemanageroptions = array()) { + global $CFG, $DB; + require_once("$CFG->libdir/gdlib.php"); + + $context = context_user::instance($usernew->id, MUST_EXIST); + $user = core_user::get_user($usernew->id, 'id, picture', MUST_EXIST); + + $newpicture = $user->picture; + // Get file_storage to process files. + $fs = get_file_storage(); + if (!empty($usernew->deletepicture)) { + // The user has chosen to delete the selected users picture. + $fs->delete_area_files($context->id, 'user', 'icon'); // Drop all images in area. + $newpicture = 0; + + } else { + // Save newly uploaded file, this will avoid context mismatch for newly created users. + file_save_draft_area_files($usernew->imagefile, $context->id, 'user', 'newicon', 0, $filemanageroptions); + if (($iconfiles = $fs->get_area_files($context->id, 'user', 'newicon')) && count($iconfiles) == 2) { + // Get file which was uploaded in draft area. + foreach ($iconfiles as $file) { + if (!$file->is_directory()) { + break; + } + } + // Copy file to temporary location and the send it for processing icon. + if ($iconfile = $file->copy_content_to_temp()) { + // There is a new image that has been uploaded. + // Process the new image and set the user to make use of it. + // NOTE: Uploaded images always take over Gravatar. + $newpicture = (int)process_new_icon($context, 'user', 'icon', 0, $iconfile); + // Delete temporary file. + @unlink($iconfile); + // Remove uploaded file. + $fs->delete_area_files($context->id, 'user', 'newicon'); + } else { + // Something went wrong while creating temp file. + // Remove uploaded file. + $fs->delete_area_files($context->id, 'user', 'newicon'); + return false; + } + } + } + + if ($newpicture != $user->picture) { + $DB->set_field('user', 'picture', $newpicture, array('id' => $user->id)); + return true; + } else { + return false; + } + } + + + /** * Definition of user profile fields and the expected parameter type for data validation. * diff --git a/user/edit.php b/user/edit.php index 4e141b99ad3bd..a3341f07045cb 100644 --- a/user/edit.php +++ b/user/edit.php @@ -236,7 +236,7 @@ // Update user picture. if (empty($CFG->disableuserimages)) { - useredit_update_picture($usernew, $userform, $filemanageroptions); + core_user::update_picture($usernew, $filemanageroptions); } // Update mail bounces. diff --git a/user/editadvanced.php b/user/editadvanced.php index b0aefa6a1ef70..91788b390ca1c 100644 --- a/user/editadvanced.php +++ b/user/editadvanced.php @@ -239,7 +239,7 @@ // Update user picture. if (empty($USER->newadminuser)) { - useredit_update_picture($usernew, $userform, $filemanageroptions); + core_user::update_picture($usernew, $filemanageroptions); } // Update mail bounces. diff --git a/user/editlib.php b/user/editlib.php index 3cf9ed56ce8df..464adac21840a 100644 --- a/user/editlib.php +++ b/user/editlib.php @@ -164,62 +164,19 @@ function useredit_update_user_preference($usernew) { /** * Updates the provided users profile picture based upon the expected fields returned from the edit or edit_advanced forms. * + * @deprecated since Moodle 3.2 MDL-51789 - please use core_user::update_picture() instead. + * @todo MDL-54858 This will be deleted in Moodle 3.5. + * @see core_user::update_picture() + * * @global moodle_database $DB * @param stdClass $usernew An object that contains some information about the user being updated - * @param moodleform $userform The form that was submitted to edit the form + * @param moodleform $userform The form that was submitted to edit the form (unused) * @param array $filemanageroptions * @return bool True if the user was updated, false if it stayed the same. */ function useredit_update_picture(stdClass $usernew, moodleform $userform, $filemanageroptions = array()) { - global $CFG, $DB; - require_once("$CFG->libdir/gdlib.php"); - - $context = context_user::instance($usernew->id, MUST_EXIST); - $user = $DB->get_record('user', array('id' => $usernew->id), 'id, picture', MUST_EXIST); - - $newpicture = $user->picture; - // Get file_storage to process files. - $fs = get_file_storage(); - if (!empty($usernew->deletepicture)) { - // The user has chosen to delete the selected users picture. - $fs->delete_area_files($context->id, 'user', 'icon'); // Drop all images in area. - $newpicture = 0; - - } else { - // Save newly uploaded file, this will avoid context mismatch for newly created users. - file_save_draft_area_files($usernew->imagefile, $context->id, 'user', 'newicon', 0, $filemanageroptions); - if (($iconfiles = $fs->get_area_files($context->id, 'user', 'newicon')) && count($iconfiles) == 2) { - // Get file which was uploaded in draft area. - foreach ($iconfiles as $file) { - if (!$file->is_directory()) { - break; - } - } - // Copy file to temporary location and the send it for processing icon. - if ($iconfile = $file->copy_content_to_temp()) { - // There is a new image that has been uploaded. - // Process the new image and set the user to make use of it. - // NOTE: Uploaded images always take over Gravatar. - $newpicture = (int)process_new_icon($context, 'user', 'icon', 0, $iconfile); - // Delete temporary file. - @unlink($iconfile); - // Remove uploaded file. - $fs->delete_area_files($context->id, 'user', 'newicon'); - } else { - // Something went wrong while creating temp file. - // Remove uploaded file. - $fs->delete_area_files($context->id, 'user', 'newicon'); - return false; - } - } - } - - if ($newpicture != $user->picture) { - $DB->set_field('user', 'picture', $newpicture, array('id' => $user->id)); - return true; - } else { - return false; - } + debugging('useredit_update_picture() is deprecated. Please use core_user::update_picture() instead.', DEBUG_DEVELOPER); + return core_user::update_picture($usernew, $filemanageroptions); } /** diff --git a/user/externallib.php b/user/externallib.php index 426b11d71727d..9260620cc880f 100644 --- a/user/externallib.php +++ b/user/externallib.php @@ -386,6 +386,9 @@ public static function update_users_parameters() { new external_value(core_user::get_property_type('middlename'), 'The middle name of the user', VALUE_OPTIONAL), 'alternatename' => new external_value(core_user::get_property_type('alternatename'), 'The alternate name of the user', VALUE_OPTIONAL), + 'userpicture' => + new external_value(PARAM_INT, 'The itemid where the new user picture '. + 'has been uploaded to, 0 to delete', VALUE_OPTIONAL), 'customfields' => new external_multiple_structure( new external_single_structure( array( @@ -426,10 +429,31 @@ public static function update_users($users) { $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users)); + $filemanageroptions = array('maxbytes' => $CFG->maxbytes, + 'subdirs' => 0, + 'maxfiles' => 1, + 'accepted_types' => 'web_image'); + $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { user_update_user($user, true, false); + + // Update user picture if it was specified for this user. + if (empty($CFG->disableuserimages) && isset($user['userpicture'])) { + $userobject = (object)$user; + + $userobject->deletepicture = null; + + if ($user['userpicture'] == 0) { + $userobject->deletepicture = true; + } else { + $userobject->imagefile = $user['userpicture']; + } + + core_user::update_picture($userobject, $filemanageroptions); + } + // Update user custom fields. if (!empty($user['customfields'])) { diff --git a/user/tests/externallib_test.php b/user/tests/externallib_test.php index 54eb4e578d36c..c965b4208f97c 100644 --- a/user/tests/externallib_test.php +++ b/user/tests/externallib_test.php @@ -566,6 +566,22 @@ public function test_update_users() { $this->resetAfterTest(true); + $wsuser = self::getDataGenerator()->create_user(); + self::setUser($wsuser); + + $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); + $draftfile = external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile); + + $draftid = $draftfile['itemid']; + $user1 = self::getDataGenerator()->create_user(); $user1 = array( @@ -582,6 +598,7 @@ public function test_update_users() { 'email' => 'usertest1@example.com', 'description' => 'This is a description for user 1', 'city' => 'Perth', + 'userpicture' => $draftid, 'country' => 'AU' ); @@ -600,6 +617,20 @@ public function test_update_users() { $this->assertEquals($dbuser->description, $user1['description']); $this->assertEquals($dbuser->city, $user1['city']); $this->assertEquals($dbuser->country, $user1['country']); + $this->assertNotEquals(0, $dbuser->picture, 'Picture must be set to the new icon itemid for this user'); + + // Confirm no picture change when parameter is not supplied. + unset($user1['userpicture']); + core_user_external::update_users(array($user1)); + $dbusernopic = $DB->get_record('user', array('id' => $user1['id'])); + $this->assertEquals($dbuser->picture, $dbusernopic->picture, 'Picture not change without the parameter.'); + + // Confirm delete of picture deletes the picture from the user record. + $user1['userpicture'] = 0; + core_user_external::update_users(array($user1)); + $dbuserdelpic = $DB->get_record('user', array('id' => $user1['id'])); + $this->assertEquals(0, $dbuserdelpic->picture, 'Picture must be deleted when sent as 0.'); + // Call without required capability. $this->unassignUserCapability('moodle/user:update', $context->id, $roleid);