diff options
author | blizzz <blizzz@owncloud.com> | 2013-11-26 12:05:32 -0800 |
---|---|---|
committer | blizzz <blizzz@owncloud.com> | 2013-11-26 12:05:32 -0800 |
commit | 4f15282bc998bb68896b5df67f4f749dd435897d (patch) | |
tree | d30a978ee443343541cfc9f825bba229da107296 | |
parent | 1fef97f6a535cd79d0aea600634ec54c5f87bcea (diff) | |
parent | 69518b901326617a2a80986df0e250038684563b (diff) | |
download | nextcloud-server-4f15282bc998bb68896b5df67f4f749dd435897d.tar.gz nextcloud-server-4f15282bc998bb68896b5df67f4f749dd435897d.zip |
Merge pull request #6058 from owncloud/ldap2avatar
Set Avatar for LDAP users automatically (if a picture is available)
-rw-r--r-- | apps/user_ldap/group_proxy.php | 5 | ||||
-rw-r--r-- | apps/user_ldap/lib/access.php | 4 | ||||
-rw-r--r-- | apps/user_ldap/lib/configuration.php | 3 | ||||
-rw-r--r-- | apps/user_ldap/lib/proxy.php | 7 | ||||
-rw-r--r-- | apps/user_ldap/user_ldap.php | 76 | ||||
-rw-r--r-- | apps/user_ldap/user_proxy.php | 15 | ||||
-rw-r--r-- | lib/private/avatar.php | 10 | ||||
-rw-r--r-- | lib/private/user.php | 16 | ||||
-rw-r--r-- | lib/private/user/backend.php | 15 | ||||
-rw-r--r-- | lib/private/user/user.php | 12 | ||||
-rw-r--r-- | settings/personal.php | 1 | ||||
-rw-r--r-- | settings/templates/personal.php | 4 | ||||
-rw-r--r-- | tests/lib/user/avataruserdummy.php | 27 | ||||
-rw-r--r-- | tests/lib/user/user.php | 69 |
14 files changed, 245 insertions, 19 deletions
diff --git a/apps/user_ldap/group_proxy.php b/apps/user_ldap/group_proxy.php index acc563c9532..4404bd7fe3a 100644 --- a/apps/user_ldap/group_proxy.php +++ b/apps/user_ldap/group_proxy.php @@ -67,16 +67,17 @@ class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface { * @param $gid string, the gid connected to the request * @param $method string, the method of the group backend that shall be called * @param $parameters an array of parameters to be passed + * @param $passOnWhen the result matches this variable * @return mixed, the result of the method or false */ - protected function callOnLastSeenOn($gid, $method, $parameters) { + protected function callOnLastSeenOn($gid, $method, $parameters, $passOnWhen) { $cacheKey = $this->getGroupCacheKey($gid);; $prefix = $this->getFromCache($cacheKey); //in case the uid has been found in the past, try this stored connection first if(!is_null($prefix)) { if(isset($this->backends[$prefix])) { $result = call_user_func_array(array($this->backends[$prefix], $method), $parameters); - if(!$result) { + if($result === $passOnWhen) { //not found here, reset cache to null if group vanished //because sometimes methods return false with a reason $groupExists = call_user_func_array( diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index a07bd3fa11f..ecc74b6cf54 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -199,7 +199,9 @@ class Access extends LDAPUtility { */ public function username2dn($name) { $dn = $this->ocname2dn($name, true); - if($dn) { + //Check whether the DN belongs to the Base, to avoid issues on multi- + //server setups + if($dn && $this->isDNPartOfBase($dn, $this->connection->ldapBaseUsers)) { return $dn; } diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index e14ed824a74..58f4b11e690 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -72,6 +72,7 @@ class Configuration { 'ldapExpertUsernameAttr' => null, 'ldapExpertUUIDUserAttr' => null, 'ldapExpertUUIDGroupAttr' => null, + 'lastJpegPhotoLookup' => null, ); public function __construct($configPrefix, $autoread = true) { @@ -330,6 +331,7 @@ class Configuration { 'ldap_expert_uuid_user_attr' => '', 'ldap_expert_uuid_group_attr' => '', 'has_memberof_filter_support' => 0, + 'last_jpegPhoto_lookup' => 0, ); } @@ -377,6 +379,7 @@ class Configuration { 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr', 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr', 'has_memberof_filter_support' => 'hasMemberOfFilterSupport', + 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup', ); return $array; } diff --git a/apps/user_ldap/lib/proxy.php b/apps/user_ldap/lib/proxy.php index c74b357bdd2..30e1875901c 100644 --- a/apps/user_ldap/lib/proxy.php +++ b/apps/user_ldap/lib/proxy.php @@ -54,7 +54,7 @@ abstract class Proxy { return 'group-'.$gid.'-lastSeenOn'; } - abstract protected function callOnLastSeenOn($id, $method, $parameters); + abstract protected function callOnLastSeenOn($id, $method, $parameters, $passOnWhen); abstract protected function walkBackends($id, $method, $parameters); /** @@ -64,8 +64,9 @@ abstract class Proxy { * @param $parameters an array of parameters to be passed * @return mixed, the result of the specified method */ - protected function handleRequest($id, $method, $parameters) { - if(!$result = $this->callOnLastSeenOn($id, $method, $parameters)) { + protected function handleRequest($id, $method, $parameters, $passOnWhen = false) { + $result = $this->callOnLastSeenOn($id, $method, $parameters, $passOnWhen); + if($result === $passOnWhen) { $result = $this->walkBackends($id, $method, $parameters); } return $result; diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index 6f52bbdf233..527a5c10b85 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -70,6 +70,74 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface { } /** + * @brief reads jpegPhoto and set is as avatar if available + * @param $uid string ownCloud user name + * @param $dn string the user's LDAP DN + * @return void + */ + private function updateAvatar($uid, $dn) { + $hasLoggedIn = \OCP\Config::getUserValue($uid, 'user_ldap', + 'firstLoginAccomplished', 0); + $lastChecked = \OCP\Config::getUserValue($uid, 'user_ldap', + 'lastJpegPhotoLookup', 0); + if(($hasLoggedIn !== '1') || (time() - intval($lastChecked)) < 86400 ) { + //update only once a day + return; + } + + $jpegPhoto = $this->access->readAttribute($dn, 'jpegPhoto'); + \OCP\Config::setUserValue($uid, 'user_ldap', 'lastJpegPhotoLookup', time()); + if(!$jpegPhoto || !is_array($jpegPhoto) || !isset($jpegPhoto[0])) { + //not set, nothing left to do; + return; + } + + $image = new \OCP\Image(); + $image->loadFromBase64(base64_encode($jpegPhoto[0])); + + if(!$image->valid()) { + \OCP\Util::writeLog('user_ldap', 'jpegPhoto data invalid for '.$dn, + \OCP\Util::ERROR); + return; + } + //make sure it is a square and not bigger than 128x128 + $size = min(array($image->width(), $image->height(), 128)); + if(!$image->centerCrop($size)) { + \OCP\Util::writeLog('user_ldap', + 'croping image for avatar failed for '.$dn, + \OCP\Util::ERROR); + return; + } + + if(!\OC\Files\Filesystem::$loaded) { + \OC_Util::setupFS($uid); + } + + $avatarManager = \OC::$server->getAvatarManager(); + $avatar = $avatarManager->getAvatar($uid); + $avatar->set($image); + } + + /** + * @brief checks whether the user is allowed to change his avatar in ownCloud + * @param $uid string the ownCloud user name + * @return boolean either the user can or cannot + */ + public function canChangeAvatar($uid) { + $dn = $this->access->username2dn($uid); + if(!$dn) { + return false; + } + $jpegPhoto = $this->access->readAttribute($dn, 'jpegPhoto'); + if(!$jpegPhoto || !is_array($jpegPhoto) || !isset($jpegPhoto[0])) { + //The user is allowed to change his avatar in ownCloud only if no + //avatar is provided by LDAP + return true; + } + return false; + } + + /** * @brief Check if the password is correct * @param $uid The username * @param $password The password @@ -100,6 +168,10 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface { return false; } + \OCP\Config::setUserValue($ocname, 'user_ldap', + 'firstLoginAccomplished', 1); + + $this->updateAvatar($ocname, $dn); //give back the display name return $ocname; } @@ -173,6 +245,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface { $this->access->connection->writeToCache('userExists'.$uid, true); $this->updateQuota($dn); + $this->updateAvatar($uid, $dn); return true; } @@ -289,7 +362,8 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface { public function implementsActions($actions) { return (bool)((OC_USER_BACKEND_CHECK_PASSWORD | OC_USER_BACKEND_GET_HOME - | OC_USER_BACKEND_GET_DISPLAYNAME) + | OC_USER_BACKEND_GET_DISPLAYNAME + | OC_USER_BACKEND_PROVIDE_AVATAR) & $actions); } diff --git a/apps/user_ldap/user_proxy.php b/apps/user_ldap/user_proxy.php index 092fdbf7c78..b073b143e74 100644 --- a/apps/user_ldap/user_proxy.php +++ b/apps/user_ldap/user_proxy.php @@ -54,6 +54,7 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface { protected function walkBackends($uid, $method, $parameters) { $cacheKey = $this->getUserCacheKey($uid); foreach($this->backends as $configPrefix => $backend) { +// print("walkBackend '$configPrefix'<br/>"); if($result = call_user_func_array(array($backend, $method), $parameters)) { $this->writeToCache($cacheKey, $configPrefix); return $result; @@ -67,16 +68,17 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface { * @param $uid string, the uid connected to the request * @param $method string, the method of the user backend that shall be called * @param $parameters an array of parameters to be passed + * @param $passOnWhen the result matches this variable * @return mixed, the result of the method or false */ - protected function callOnLastSeenOn($uid, $method, $parameters) { + protected function callOnLastSeenOn($uid, $method, $parameters, $passOnWhen) { $cacheKey = $this->getUserCacheKey($uid); $prefix = $this->getFromCache($cacheKey); //in case the uid has been found in the past, try this stored connection first if(!is_null($prefix)) { if(isset($this->backends[$prefix])) { $result = call_user_func_array(array($this->backends[$prefix], $method), $parameters); - if(!$result) { + if($result === $passOnWhen) { //not found here, reset cache to null if user vanished //because sometimes methods return false with a reason $userExists = call_user_func_array( @@ -164,6 +166,15 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface { } /** + * @brief checks whether the user is allowed to change his avatar in ownCloud + * @param $uid string the ownCloud user name + * @return boolean either the user can or cannot + */ + public function canChangeAvatar($uid) { + return $this->handleRequest($uid, 'canChangeAvatar', array($uid), true); + } + + /** * @brief Get a list of all display names * @returns array with all displayNames (value) and the corresponding uids (key) * diff --git a/lib/private/avatar.php b/lib/private/avatar.php index 814a9b22bed..e97f55eecaf 100644 --- a/lib/private/avatar.php +++ b/lib/private/avatar.php @@ -44,15 +44,19 @@ class OC_Avatar implements \OCP\IAvatar { /** * @brief sets the users avatar - * @param $data mixed imagedata or path to set a new avatar + * @param $data mixed OC_Image, imagedata or path to set a new avatar * @throws Exception if the provided file is not a jpg or png image * @throws Exception if the provided image is not valid * @throws \OC\NotSquareException if the image is not square * @return void */ public function set ($data) { - - $img = new OC_Image($data); + if($data instanceOf OC_Image) { + $img = $data; + $data = $img->data(); + } else { + $img = new OC_Image($data); + } $type = substr($img->mimeType(), -3); if ($type === 'peg') { $type = 'jpg'; diff --git a/lib/private/user.php b/lib/private/user.php index 5bd36006750..210e5ed3f02 100644 --- a/lib/private/user.php +++ b/lib/private/user.php @@ -425,6 +425,22 @@ class OC_User { } /** + * @brief Check whether user can change his avatar + * @param string $uid The username + * @return bool + * + * Check whether a specified user can change his avatar + */ + public static function canUserChangeAvatar($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->canChangeAvatar(); + } else { + return false; + } + } + + /** * @brief Check whether user can change his password * @param string $uid The username * @return bool diff --git a/lib/private/user/backend.php b/lib/private/user/backend.php index e9be08e429c..02c93d13bdf 100644 --- a/lib/private/user/backend.php +++ b/lib/private/user/backend.php @@ -31,13 +31,13 @@ define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501); /** * actions that user backends can define */ -define('OC_USER_BACKEND_CREATE_USER', 0x000001); -define('OC_USER_BACKEND_SET_PASSWORD', 0x000010); -define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100); -define('OC_USER_BACKEND_GET_HOME', 0x001000); -define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000); -define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x100000); - +define('OC_USER_BACKEND_CREATE_USER', 0x0000001); +define('OC_USER_BACKEND_SET_PASSWORD', 0x0000010); +define('OC_USER_BACKEND_CHECK_PASSWORD', 0x0000100); +define('OC_USER_BACKEND_GET_HOME', 0x0001000); +define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x0010000); +define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x0100000); +define('OC_USER_BACKEND_PROVIDE_AVATAR', 0x1000000); /** * Abstract base class for user management. Provides methods for querying backend @@ -54,6 +54,7 @@ abstract class OC_User_Backend implements OC_User_Interface { OC_USER_BACKEND_GET_HOME => 'getHome', OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName', OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName', + OC_USER_BACKEND_PROVIDE_AVATAR => 'canChangeAvatar', ); /** diff --git a/lib/private/user/user.php b/lib/private/user/user.php index e5f842944f1..e773473ec41 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -140,6 +140,18 @@ class User { } /** + * check if the backend allows the user to change his avatar on Personal page + * + * @return bool + */ + public function canChangeAvatar() { + if($this->backend->implementsActions(\OC_USER_BACKEND_PROVIDE_AVATAR)) { + return $this->backend->canChangeAvatar($this->uid); + } + return true; + } + + /** * check if the backend supports changing passwords * * @return bool diff --git a/settings/personal.php b/settings/personal.php index 670e18e20ef..44e1048941b 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -90,6 +90,7 @@ $tmpl->assign('displayNameChangeSupported', OC_User::canUserChangeDisplayName(OC $tmpl->assign('displayName', OC_User::getDisplayName()); $tmpl->assign('enableDecryptAll' , $enableDecryptAll); $tmpl->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true)); +$tmpl->assign('avatarChangeSupported', OC_User::canUserChangeAvatar(OC_User::getUser())); $forms=OC_App::getForms('personal'); $tmpl->assign('forms', array()); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index a79eeefa796..3eb864655bb 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -87,11 +87,15 @@ if($_['passwordChangeSupported']) { <div id="displayavatar"> <div class="avatardiv"></div><br> <div class="warning hidden"></div> + <?php if ($_['avatarChangeSupported']): ?> <div class="inlineblock button" id="uploadavatarbutton"><?php p($l->t('Upload new')); ?></div> <input type="file" class="hidden" name="files[]" id="uploadavatar"> <div class="inlineblock button" id="selectavatar"><?php p($l->t('Select new from Files')); ?></div> <div class="inlineblock button" id="removeavatar"><?php p($l->t('Remove image')); ?></div><br> <?php p($l->t('Either png or jpg. Ideally square but you will be able to crop it.')); ?> + <?php else: ?> + <?php p($l->t('Your avatar is provided by your original account.')); ?> + <?php endif; ?> </div> <div id="cropper" class="hidden"> <div class="inlineblock button" id="abortcropperbutton"><?php p($l->t('Abort')); ?></div> diff --git a/tests/lib/user/avataruserdummy.php b/tests/lib/user/avataruserdummy.php new file mode 100644 index 00000000000..738b10492ea --- /dev/null +++ b/tests/lib/user/avataruserdummy.php @@ -0,0 +1,27 @@ +<?php +/** +* ownCloud +* +* @author Arthur Schiwon +* @copyright 2013 Arthur Schiwon blizzz@owncloud.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +class Avatar_User_Dummy extends \OC_User_Dummy { + public function canChangeAvatar($uid) { + return true; + } +}
\ No newline at end of file diff --git a/tests/lib/user/user.php b/tests/lib/user/user.php index de5ccbf38c1..0bbcda013ce 100644 --- a/tests/lib/user/user.php +++ b/tests/lib/user/user.php @@ -87,6 +87,75 @@ class User extends \PHPUnit_Framework_TestCase { $this->assertFalse($user->setPassword('bar','')); } + public function testChangeAvatarSupportedYes() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + require_once 'avataruserdummy.php'; + $backend = $this->getMock('Avatar_User_Dummy'); + $backend->expects($this->once()) + ->method('canChangeAvatar') + ->with($this->equalTo('foo')) + ->will($this->returnValue(true)); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnCallback(function ($actions) { + if ($actions === \OC_USER_BACKEND_PROVIDE_AVATAR) { + return true; + } else { + return false; + } + })); + + $user = new \OC\User\User('foo', $backend); + $this->assertTrue($user->canChangeAvatar()); + } + + public function testChangeAvatarSupportedNo() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + require_once 'avataruserdummy.php'; + $backend = $this->getMock('Avatar_User_Dummy'); + $backend->expects($this->once()) + ->method('canChangeAvatar') + ->with($this->equalTo('foo')) + ->will($this->returnValue(false)); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnCallback(function ($actions) { + if ($actions === \OC_USER_BACKEND_PROVIDE_AVATAR) { + return true; + } else { + return false; + } + })); + + $user = new \OC\User\User('foo', $backend); + $this->assertFalse($user->canChangeAvatar()); + } + + public function testChangeAvatarNotSupported() { + /** + * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend + */ + require_once 'avataruserdummy.php'; + $backend = $this->getMock('Avatar_User_Dummy'); + $backend->expects($this->never()) + ->method('canChangeAvatar'); + + $backend->expects($this->any()) + ->method('implementsActions') + ->will($this->returnCallback(function ($actions) { + return false; + })); + + $user = new \OC\User\User('foo', $backend); + $this->assertTrue($user->canChangeAvatar()); + } + public function testDelete() { /** * @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend |