diff options
-rw-r--r-- | apps/files/templates/appnavigation.php | 4 | ||||
-rw-r--r-- | apps/files_external/lib/sftp.php | 38 | ||||
-rw-r--r-- | apps/files_external/tests/backends/sftp.php | 38 | ||||
-rw-r--r-- | apps/files_sharing/api/ocssharewrapper.php | 14 | ||||
-rw-r--r-- | apps/files_sharing/api/share20ocs.php | 100 | ||||
-rw-r--r-- | apps/files_sharing/tests/api/share20ocstest.php | 259 | ||||
-rw-r--r-- | apps/provisioning_api/appinfo/routes.php | 2 | ||||
-rw-r--r-- | apps/provisioning_api/lib/users.php | 45 | ||||
-rw-r--r-- | apps/provisioning_api/tests/userstest.php | 381 | ||||
-rw-r--r-- | core/css/apps.css | 9 | ||||
-rw-r--r-- | core/css/inputs.css | 232 | ||||
-rw-r--r-- | core/css/styles.css | 246 | ||||
-rw-r--r-- | core/js/js.js | 6 | ||||
-rw-r--r-- | core/shipped.json | 3 | ||||
-rw-r--r-- | lib/private/share20/defaultshareprovider.php | 9 | ||||
-rw-r--r-- | lib/private/share20/ishare.php | 21 | ||||
-rw-r--r-- | lib/private/share20/share.php | 57 | ||||
-rw-r--r-- | lib/private/template.php | 1 | ||||
-rw-r--r-- | tests/lib/share20/defaultshareprovidertest.php | 2 |
19 files changed, 1148 insertions, 319 deletions
diff --git a/apps/files/templates/appnavigation.php b/apps/files/templates/appnavigation.php index 512300e3a58..d05a02ee7db 100644 --- a/apps/files/templates/appnavigation.php +++ b/apps/files/templates/appnavigation.php @@ -16,9 +16,7 @@ </button> </div> <div id="app-settings-content"> - <h2> - <label for="webdavurl"><?php p($l->t('WebDAV'));?></label> - </h2> + <label for="webdavurl"><?php p($l->t('WebDAV'));?></label> <input id="webdavurl" type="text" readonly="readonly" value="<?php p(\OCP\Util::linkToRemote('webdav')); ?>" /> <em><?php print_unescaped($l->t('Use this address to <a href="%s" target="_blank">access your Files via WebDAV</a>', array(link_to_docs('user-webdav'))));?></em> </div> diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php index 5dcc7686ca3..f8651727fd2 100644 --- a/apps/files_external/lib/sftp.php +++ b/apps/files_external/lib/sftp.php @@ -52,27 +52,37 @@ class SFTP extends \OC\Files\Storage\Common { protected $client; /** + * @param string $host protocol://server:port + * @return array [$server, $port] + */ + private function splitHost($host) { + $input = $host; + if (strpos($host, '://') === false) { + // add a protocol to fix parse_url behavior with ipv6 + $host = 'http://' . $host; + } + + $parsed = parse_url($host); + if(is_array($parsed) && isset($parsed['port'])) { + return [$parsed['host'], $parsed['port']]; + } else if (is_array($parsed)) { + return [$parsed['host'], 22]; + } else { + return [$input, 22]; + } + } + + /** * {@inheritdoc} */ public function __construct($params) { // Register sftp:// Stream::register(); - $this->host = $params['host']; + $parsedHost = $this->splitHost($params['host']); - //deals with sftp://server example - $proto = strpos($this->host, '://'); - if ($proto != false) { - $this->host = substr($this->host, $proto+3); - } - - //deals with server:port - $hasPort = strpos($this->host,':'); - if($hasPort != false) { - $pieces = explode(":", $this->host); - $this->host = $pieces[0]; - $this->port = $pieces[1]; - } + $this->host = $parsedHost[0]; + $this->port = $parsedHost[1]; $this->user = $params['user']; diff --git a/apps/files_external/tests/backends/sftp.php b/apps/files_external/tests/backends/sftp.php index da2c0ac6ba2..aaed2b3460a 100644 --- a/apps/files_external/tests/backends/sftp.php +++ b/apps/files_external/tests/backends/sftp.php @@ -26,6 +26,11 @@ namespace Test\Files\Storage; class SFTP extends Storage { + /** + * @var \OC\Files\Storage\SFTP instance + */ + protected $instance; + private $config; protected function setUp() { @@ -103,6 +108,39 @@ class SFTP extends Storage { ], 'sftp::someuser@somehost:8822//remotedir/subdir/', ], + [ + // ipv6 with port + [ + 'run' => true, + 'host' => 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80:0000:0000:0000:0202:B3FF:FE1E:8329//remotedir/subdir/', + ], + [ + // ipv6 without port + [ + 'run' => true, + 'host' => 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329:8822', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80:0000:0000:0000:0202:B3FF:FE1E:8329:8822//remotedir/subdir/', + ], + [ + // collapsed ipv6 with port + [ + 'run' => true, + 'host' => 'FE80::0202:B3FF:FE1E:8329:8822', + 'user' => 'someuser', + 'password' => 'somepassword', + 'root' => 'remotedir/subdir/', + ], + 'sftp::someuser@FE80::0202:B3FF:FE1E:8329:8822//remotedir/subdir/', + ], ]; } } diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php index 8c0d8f7d150..3ce2901dfb4 100644 --- a/apps/files_sharing/api/ocssharewrapper.php +++ b/apps/files_sharing/api/ocssharewrapper.php @@ -35,15 +35,16 @@ class OCSShareWrapper { \OC::$server->getUserFolder(), new \OC\Share20\DefaultShareProvider( \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getGroupManager(), - \OC::$server->getUserFolder() + \OC::$server->getUserManager(), + \OC::$server->getGroupManager(), + \OC::$server->getUserFolder() ) ), \OC::$server->getGroupManager(), \OC::$server->getUserManager(), \OC::$server->getRequest(), - \OC::$server->getUserFolder()); + \OC::$server->getUserFolder(), + \OC::$server->getURLGenerator()); } public function getAllShares($params) { @@ -55,7 +56,8 @@ class OCSShareWrapper { } public function getShare($params) { - return \OCA\Files_Sharing\API\Local::getShare($params); + $id = $params['id']; + return $this->getShare20OCS()->getShare($id); } public function updateShare($params) { @@ -63,7 +65,7 @@ class OCSShareWrapper { } public function deleteShare($params) { - $id = (int)$params['id']; + $id = $params['id']; return $this->getShare20OCS()->deleteShare($id); } } diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index 8a7f90c0023..aaf5a3c72b6 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -20,39 +20,125 @@ */ namespace OCA\Files_Sharing\API; +use OC\Share20\IShare; + class Share20OCS { - /** @var OC\Share20\Manager */ + /** @var \OC\Share20\Manager */ private $shareManager; - /** @var OCP\IGroupManager */ + /** @var \OCP\IGroupManager */ private $groupManager; - /** @var OCP\IUserManager */ + /** @var \OCP\IUserManager */ private $userManager; - /** @var OCP\IRequest */ + /** @var \OCP\IRequest */ private $request; - /** @var OCP\Files\Folder */ + /** @var \OCP\Files\Folder */ private $userFolder; public function __construct(\OC\Share20\Manager $shareManager, \OCP\IGroupManager $groupManager, \OCP\IUserManager $userManager, \OCP\IRequest $request, - \OCP\Files\Folder $userFolder) { + \OCP\Files\Folder $userFolder, + \OCP\IURLGenerator $urlGenerator) { $this->shareManager = $shareManager; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->request = $request; $this->userFolder = $userFolder; + $this->urlGenerator = $urlGenerator; + } + + /** + * Convert an IShare to an array for OCS output + * + * @param IShare $share + * @return array + */ + protected function formatShare($share) { + $result = [ + 'id' => $share->getId(), + 'share_type' => $share->getShareType(), + 'uid_owner' => $share->getSharedBy()->getUID(), + 'displayname_owner' => $share->getSharedBy()->getDisplayName(), + 'permissions' => $share->getPermissions(), + 'stime' => $share->getShareTime(), + 'parent' => $share->getParent(), + 'expiration' => null, + 'token' => null, + ]; + + $path = $share->getPath(); + $result['path'] = $this->userFolder->getRelativePath($path->getPath()); + if ($path instanceOf \OCP\Files\Folder) { + $result['item_type'] = 'folder'; + } else { + $result['item_type'] = 'file'; + } + $result['storage_id'] = $path->getStorage()->getId(); + $result['storage'] = \OC\Files\Cache\Storage::getNumericStorageId($path->getStorage()->getId()); + $result['item_source'] = $path->getId(); + $result['file_source'] = $path->getId(); + $result['file_parent'] = $path->getParent()->getId(); + $result['file_target'] = $share->getTarget(); + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + $sharedWith = $share->getSharedWith(); + $result['share_with'] = $sharedWith->getUID(); + $result['share_with_displayname'] = $sharedWith->getDisplayName(); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $sharedWith = $share->getSharedWith(); + $result['share_with'] = $sharedWith->getGID(); + $result['share_with_displayname'] = $sharedWith->getGID(); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { + + $result['share_with'] = $share->getPassword(); + $result['share_with_displayname'] = $share->getPassword(); + + $result['token'] = $share->getToken(); + $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); + + $expiration = $share->getExpirationDate(); + if ($expiration !== null) { + $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); + } + + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) { + $result['share_with'] = $share->getSharedWith(); + $result['share_with_displayname'] = $share->getSharedWith(); + $result['token'] = $share->getToken(); + } + + $result['mail_send'] = $share->getMailSend() ? 1 : 0; + + return $result; + } + + /** + * Get a specific share by id + * + * @param string $id + * @return \OC_OCS_Result + */ + public function getShare($id) { + try { + $share = $this->shareManager->getShareById($id); + } catch (\OC\Share20\Exception\ShareNotFound $e) { + return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); + } + + $share = $this->formatShare($share); + return new \OC_OCS_Result($share); } /** * Delete a share * - * @param int $id + * @param string $id * @return \OC_OCS_Result */ public function deleteShare($id) { diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php index 9c4377a2a7f..f74585eb47d 100644 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ b/apps/files_sharing/tests/api/share20ocstest.php @@ -39,6 +39,9 @@ class Share20OCSTest extends \Test\TestCase { /** @var OCP\Files\Folder */ private $userFolder; + /** @var OCP\IURLGenerator */ + private $urlGenerator; + /** @var OCS */ private $ocs; @@ -46,24 +49,18 @@ class Share20OCSTest extends \Test\TestCase { $this->shareManager = $this->getMockBuilder('OC\Share20\Manager') ->disableOriginalConstructor() ->getMock(); - $this->groupManager = $this->getMockBuilder('OCP\IGroupManager') - ->disableOriginalConstructor() - ->getMock(); - $this->userManager = $this->getMockBuilder('OCP\IUserManager') - ->disableOriginalConstructor() - ->getMock(); - $this->request = $this->getMockBuilder('OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->userFolder = $this->getMockBuilder('OCP\Files\Folder') - ->disableOriginalConstructor() - ->getMock(); + $this->groupManager = $this->getMock('OCP\IGroupManager'); + $this->userManager = $this->getMock('OCP\IUserManager'); + $this->request = $this->getMock('OCP\IRequest'); + $this->userFolder = $this->getMock('OCP\Files\Folder'); + $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); $this->ocs = new Share20OCS($this->shareManager, $this->groupManager, $this->userManager, $this->request, - $this->userFolder); + $this->userFolder, + $this->urlGenerator); } public function testDeleteShareShareNotFound() { @@ -110,4 +107,240 @@ class Share20OCSTest extends \Test\TestCase { $expected = new \OC_OCS_Result(); $this->assertEquals($expected, $this->ocs->deleteShare(42)); } + + public function testGetGetShareNotExists() { + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with(42) + ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound())); + + $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); + $this->assertEquals($expected, $this->ocs->getShare(42)); + } + + public function createShare($id, $shareType, $sharedWith, $sharedBy, $path, $permissions, + $shareTime, $expiration, $parent, $target, $mail_send, $token=null, + $password=null) { + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getId')->willReturn($id); + $share->method('getShareType')->willReturn($shareType); + $share->method('getSharedWith')->willReturn($sharedWith); + $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getPath')->willReturn($path); + $share->method('getPermissions')->willReturn($permissions); + $share->method('getShareTime')->willReturn($shareTime); + $share->method('getExpirationDate')->willReturn($expiration); + $share->method('getParent')->willReturn($parent); + $share->method('getTarget')->willReturn($target); + $share->method('getMailSend')->willReturn($mail_send); + $share->method('getToken')->willReturn($token); + $share->method('getPassword')->willReturn($password); + + return $share; + } + + public function dataGetShare() { + $data = []; + + $owner = $this->getMock('OCP\IUser'); + $owner->method('getUID')->willReturn('ownerId'); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + + $user = $this->getMock('OCP\IUser'); + $user->method('getUID')->willReturn('userId'); + $user->method('getDisplayName')->willReturn('userDisplay'); + + $group = $this->getMock('OCP\IGroup'); + $group->method('getGID')->willReturn('groupId'); + + $storage = $this->getMock('OCP\Files\Storage'); + $storage->method('getId')->willReturn('STORAGE'); + + $parentFolder = $this->getMock('OCP\Files\Folder'); + $parentFolder->method('getId')->willReturn(3); + + $file = $this->getMock('OCP\Files\File'); + $file->method('getId')->willReturn(1); + $file->method('getPath')->willReturn('file'); + $file->method('getStorage')->willReturn($storage); + $file->method('getParent')->willReturn($parentFolder); + + $folder = $this->getMock('OCP\Files\Folder'); + $folder->method('getId')->willReturn(2); + $folder->method('getPath')->willReturn('folder'); + $folder->method('getStorage')->willReturn($storage); + $folder->method('getParent')->willReturn($parentFolder); + + // File shared with user + $share = $this->createShare(100, + \OCP\Share::SHARE_TYPE_USER, + $user, + $owner, + $file, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 100, + 'share_type' => \OCP\Share::SHARE_TYPE_USER, + 'share_with' => 'userId', + 'share_with_displayname' => 'userDisplay', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'file', + 'item_source' => 1, + 'file_source' => 1, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'file', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // Folder shared with group + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_GROUP, + $group, + $owner, + $folder, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_GROUP, + 'share_with' => 'groupId', + 'share_with_displayname' => 'groupId', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // Folder shared with remote + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_REMOTE, + 'user@remote.com', + $owner, + $folder, + 4, + 5, + null, + 6, + 'target', + 0); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE, + 'share_with' => 'user@remote.com', + 'share_with_displayname' => 'user@remote.com', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + ]; + $data[] = [$share, $expected]; + + // File shared by link with Expire + $expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03'); + $share = $this->createShare(101, + \OCP\Share::SHARE_TYPE_LINK, + null, + $owner, + $folder, + 4, + 5, + $expire, + 6, + 'target', + 0, + 'token', + 'password'); + $expected = [ + 'id' => 101, + 'share_type' => \OCP\Share::SHARE_TYPE_LINK, + 'share_with' => 'password', + 'share_with_displayname' => 'password', + 'uid_owner' => 'ownerId', + 'displayname_owner' => 'ownerDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => 'token', + 'expiration' => '2000-01-02 00:00:00', + 'permissions' => 4, + 'stime' => 5, + 'parent' => 6, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => null, // HACK around static function + 'mail_send' => 0, + 'url' => 'url', + ]; + $data[] = [$share, $expected]; + + return $data; + } + + /** + * @dataProvider dataGetShare + */ + public function testGetShare(\OC\Share20\IShare $share, array $result) { + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with($share->getId()) + ->willReturn($share); + + $this->userFolder + ->method('getRelativePath') + ->will($this->returnArgument(0)); + + $this->urlGenerator + ->method('linkToRouteAbsolute') + ->willReturn('url'); + + $expected = new \OC_OCS_Result($result); + $this->assertEquals($expected->getData(), $this->ocs->getShare($share->getId())->getData()); } } diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php index db7dc0d5b42..22a923f5c20 100644 --- a/apps/provisioning_api/appinfo/routes.php +++ b/apps/provisioning_api/appinfo/routes.php @@ -37,7 +37,7 @@ $users = new \OCA\Provisioning_API\Users( \OC::$server->getLogger() ); API::register('get', '/cloud/users', [$users, 'getUsers'], 'provisioning_api', API::SUBADMIN_AUTH); -API::register('post', '/cloud/users', [$users, 'addUser'], 'provisioning_api', API::ADMIN_AUTH); +API::register('post', '/cloud/users', [$users, 'addUser'], 'provisioning_api', API::SUBADMIN_AUTH); API::register('get', '/cloud/users/{userid}', [$users, 'getUser'], 'provisioning_api', API::USER_AUTH); API::register('put', '/cloud/users/{userid}', [$users, 'editUser'], 'provisioning_api', API::USER_AUTH); API::register('delete', '/cloud/users/{userid}', [$users, 'deleteUser'], 'provisioning_api', API::SUBADMIN_AUTH); diff --git a/apps/provisioning_api/lib/users.php b/apps/provisioning_api/lib/users.php index 304fe901cfd..a2568425d0f 100644 --- a/apps/provisioning_api/lib/users.php +++ b/apps/provisioning_api/lib/users.php @@ -117,19 +117,50 @@ class Users { public function addUser() { $userId = isset($_POST['userid']) ? $_POST['userid'] : null; $password = isset($_POST['password']) ? $_POST['password'] : null; + $groups = isset($_POST['groups']) ? $_POST['groups'] : null; + $user = $this->userSession->getUser(); + $isAdmin = $this->groupManager->isAdmin($user->getUID()); + $subAdminManager = $this->groupManager->getSubAdmin(); + + if (!$isAdmin && !$subAdminManager->isSubAdmin($user)) { + return new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED); + } + if($this->userManager->userExists($userId)) { $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']); return new OC_OCS_Result(null, 102, 'User already exists'); + } + + if(is_array($groups)) { + foreach ($groups as $group) { + if(!$this->groupManager->groupExists($group)){ + return new OC_OCS_Result(null, 104, 'group '.$group.' does not exist'); + } + if(!$isAdmin && !$subAdminManager->isSubAdminofGroup($user, $this->groupManager->get($group))) { + return new OC_OCS_Result(null, 105, 'insufficient privileges for group '. $group); + } + } } else { - try { - $this->userManager->createUser($userId, $password); - $this->logger->info('Successful addUser call with userid: '.$_POST['userid'], ['app' => 'ocs_api']); - return new OC_OCS_Result(null, 100); - } catch (\Exception $e) { - $this->logger->error('Failed addUser attempt with exception: '.$e->getMessage(), ['app' => 'ocs_api']); - return new OC_OCS_Result(null, 101, 'Bad request'); + if(!$isAdmin) { + return new OC_OCS_Result(null, 106, 'no group specified (required for subadmins)'); } } + + try { + $newUser = $this->userManager->createUser($userId, $password); + $this->logger->info('Successful addUser call with userid: '.$userId, ['app' => 'ocs_api']); + + if (is_array($groups)) { + foreach ($groups as $group) { + $this->groupManager->get($group)->addUser($newUser); + $this->logger->info('Added userid '.$userId.' to group '.$group, ['app' => 'ocs_api']); + } + } + return new OC_OCS_Result(null, 100); + } catch (\Exception $e) { + $this->logger->error('Failed addUser attempt with exception: '.$e->getMessage(), ['app' => 'ocs_api']); + return new OC_OCS_Result(null, 101, 'Bad request'); + } } /** diff --git a/apps/provisioning_api/tests/userstest.php b/apps/provisioning_api/tests/userstest.php index ba4ed8a2e2f..63180eb3472 100644 --- a/apps/provisioning_api/tests/userstest.php +++ b/apps/provisioning_api/tests/userstest.php @@ -218,11 +218,95 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('error') ->with('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); $expected = new \OC_OCS_Result(null, 102, 'User already exists'); $this->assertEquals($expected, $this->api->addUser()); } + public function testAddUserNonExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['groups'] = ['NonExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('NonExistingGroup') + ->willReturn(false); + + $expected = new \OC_OCS_Result(null, 104, 'group NonExistingGroup does not exist'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserExistingGroupNonExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['groups'] = ['ExistingGroup', 'NonExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->exactly(2)) + ->method('groupExists') + ->withConsecutive( + ['ExistingGroup'], + ['NonExistingGroup'] + ) + ->will($this->returnValueMap([ + ['ExistingGroup', true], + ['NonExistingGroup', false] + ])); + + $expected = new \OC_OCS_Result(null, 104, 'group NonExistingGroup does not exist'); + $this->assertEquals($expected, $this->api->addUser()); + } + public function testAddUserSuccessful() { $_POST['userid'] = 'NewUser'; $_POST['password'] = 'PasswordOfTheNewUser'; @@ -239,6 +323,76 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('info') ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + + $expected = new \OC_OCS_Result(null, 100); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserExistingGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn(true); + $user = $this->getMock('\OCP\IUser'); + $this->userManager + ->expects($this->once()) + ->method('createUser') + ->with('NewUser', 'PasswordOfTheNewUser') + ->willReturn($user); + $group = $this->getMock('\OCP\IGroup'); + $group + ->expects($this->once()) + ->method('addUser') + ->with($user); + $this->groupManager + ->expects($this->once()) + ->method('get') + ->with('ExistingGroup') + ->willReturn($group); + $this->logger + ->expects($this->exactly(2)) + ->method('info') + ->withConsecutive( + ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']] + ); $expected = new \OC_OCS_Result(null, 100); $this->assertEquals($expected, $this->api->addUser()); @@ -261,11 +415,238 @@ class UsersTest extends OriginalTest { ->expects($this->once()) ->method('error') ->with('Failed addUser attempt with exception: User backend not found.', ['app' => 'ocs_api']); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('adminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('adminUser') + ->willReturn(true); $expected = new \OC_OCS_Result(null, 101, 'Bad request'); $this->assertEquals($expected, $this->api->addUser()); } + public function testAddUserAsRegularUser() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(false); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + + $expected = new \OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminNoGroup() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + + $expected = new \OC_OCS_Result(null, 106, 'no group specified (required for subadmins)'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminValidGroupNotSubAdmin() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup']; + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('regularUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('regularUser') + ->willReturn(false); + $existingGroup = $this->getMock('\OCP\IGroup'); + $this->groupManager + ->expects($this->once()) + ->method('get') + ->with('ExistingGroup') + ->willReturn($existingGroup); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdminOfGroup') + ->with($loggedInUser, $existingGroup) + ->wilLReturn(false); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->with() + ->willReturn($subAdminManager); + $this->groupManager + ->expects($this->once()) + ->method('groupExists') + ->with('ExistingGroup') + ->willReturn(true); + + $expected = new \OC_OCS_Result(null, 105, 'insufficient privileges for group ExistingGroup'); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testAddUserAsSubAdminExistingGroups() { + $_POST['userid'] = 'NewUser'; + $_POST['password'] = 'PasswordOfTheNewUser'; + $_POST['groups'] = ['ExistingGroup1', 'ExistingGroup2']; + $this->userManager + ->expects($this->once()) + ->method('userExists') + ->with('NewUser') + ->willReturn(false); + $loggedInUser = $this->getMock('\OCP\IUser'); + $loggedInUser + ->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('subAdminUser')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('isAdmin') + ->with('subAdminUser') + ->willReturn(false); + $this->groupManager + ->expects($this->exactly(2)) + ->method('groupExists') + ->withConsecutive( + ['ExistingGroup1'], + ['ExistingGroup2'] + ) + ->willReturn(true); + $user = $this->getMock('\OCP\IUser'); + $this->userManager + ->expects($this->once()) + ->method('createUser') + ->with('NewUser', 'PasswordOfTheNewUser') + ->willReturn($user); + $existingGroup1 = $this->getMock('\OCP\IGroup'); + $existingGroup2 = $this->getMock('\OCP\IGroup'); + $existingGroup1 + ->expects($this->once()) + ->method('addUser') + ->with($user); + $existingGroup2 + ->expects($this->once()) + ->method('addUser') + ->with($user); + $this->groupManager + ->expects($this->exactly(4)) + ->method('get') + ->withConsecutive( + ['ExistingGroup1'], + ['ExistingGroup2'], + ['ExistingGroup1'], + ['ExistingGroup2'] + ) + ->will($this->returnValueMap([ + ['ExistingGroup1', $existingGroup1], + ['ExistingGroup2', $existingGroup2] + ])); + $this->logger + ->expects($this->exactly(3)) + ->method('info') + ->withConsecutive( + ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']], + ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']] + ); + $subAdminManager = $this->getMockBuilder('\OC\Subadmin') + ->disableOriginalConstructor()->getMock(); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->willReturn($subAdminManager); + $subAdminManager + ->expects($this->once()) + ->method('isSubAdmin') + ->with($loggedInUser) + ->willReturn(true); + $subAdminManager + ->expects($this->exactly(2)) + ->method('isSubAdminOfGroup') + ->withConsecutive( + [$loggedInUser, $existingGroup1], + [$loggedInUser, $existingGroup2] + ) + ->wilLReturn(true); + + + $expected = new \OC_OCS_Result(null, 100); + $this->assertEquals($expected, $this->api->addUser()); + } + + public function testGetUserNotLoggedIn() { $this->userSession ->expects($this->once()) diff --git a/core/css/apps.css b/core/css/apps.css index ac2be40ac5b..e9abbe0aee1 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -563,16 +563,19 @@ button.loading { #app-content > .section:first-child { border-top: none; } -.section h2 { + +/* heading styles */ +h2 { font-size: 20px; - margin-bottom: 12px; font-weight: 300; + margin-bottom: 12px; } -.section h3 { +h3 { font-size: 15px; font-weight: 300; margin: 12px 0; } + /* slight position correction of checkboxes and radio buttons */ .section input[type="checkbox"], .section input[type="radio"] { diff --git a/core/css/inputs.css b/core/css/inputs.css new file mode 100644 index 00000000000..9f440a6c359 --- /dev/null +++ b/core/css/inputs.css @@ -0,0 +1,232 @@ +/* INPUTS */ + +/* specifically override browser styles */ +input, textarea, select, button { + font-family: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif; +} + +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"], +input[type="date"], +textarea, +select, +button, .button, +input[type="submit"], +input[type="button"], +#quota, +.pager li a { + width: 130px; + margin: 3px 3px 3px 0; + padding: 7px 6px 5px; + font-size: 13px; + background-color: #fff; + color: #333; + border: 1px solid #ddd; + outline: none; + border-radius: 3px; +} +input[type="hidden"] { + height: 0; + width: 0; +} +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"], +textarea { + background: #fff; + color: #555; + cursor: text; + font-family: inherit; /* use default ownCloud font instead of default textarea monospace */ +} +input[type="text"], +input[type="password"], +input[type="search"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="time"] { + -webkit-appearance:textfield; -moz-appearance:textfield; + -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; +} +input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active, +input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active, +input[type="number"]:hover, input[type="number"]:focus, input[type="number"]:active, +input[type="search"]:hover, input[type="search"]:focus, input[type="search"]:active, +input[type="email"]:hover, input[type="email"]:focus, input[type="email"]:active, +input[type="url"]:hover, input[type="url"]:focus, input[type="url"]:active, +input[type="time"]:hover, input[type="time"]:focus, input[type="time"]:active, +textarea:hover, textarea:focus, textarea:active { + color: #333; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + opacity: 1; +} + +.ie8 input[type="checkbox"] { margin:0; padding:0; height:auto; width:auto; } +.ie8 input[type="checkbox"]:hover+label, input[type="checkbox"]:focus+label { color:#111 !important; } + +/* ie8 doesn't support :checked */ +html:not(.ie8) input[type="checkbox"].checkbox { + position: absolute; + left:-10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; +} + +html:not(.ie8) input[type="checkbox"].checkbox + label:before { + content: ""; + display: inline-block; + + height: 20px; + width: 20px; + vertical-align: middle; + + background: url('../img/actions/checkbox.svg') left top no-repeat; + opacity: 0.7; +} + +html:not(.ie8) input[type="checkbox"].checkbox:disabled +label:before { opacity: .6; } + +html:not(.ie8) input[type="checkbox"].checkbox.u-left +label:before { float: left; } +html:not(.ie8) input[type="checkbox"].checkbox.u-hidden + label:before { display: none; } + +html:not(.ie8) input[type="checkbox"].checkbox--white + label:before { + background-image: url('../img/actions/checkbox-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before { + background-image: url('../img/actions/checkbox-checked.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before { + background-image: url('../img/actions/checkbox-checked-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { + color:#111 !important; +} + +input[type="time"] { + width: initial; + height: 31px; + -moz-box-sizing: border-box; box-sizing: border-box; +} + +select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: url('../../core/img/actions/triangle-s.svg') no-repeat right 8px center rgba(240, 240, 240, 0.90); + outline: 0; + padding-right: 24px !important; +} + +select:hover { + background-color: #fefefe; +} + +.select2-choices { + border: 1px solid #ddd; + border-radius: 3px; + color: #333; + background-image: none; +} +.select2-dropdown-open .select2-choices { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border: 1px solid #3875d7; +} + +/* correctly align images inside of buttons */ +input img, button img, .button img { + vertical-align: text-bottom; +} + +input[type="submit"].enabled { + background-color: #66f866; + border: 1px solid #5e5; +} + +.input-button-inline { + position: absolute !important; + right: 0; + background-color: transparent !important; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; + opacity: .3; +} + + +/* BUTTONS */ +input[type="submit"], input[type="button"], +button, .button, +#quota, select, .pager li a { + width: auto; + min-width: 25px; + padding: 5px; + background-color: rgba(240,240,240,.9); + font-weight: 600; + color: #555; + border: 1px solid rgba(240,240,240,.9); + cursor: pointer; +} +select, .button.multiselect { + font-weight: 400; +} +input[type="submit"]:hover, input[type="submit"]:focus, +input[type="button"]:hover, input[type="button"]:focus, +button:hover, button:focus, +.button:hover, .button:focus, +.button a:focus, +select:hover, select:focus, select:active { + background-color: rgba(255, 255, 255, .95); + color: #111; +} +input[type="submit"] img, input[type="button"] img, button img, .button img { cursor:pointer; } +#header .button { + border: none; + box-shadow: none; +} + +/* disabled input fields and buttons */ +input:disabled, input:disabled:hover, input:disabled:focus, +button:disabled, button:disabled:hover, button:disabled:focus, +.button:disabled, .button:disabled:hover, .button:disabled:focus, +a.disabled, a.disabled:hover, a.disabled:focus, +textarea:disabled { + background-color: rgba(230,230,230,.9); + color: #999; + cursor: default; +} +input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { + color: #999 !important; + cursor: default; +} + +/* Primary action button, use sparingly */ +.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary { + border: 1px solid #1d2d44; + background-color: #35537a; + color: #ddd; +} +.primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover, +.primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus { + background-color: #304d76; + color: #fff; +} +.primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active, +.primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled, +.primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover, +.primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus { + background-color: #1d2d44; + color: #bbb; +} diff --git a/core/css/styles.css b/core/css/styles.css index 066087cc433..75bbb78fe52 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -12,18 +12,6 @@ table, td, th { vertical-align:middle; } a { border:0; color:#000; text-decoration:none;} a, a *, input, input *, select, .button span, label { cursor:pointer; } ul { list-style:none; } -select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background: url('../../core/img/actions/triangle-s.svg') no-repeat right 8px center rgba(240, 240, 240, 0.90); - outline: 0; - padding-right: 24px !important; -} - -select:hover { - background-color: #fefefe; -} body { background-color: #ffffff; @@ -85,155 +73,6 @@ body { color: #ddd; } - - -/* INPUTS */ - -/* specifically override browser styles */ -input, textarea, select, button { - font-family: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif; -} - -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"], -input[type="date"], -textarea, -select, -button, .button, -input[type="submit"], -input[type="button"], -#quota, -.pager li a { - width: 130px; - margin: 3px 3px 3px 0; - padding: 7px 6px 5px; - font-size: 13px; - background-color: #fff; - color: #333; - border: 1px solid #ddd; - outline: none; - border-radius: 3px; -} -input[type="hidden"] { - height: 0; - width: 0; -} -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"], -textarea { - background: #fff; - color: #555; - cursor: text; - font-family: inherit; /* use default ownCloud font instead of default textarea monospace */ -} -input[type="text"], -input[type="password"], -input[type="search"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="time"] { - -webkit-appearance:textfield; -moz-appearance:textfield; - -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; -} -input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active, -input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active, -input[type="number"]:hover, input[type="number"]:focus, input[type="number"]:active, -.searchbox input[type="search"]:hover, .searchbox input[type="search"]:focus, .searchbox input[type="search"]:active, -input[type="email"]:hover, input[type="email"]:focus, input[type="email"]:active, -input[type="url"]:hover, input[type="url"]:focus, input[type="url"]:active, -input[type="time"]:hover, input[type="time"]:focus, input[type="time"]:active, -textarea:hover, textarea:focus, textarea:active { - color: #333; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; - opacity: 1; -} - -.ie8 input[type="checkbox"] { margin:0; padding:0; height:auto; width:auto; } -.ie8 input[type="checkbox"]:hover+label, input[type="checkbox"]:focus+label { color:#111 !important; } - -/* ie8 doesn't support :checked */ -html:not(.ie8) input[type="checkbox"].checkbox { - position: absolute; - left:-10000px; - top: auto; - width: 1px; - height: 1px; - overflow: hidden; -} - -html:not(.ie8) input[type="checkbox"].checkbox + label:before { - content: ""; - display: inline-block; - - height: 20px; - width: 20px; - vertical-align: middle; - - background: url('../img/actions/checkbox.svg') left top no-repeat; - opacity: 0.7; -} - -html:not(.ie8) input[type="checkbox"].checkbox:disabled +label:before { opacity: .6; } - -html:not(.ie8) input[type="checkbox"].checkbox.u-left +label:before { float: left; } -html:not(.ie8) input[type="checkbox"].checkbox.u-hidden + label:before { display: none; } - -html:not(.ie8) input[type="checkbox"].checkbox--white + label:before { - background-image: url('../img/actions/checkbox-white.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before { - background-image: url('../img/actions/checkbox-checked.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before { - background-image: url('../img/actions/checkbox-checked-white.svg'); -} - -html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { - color:#111 !important; -} - -input[type="time"] { - width: initial; - height: 31px; - -moz-box-sizing: border-box; box-sizing: border-box; -} - -.select2-choices { - border: 1px solid #ddd; - border-radius: 3px; - color: #333; - background-image: none; -} -.select2-dropdown-open .select2-choices { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border: 1px solid #3875d7; -} - -/* correctly align images inside of buttons */ -input img, button img, .button img { - vertical-align: text-bottom; -} - -#quota { - cursor: default; - margin: 30px; -} - - /* SCROLLING */ ::-webkit-scrollbar { width: 8px; @@ -245,72 +84,6 @@ input img, button img, .button img { background: #ddd; } - -/* BUTTONS */ -input[type="submit"], input[type="button"], -button, .button, -#quota, select, .pager li a { - width: auto; - min-width: 25px; - padding: 5px; - background-color: rgba(240,240,240,.9); - font-weight: 600; - color: #555; - border: 1px solid rgba(240,240,240,.9); - cursor: pointer; -} -select, .button.multiselect { - font-weight: 400; -} -input[type="submit"]:hover, input[type="submit"]:focus, -input[type="button"]:hover, input[type="button"]:focus, -button:hover, button:focus, -.button:hover, .button:focus, -.button a:focus, -select:hover, select:focus, select:active { - background-color: rgba(255, 255, 255, .95); - color: #111; -} -input[type="submit"] img, input[type="button"] img, button img, .button img { cursor:pointer; } -#header .button { - border: none; - box-shadow: none; -} - -/* disabled input fields and buttons */ -input:disabled, input:disabled:hover, input:disabled:focus, -button:disabled, button:disabled:hover, button:disabled:focus, -.button:disabled, .button:disabled:hover, .button:disabled:focus, -a.disabled, a.disabled:hover, a.disabled:focus, -textarea:disabled { - background-color: rgba(230,230,230,.9); - color: #999; - cursor: default; -} -input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { - color: #999 !important; - cursor: default; -} - -/* Primary action button, use sparingly */ -.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary { - border: 1px solid #1d2d44; - background-color: #35537a; - color: #ddd; -} - .primary:hover, input[type="submit"].primary:hover, input[type="button"].primary:hover, button.primary:hover, .button.primary:hover, - .primary:focus, input[type="submit"].primary:focus, input[type="button"].primary:focus, button.primary:focus, .button.primary:focus { - background-color: #304d76; - color: #fff; - } - .primary:active, input[type="submit"].primary:active, input[type="button"].primary:active, button.primary:active, .button.primary:active, - .primary:disabled, input[type="submit"].primary:disabled, input[type="button"].primary:disabled, button.primary:disabled, .button.primary:disabled, - .primary:disabled:hover, input[type="submit"].primary:disabled:hover, input[type="button"].primary:disabled:hover, button.primary:disabled:hover, .button.primary:disabled:hover, - .primary:disabled:focus, input[type="submit"].primary:disabled:focus, input[type="button"].primary:disabled:focus, button.primary:disabled:focus, .button.primary:disabled:focus { - background-color: #1d2d44; - color: #bbb; - } - /* Searchbox */ .searchbox input[type="search"] { position: relative; @@ -342,21 +115,6 @@ input:disabled+label, input:disabled:hover+label, input:disabled:focus+label { background-color: #112; } -input[type="submit"].enabled { - background-color: #66f866; - border: 1px solid #5e5; -} - -.input-button-inline { - position: absolute !important; - right: 0; - background-color: transparent !important; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; - opacity: .3; -} - - - /* CONTENT ------------------------------------------------------------------ */ #controls { -moz-box-sizing: border-box; @@ -437,7 +195,6 @@ input[type="submit"].enabled { #emptycontent h2, .emptycontent h2 { font-weight: 600; - font-size: 22px; margin-bottom: 10px; } #emptycontent [class^="icon-"], @@ -483,7 +240,6 @@ input[type="submit"].enabled { } #body-login .update h2 { - font-size: 20px; line-height: 130%; margin-bottom: 30px; } @@ -941,6 +697,8 @@ tbody tr:active { code { font-family:"Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", monospace; } #quota { + cursor: default; + margin: 30px; position: relative; padding: 0; } diff --git a/core/js/js.js b/core/js/js.js index 07320a1d225..57c9871233b 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -119,10 +119,12 @@ var OC={ /** * Gets the base path for the given OCS API service. * @param {string} service name + * @param {int} version OCS API version * @return {string} OCS API base path */ - linkToOCS: function(service) { - return window.location.protocol + '//' + window.location.host + OC.webroot + '/ocs/v1.php/' + service + '/'; + linkToOCS: function(service, version) { + version = (version !== 2) ? 1 : 2; + return window.location.protocol + '//' + window.location.host + OC.webroot + '/ocs/v' + version + '.php/' + service + '/'; }, /** diff --git a/core/shipped.json b/core/shipped.json index 49a649f3c9e..cd1fca4d9fe 100644 --- a/core/shipped.json +++ b/core/shipped.json @@ -31,7 +31,8 @@ "user_external", "user_ldap", "user_shibboleth", - "windows_network_drive" + "windows_network_drive", + "password_policy" ], "alwaysEnabled": [ "files", diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 79bc809b9b2..7f21d3aadf5 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -235,17 +235,16 @@ class DefaultShareProvider implements IShareProvider { $share->setId((int)$data['id']) ->setShareType((int)$data['share_type']) ->setPermissions((int)$data['permissions']) - ->setTarget($data['file_target']); + ->setTarget($data['file_target']) + ->setShareTime((int)$data['stime']) + ->setMailSend((bool)$data['mail_send']); if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { $share->setSharedWith($this->userManager->get($data['share_with'])); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { $share->setSharedWith($this->groupManager->get($data['share_with'])); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { - /* - * TODO: Clean this up, this should be set as password not sharedWith - */ - $share->setSharedWith($data['share_with']); + $share->setPassword($data['share_with']); $share->setToken($data['token']); } else { $share->setSharedWith($data['share_with']); diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php index fa7c1ea614c..a80abebd71c 100644 --- a/lib/private/share20/ishare.php +++ b/lib/private/share20/ishare.php @@ -134,6 +134,13 @@ interface IShare { public function setPassword($password); /** + * Is a password set for this share + * + * @return string + */ + public function getPassword(); + + /** * Get the token * * @return string @@ -153,4 +160,18 @@ interface IShare { * @return string */ public function getTarget(); + + /** + * Get the timestamp this share was created + * + * @return int + */ + public function getSharetime(); + + /** + * Get mailSend + * + * @return bool + */ + public function getMailSend(); } diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php index 989edd3c079..4200816799e 100644 --- a/lib/private/share20/share.php +++ b/lib/private/share20/share.php @@ -28,39 +28,32 @@ class Share implements IShare { /** @var string */ private $id; - /** @var Node */ private $path; - /** @var int */ private $shareType; - /** @var IUser|IGroup|string */ private $sharedWith; - /** @var IUser|string */ private $sharedBy; - /** @var IUser|string */ private $shareOwner; - /** @var int */ private $permissions; - /** @var \DateTime */ private $expireDate; - /** @var string */ private $password; - /** @var string */ private $token; - /** @var int */ private $parent; - /** @var string */ private $target; + /** @var int */ + private $shareTime; + /** @var bool */ + private $mailSend; /** * Set the id of the share @@ -252,7 +245,7 @@ class Share implements IShare { * * @return string */ - public function getPassword($password) { + public function getPassword() { return $this->password; } @@ -315,4 +308,44 @@ class Share implements IShare { public function getTarget() { return $this->target; } + + /** + * Set the time this share was created + * + * @param int $shareTime + * @return Share The modified object + */ + public function setShareTime($shareTime) { + $this->shareTime = $shareTime; + return $this; + } + + /** + * Get the timestamp this share was created + * + * @return int + */ + public function getSharetime() { + return $this->shareTime; + } + + /** + * Set mailSend + * + * @param bool $mailSend + * @return Share The modified object + */ + public function setMailSend($mailSend) { + $this->mailSend = $mailSend; + return $this; + } + + /** + * Get mailSend + * + * @return bool + */ + public function getMailSend() { + return $this->mailSend; + } } diff --git a/lib/private/template.php b/lib/private/template.php index 722194dc764..97666f0b8dc 100644 --- a/lib/private/template.php +++ b/lib/private/template.php @@ -114,6 +114,7 @@ class OC_Template extends \OC\Template\Base { OC_Util::addStyle("icons",null,true); OC_Util::addStyle("mobile",null,true); OC_Util::addStyle("header",null,true); + OC_Util::addStyle("inputs",null,true); OC_Util::addStyle("styles",null,true); // avatars diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php index e99290f6724..f8b6f98be7c 100644 --- a/tests/lib/share20/defaultshareprovidertest.php +++ b/tests/lib/share20/defaultshareprovidertest.php @@ -266,7 +266,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($id, $share->getId()); $this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType()); - $this->assertEquals('sharedWith', $share->getSharedWith()); + $this->assertEquals('sharedWith', $share->getPassword()); $this->assertEquals($sharedBy, $share->getSharedBy()); $this->assertEquals($shareOwner, $share->getShareOwner()); $this->assertEquals($path, $share->getPath()); |