aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/templates/appnavigation.php4
-rw-r--r--apps/files_external/lib/sftp.php38
-rw-r--r--apps/files_external/tests/backends/sftp.php38
-rw-r--r--apps/files_sharing/api/ocssharewrapper.php14
-rw-r--r--apps/files_sharing/api/share20ocs.php100
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php259
-rw-r--r--apps/provisioning_api/appinfo/routes.php2
-rw-r--r--apps/provisioning_api/lib/users.php45
-rw-r--r--apps/provisioning_api/tests/userstest.php381
-rw-r--r--core/css/apps.css9
-rw-r--r--core/css/inputs.css232
-rw-r--r--core/css/styles.css246
-rw-r--r--core/js/js.js6
-rw-r--r--core/shipped.json3
-rw-r--r--lib/private/share20/defaultshareprovider.php9
-rw-r--r--lib/private/share20/ishare.php21
-rw-r--r--lib/private/share20/share.php57
-rw-r--r--lib/private/template.php1
-rw-r--r--tests/lib/share20/defaultshareprovidertest.php2
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());