aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/.gitignore1
-rw-r--r--apps/dav/appinfo/database.xml186
-rw-r--r--apps/dav/appinfo/info.xml2
-rw-r--r--apps/dav/appinfo/register_command.php8
-rw-r--r--apps/dav/command/createaddressbook.php52
-rw-r--r--apps/dav/lib/carddav/carddavbackend.php558
-rw-r--r--apps/dav/lib/rootcollection.php6
-rw-r--r--apps/dav/lib/server.php2
-rw-r--r--apps/dav/tests/unit/bootstrap.php13
-rw-r--r--apps/dav/tests/unit/carddav/carddavbackendtest.php180
-rw-r--r--apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/auth.php3
-rw-r--r--apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php4
-rw-r--r--apps/dav/tests/unit/connector/sabre/directory.php9
-rw-r--r--apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/file.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/filesplugin.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/node.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/objecttree.php5
-rw-r--r--apps/dav/tests/unit/connector/sabre/principal.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/quotaplugin.php3
-rw-r--r--apps/dav/tests/unit/connector/sabre/tagsplugin.php4
-rw-r--r--apps/dav/tests/unit/phpunit.xml25
-rw-r--r--apps/files/l10n/el.js56
-rw-r--r--apps/files/l10n/el.json56
-rw-r--r--apps/files_external/ajax/oauth2.php1
-rw-r--r--apps/files_external/l10n/cs_CZ.js2
-rw-r--r--apps/files_external/l10n/cs_CZ.json2
-rw-r--r--apps/files_external/l10n/el.js1
-rw-r--r--apps/files_external/l10n/el.json1
-rw-r--r--apps/files_external/l10n/fr.js2
-rw-r--r--apps/files_external/l10n/fr.json2
-rw-r--r--apps/files_external/l10n/ja.js1
-rw-r--r--apps/files_external/l10n/ja.json1
-rw-r--r--apps/files_external/l10n/nl.js1
-rw-r--r--apps/files_external/l10n/nl.json1
-rw-r--r--apps/files_external/l10n/oc.js2
-rw-r--r--apps/files_external/l10n/oc.json2
-rw-r--r--apps/files_external/lib/config.php2
-rw-r--r--apps/files_sharing/api/ocssharewrapper.php69
-rw-r--r--apps/files_sharing/api/share20ocs.php81
-rw-r--r--apps/files_sharing/appinfo/routes.php13
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php113
-rw-r--r--apps/provisioning_api/lib/users.php7
-rw-r--r--apps/provisioning_api/tests/userstest.php12
-rw-r--r--apps/user_ldap/l10n/hu_HU.js2
-rw-r--r--apps/user_ldap/l10n/hu_HU.json2
-rw-r--r--apps/user_ldap/l10n/zh_TW.js3
-rw-r--r--apps/user_ldap/l10n/zh_TW.json3
-rw-r--r--apps/user_ldap/lib/connection.php51
-rw-r--r--apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php118
-rw-r--r--build/integration/features/bootstrap/FeatureContext.php183
-rw-r--r--build/integration/features/provisioning-v1.feature8
-rw-r--r--build/integration/features/sharing-v1.feature69
-rw-r--r--core/command/app/checkcode.php4
-rw-r--r--core/img/favicon-mask.svg2
-rw-r--r--core/img/favicon.icobin0 -> 5686 bytes
-rw-r--r--core/l10n/cs_CZ.js2
-rw-r--r--core/l10n/cs_CZ.json2
-rw-r--r--core/l10n/es.js2
-rw-r--r--core/l10n/es.json2
-rw-r--r--core/l10n/hu_HU.js12
-rw-r--r--core/l10n/hu_HU.json12
-rw-r--r--core/l10n/nl.js2
-rw-r--r--core/l10n/nl.json2
-rw-r--r--core/shipped.json1
-rw-r--r--core/templates/layout.base.php3
-rw-r--r--core/templates/layout.guest.php3
-rw-r--r--core/templates/layout.user.php3
-rw-r--r--core/templates/update.admin.php4
-rw-r--r--cron.php2
-rw-r--r--lib/autoloader.php32
-rw-r--r--lib/base.php6
-rw-r--r--lib/l10n/hu_HU.js5
-rw-r--r--lib/l10n/hu_HU.json5
-rw-r--r--lib/private/app/codechecker/infochecker.php15
-rw-r--r--lib/private/files/storage/wrapper/encryption.php14
-rw-r--r--lib/private/group/manager.php4
-rw-r--r--lib/private/share/share.php4
-rw-r--r--lib/private/share20/defaultshareprovider.php275
-rw-r--r--lib/private/share20/exception/backenderror.php25
-rw-r--r--lib/private/share20/exception/sharenotfound.php25
-rw-r--r--lib/private/share20/ishare.php156
-rw-r--r--lib/private/share20/ishareprovider.php98
-rw-r--r--lib/private/share20/manager.php212
-rw-r--r--lib/private/share20/share.php318
-rw-r--r--lib/private/subadmin.php22
-rw-r--r--settings/js/admin.js64
-rw-r--r--settings/l10n/cs_CZ.js2
-rw-r--r--settings/l10n/cs_CZ.json2
-rw-r--r--settings/l10n/fi_FI.js1
-rw-r--r--settings/l10n/fi_FI.json1
-rw-r--r--settings/l10n/ja.js2
-rw-r--r--settings/l10n/ja.json2
-rw-r--r--settings/l10n/oc.js22
-rw-r--r--settings/l10n/oc.json22
-rw-r--r--settings/personal.php8
-rw-r--r--tests/lib/autoloader.php52
-rw-r--r--tests/lib/files/storage/wrapper/encryption.php96
-rw-r--r--tests/lib/group/manager.php26
-rw-r--r--tests/lib/share20/defaultshareprovidertest.php654
-rw-r--r--tests/lib/share20/managertest.php198
-rw-r--r--tests/lib/subadmin.php31
-rw-r--r--themes/example/core/img/favicon.icobin0 -> 5686 bytes
108 files changed, 4214 insertions, 191 deletions
diff --git a/apps/dav/.gitignore b/apps/dav/.gitignore
new file mode 100644
index 00000000000..885b6b3e6de
--- /dev/null
+++ b/apps/dav/.gitignore
@@ -0,0 +1 @@
+tests/travis/CalDAVTester
diff --git a/apps/dav/appinfo/database.xml b/apps/dav/appinfo/database.xml
new file mode 100644
index 00000000000..f3fd5079949
--- /dev/null
+++ b/apps/dav/appinfo/database.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+
+ <!--
+CREATE TABLE addressbooks (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ principaluri VARBINARY(255),
+ displayname VARCHAR(255),
+ uri VARBINARY(200),
+ description TEXT,
+ synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1',
+ UNIQUE(principaluri(100), uri(100))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+ <table>
+
+ <name>*dbprefix*addressbooks</name>
+
+ <declaration>
+
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+
+ <field>
+ <name>principaluri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>displayname</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>description</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>synctoken</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <index>
+ <name>addressbook_index</name>
+ <unique>true</unique>
+ <field>
+ <name>principaluri</name>
+ </field>
+ <field>
+ <name>uri</name>
+ </field>
+ </index>
+ </declaration>
+ </table>
+
+ <!--
+
+CREATE TABLE cards (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ addressbookid INT(11) UNSIGNED NOT NULL,
+ carddata MEDIUMBLOB,
+ uri VARBINARY(200),
+ lastmodified INT(11) UNSIGNED,
+ etag VARBINARY(32),
+ size INT(11) UNSIGNED NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+ -->
+ <table>
+ <name>*dbprefix*cards</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>addressbookid</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>carddata</name>
+ <type>blob</type>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>lastmodified</name>
+ <type>integer</type>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>etag</name>
+ <type>text</type>
+ <length>32</length>
+ </field>
+ <field>
+ <name>size</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ </declaration>
+ </table>
+
+ <!--
+CREATE TABLE addressbookchanges (
+ id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ uri VARBINARY(200) NOT NULL,
+ synctoken INT(11) UNSIGNED NOT NULL,
+ addressbookid INT(11) UNSIGNED NOT NULL,
+ operation TINYINT(1) NOT NULL,
+ INDEX addressbookid_synctoken (addressbookid, synctoken)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ -->
+
+ <table>
+ <name>*dbprefix*addressbookchanges</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <unsigned>true</unsigned>
+ <length>11</length>
+ </field>
+ <field>
+ <name>uri</name>
+ <type>text</type>
+ </field>
+ <field>
+ <name>synctoken</name>
+ <type>integer</type>
+ <default>1</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ </field>
+ <field>
+ <name>addressbookid</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ </field>
+ <field>
+ <name>operation</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>1</length>
+ </field>
+
+ <index>
+ <name>addressbookid_synctoken</name>
+ <field>
+ <name>addressbookid</name>
+ </field>
+ <field>
+ <name>synctoken</name>
+ </field>
+ </index>
+
+ </declaration>
+ </table>
+
+</database>
diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml
index 8f378f5e18d..11025115691 100644
--- a/apps/dav/appinfo/info.xml
+++ b/apps/dav/appinfo/info.xml
@@ -5,7 +5,7 @@
<description>ownCloud WebDAV endpoint</description>
<licence>AGPL</licence>
<author>owncloud.org</author>
- <version>0.1.1</version>
+ <version>0.1.2</version>
<requiremin>9.0</requiremin>
<shipped>true</shipped>
<standalone/>
diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php
new file mode 100644
index 00000000000..c996dd44063
--- /dev/null
+++ b/apps/dav/appinfo/register_command.php
@@ -0,0 +1,8 @@
+<?php
+
+use OCA\DAV\Command\CreateAddressBook;
+
+$dbConnection = \OC::$server->getDatabaseConnection();
+$userManager = OC::$server->getUserManager();
+/** @var Symfony\Component\Console\Application $application */
+$application->add(new CreateAddressBook($userManager, $dbConnection));
diff --git a/apps/dav/command/createaddressbook.php b/apps/dav/command/createaddressbook.php
new file mode 100644
index 00000000000..286871b39e2
--- /dev/null
+++ b/apps/dav/command/createaddressbook.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class CreateAddressBook extends Command {
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var \OCP\IDBConnection */
+ protected $dbConnection;
+
+ /**
+ * @param IUserManager $userManager
+ * @param IDBConnection $dbConnection
+ */
+ function __construct(IUserManager $userManager, IDBConnection $dbConnection) {
+ parent::__construct();
+ $this->userManager = $userManager;
+ $this->dbConnection = $dbConnection;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('dav:create-addressbook')
+ ->setDescription('Create a dav addressbook')
+ ->addArgument('user',
+ InputArgument::REQUIRED,
+ 'User for whom the addressbook will be created')
+ ->addArgument('name',
+ InputArgument::REQUIRED,
+ 'Name of the addressbook');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $user = $input->getArgument('user');
+ if (!$this->userManager->userExists($user)) {
+ throw new \InvalidArgumentException("User <$user> in unknown.");
+ }
+ $name = $input->getArgument('name');
+ $carddav = new CardDavBackend($this->dbConnection);
+ $carddav->createAddressBook("principals/$user", $name, []);
+ }
+}
diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php
new file mode 100644
index 00000000000..7b16262a680
--- /dev/null
+++ b/apps/dav/lib/carddav/carddavbackend.php
@@ -0,0 +1,558 @@
+<?php
+
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\CardDAV;
+
+use Sabre\CardDAV\Backend\BackendInterface;
+use Sabre\CardDAV\Backend\SyncSupport;
+use Sabre\CardDAV\Plugin;
+use Sabre\DAV\Exception\BadRequest;
+
+class CardDavBackend implements BackendInterface, SyncSupport {
+
+ public function __construct(\OCP\IDBConnection $db) {
+ $this->db = $db;
+ }
+
+ /**
+ * Returns the list of addressbooks for a specific user.
+ *
+ * Every addressbook should have the following properties:
+ * id - an arbitrary unique id
+ * uri - the 'basename' part of the url
+ * principaluri - Same as the passed parameter
+ *
+ * Any additional clark-notation property may be passed besides this. Some
+ * common ones are :
+ * {DAV:}displayname
+ * {urn:ietf:params:xml:ns:carddav}addressbook-description
+ * {http://calendarserver.org/ns/}getctag
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ function getAddressBooksForUser($principalUri) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
+ ->from('addressbooks')
+ ->where($query->expr()->eq('principaluri', $query->createParameter('principaluri')))
+ ->setParameter('principaluri', $principalUri);
+
+ $addressBooks = [];
+
+ $result = $query->execute();
+ while($row = $result->fetch()) {
+ $addressBooks[] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{DAV:}displayname' => $row['displayname'],
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
+ ];
+ }
+ $result->closeCursor();
+
+ return $addressBooks;
+ }
+
+ /**
+ * Updates properties for an address book.
+ *
+ * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+ * To do the actual updates, you must tell this object which properties
+ * you're going to process with the handle() method.
+ *
+ * Calling the handle method is like telling the PropPatch object "I
+ * promise I can handle updating this property".
+ *
+ * Read the PropPatch documenation for more info and examples.
+ *
+ * @param string $addressBookId
+ * @param \Sabre\DAV\PropPatch $propPatch
+ * @return void
+ */
+ function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
+ $supportedProperties = [
+ '{DAV:}displayname',
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description',
+ ];
+
+ $propPatch->handle($supportedProperties, function($mutations) use ($addressBookId) {
+
+ $updates = [];
+ foreach($mutations as $property=>$newValue) {
+
+ switch($property) {
+ case '{DAV:}displayname' :
+ $updates['displayname'] = $newValue;
+ break;
+ case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
+ $updates['description'] = $newValue;
+ break;
+ }
+ }
+ $query = $this->db->getQueryBuilder();
+ $query->update('addressbooks');
+
+ foreach($updates as $key=>$value) {
+ $query->set($key, $query->createNamedParameter($value));
+ }
+ $query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
+ ->execute();
+
+ $this->addChange($addressBookId, "", 2);
+
+ return true;
+
+ });
+ }
+
+ /**
+ * Creates a new address book
+ *
+ * @param string $principalUri
+ * @param string $url Just the 'basename' of the url.
+ * @param array $properties
+ * @return void
+ */
+ function createAddressBook($principalUri, $url, array $properties) {
+ $values = [
+ 'displayname' => null,
+ 'description' => null,
+ 'principaluri' => $principalUri,
+ 'uri' => $url,
+ 'synctoken' => 1
+ ];
+
+ foreach($properties as $property=>$newValue) {
+
+ switch($property) {
+ case '{DAV:}displayname' :
+ $values['displayname'] = $newValue;
+ break;
+ case '{' . Plugin::NS_CARDDAV . '}addressbook-description' :
+ $values['description'] = $newValue;
+ break;
+ default :
+ throw new BadRequest('Unknown property: ' . $property);
+ }
+
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('addressbooks')
+ ->values([
+ 'uri' => $query->createParameter('uri'),
+ 'displayname' => $query->createParameter('displayname'),
+ 'description' => $query->createParameter('description'),
+ 'principaluri' => $query->createParameter('principaluri'),
+ 'synctoken' => $query->createParameter('synctoken'),
+ ])
+ ->setParameters($values)
+ ->execute();
+ }
+
+ /**
+ * Deletes an entire addressbook and all its contents
+ *
+ * @param mixed $addressBookId
+ * @return void
+ */
+ function deleteAddressBook($addressBookId) {
+ $query = $this->db->getQueryBuilder();
+ $query->delete('cards')
+ ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
+ ->setParameter('addressbookid', $addressBookId)
+ ->execute();
+
+ $query->delete('addressbookchanges')
+ ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
+ ->setParameter('addressbookid', $addressBookId)
+ ->execute();
+
+ $query->delete('addressbooks')
+ ->where($query->expr()->eq('id', $query->createParameter('id')))
+ ->setParameter('id', $addressBookId)
+ ->execute();
+ }
+
+ /**
+ * Returns all cards for a specific addressbook id.
+ *
+ * This method should return the following properties for each card:
+ * * carddata - raw vcard data
+ * * uri - Some unique url
+ * * lastmodified - A unix timestamp
+ *
+ * It's recommended to also return the following properties:
+ * * etag - A unique etag. This must change every time the card changes.
+ * * size - The size of the card in bytes.
+ *
+ * If these last two properties are provided, less time will be spent
+ * calculating them. If they are specified, you can also ommit carddata.
+ * This may speed up certain requests, especially with large cards.
+ *
+ * @param mixed $addressBookId
+ * @return array
+ */
+ function getCards($addressBookId) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata'])
+ ->from('cards')
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
+
+ $cards = [];
+
+ $result = $query->execute();
+ while($row = $result->fetch()) {
+ $row['etag'] = '"' . $row['etag'] . '"';
+ $row['carddata'] = $this->readBlob($row['carddata']);
+ $cards[] = $row;
+ }
+ $result->closeCursor();
+
+ return $cards;
+ }
+
+ /**
+ * Returns a specfic card.
+ *
+ * The same set of properties must be returned as with getCards. The only
+ * exception is that 'carddata' is absolutely required.
+ *
+ * If the card does not exist, you must return false.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @return array
+ */
+ function getCard($addressBookId, $cardUri) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata'])
+ ->from('cards')
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
+ ->setMaxResults(1);
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ if (!$row) {
+ return false;
+ }
+ $row['etag'] = '"' . $row['etag'] . '"';
+ $row['carddata'] = $this->readBlob($row['carddata']);
+
+ return $row;
+ }
+
+ /**
+ * Returns a list of cards.
+ *
+ * This method should work identical to getCard, but instead return all the
+ * cards in the list as an array.
+ *
+ * If the backend supports this, it may allow for some speed-ups.
+ *
+ * @param mixed $addressBookId
+ * @param array $uris
+ * @return array
+ */
+ function getMultipleCards($addressBookId, array $uris) {
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata'])
+ ->from('cards')
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->in('uri', $query->createParameter('uri')))
+ ->setParameter('uri', $uris, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
+
+ $cards = [];
+
+ $result = $query->execute();
+ while($row = $result->fetch()) {
+ $row['etag'] = '"' . $row['etag'] . '"';
+ $row['carddata'] = $this->readBlob($row['carddata']);
+ $cards[] = $row;
+ }
+ $result->closeCursor();
+
+ return $cards;
+ }
+
+ /**
+ * Creates a new card.
+ *
+ * The addressbook id will be passed as the first argument. This is the
+ * same id as it is returned from the getAddressBooksForUser method.
+ *
+ * The cardUri is a base uri, and doesn't include the full path. The
+ * cardData argument is the vcard body, and is passed as a string.
+ *
+ * It is possible to return an ETag from this method. This ETag is for the
+ * newly created resource, and must be enclosed with double quotes (that
+ * is, the string itself must contain the double quotes).
+ *
+ * You should only return the ETag if you store the carddata as-is. If a
+ * subsequent GET request on the same card does not have the same body,
+ * byte-by-byte and you did return an ETag here, clients tend to get
+ * confused.
+ *
+ * If you don't return an ETag, you can just return null.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @param string $cardData
+ * @return string|null
+ */
+ function createCard($addressBookId, $cardUri, $cardData) {
+ $etag = md5($cardData);
+
+ $query = $this->db->getQueryBuilder();
+ $query->insert('cards')
+ ->values([
+ 'carddata' => $query->createNamedParameter($cardData),
+ 'uri' => $query->createNamedParameter($cardUri),
+ 'lastmodified' => $query->createNamedParameter(time()),
+ 'addressbookid' => $query->createNamedParameter($addressBookId),
+ 'size' => $query->createNamedParameter(strlen($cardData)),
+ 'etag' => $query->createNamedParameter($etag),
+ ])
+ ->execute();
+
+ $this->addChange($addressBookId, $cardUri, 1);
+
+ return '"' . $etag . '"';
+ }
+
+ /**
+ * Updates a card.
+ *
+ * The addressbook id will be passed as the first argument. This is the
+ * same id as it is returned from the getAddressBooksForUser method.
+ *
+ * The cardUri is a base uri, and doesn't include the full path. The
+ * cardData argument is the vcard body, and is passed as a string.
+ *
+ * It is possible to return an ETag from this method. This ETag should
+ * match that of the updated resource, and must be enclosed with double
+ * quotes (that is: the string itself must contain the actual quotes).
+ *
+ * You should only return the ETag if you store the carddata as-is. If a
+ * subsequent GET request on the same card does not have the same body,
+ * byte-by-byte and you did return an ETag here, clients tend to get
+ * confused.
+ *
+ * If you don't return an ETag, you can just return null.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @param string $cardData
+ * @return string|null
+ */
+ function updateCard($addressBookId, $cardUri, $cardData) {
+
+ $etag = md5($cardData);
+ $query = $this->db->getQueryBuilder();
+ $query->update('cards')
+ ->set('carddata', $query->createNamedParameter($cardData, \PDO::PARAM_LOB))
+ ->set('lastmodified', $query->createNamedParameter(time()))
+ ->set('size', $query->createNamedParameter(strlen($cardData)))
+ ->set('etag', $query->createNamedParameter($etag))
+ ->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
+ ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->execute();
+
+ $this->addChange($addressBookId, $cardUri, 2);
+
+ return '"' . $etag . '"';
+ }
+
+ /**
+ * Deletes a card
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @return bool
+ */
+ function deleteCard($addressBookId, $cardUri) {
+ $query = $this->db->getQueryBuilder();
+ $ret = $query->delete('cards')
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
+ ->execute();
+
+ $this->addChange($addressBookId, $cardUri, 3);
+
+ return $ret === 1;
+ }
+
+ /**
+ * The getChanges method returns all the changes that have happened, since
+ * the specified syncToken in the specified address book.
+ *
+ * This function should return an array, such as the following:
+ *
+ * [
+ * 'syncToken' => 'The current synctoken',
+ * 'added' => [
+ * 'new.txt',
+ * ],
+ * 'modified' => [
+ * 'modified.txt',
+ * ],
+ * 'deleted' => [
+ * 'foo.php.bak',
+ * 'old.txt'
+ * ]
+ * ];
+ *
+ * The returned syncToken property should reflect the *current* syncToken
+ * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
+ * property. This is needed here too, to ensure the operation is atomic.
+ *
+ * If the $syncToken argument is specified as null, this is an initial
+ * sync, and all members should be reported.
+ *
+ * The modified property is an array of nodenames that have changed since
+ * the last token.
+ *
+ * The deleted property is an array with nodenames, that have been deleted
+ * from collection.
+ *
+ * The $syncLevel argument is basically the 'depth' of the report. If it's
+ * 1, you only have to report changes that happened only directly in
+ * immediate descendants. If it's 2, it should also include changes from
+ * the nodes below the child collections. (grandchildren)
+ *
+ * The $limit argument allows a client to specify how many results should
+ * be returned at most. If the limit is not specified, it should be treated
+ * as infinite.
+ *
+ * If the limit (infinite or not) is higher than you're willing to return,
+ * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
+ *
+ * If the syncToken is expired (due to data cleanup) or unknown, you must
+ * return null.
+ *
+ * The limit is 'suggestive'. You are free to ignore it.
+ *
+ * @param string $addressBookId
+ * @param string $syncToken
+ * @param int $syncLevel
+ * @param int $limit
+ * @return array
+ */
+ function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) {
+ // Current synctoken
+ $stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*addressbooks` WHERE `id` = ?');
+ $stmt->execute([ $addressBookId ]);
+ $currentToken = $stmt->fetchColumn(0);
+
+ if (is_null($currentToken)) return null;
+
+ $result = [
+ 'syncToken' => $currentToken,
+ 'added' => [],
+ 'modified' => [],
+ 'deleted' => [],
+ ];
+
+ if ($syncToken) {
+
+ $query = "SELECT `uri`, `operation` FROM `*PREFIX*addressbookchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `addressbookid` = ? ORDER BY `synctoken`";
+ if ($limit>0) {
+ $query .= " `LIMIT` " . (int)$limit;
+ }
+
+ // Fetching all changes
+ $stmt = $this->db->prepare($query);
+ $stmt->execute([$syncToken, $currentToken, $addressBookId]);
+
+ $changes = [];
+
+ // This loop ensures that any duplicates are overwritten, only the
+ // last change on a node is relevant.
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $changes[$row['uri']] = $row['operation'];
+
+ }
+
+ foreach($changes as $uri => $operation) {
+
+ switch($operation) {
+ case 1:
+ $result['added'][] = $uri;
+ break;
+ case 2:
+ $result['modified'][] = $uri;
+ break;
+ case 3:
+ $result['deleted'][] = $uri;
+ break;
+ }
+
+ }
+ } else {
+ // No synctoken supplied, this is the initial sync.
+ $query = "SELECT `uri` FROM `*PREFIX*cards` WHERE `addressbookid` = ?";
+ $stmt = $this->db->prepare($query);
+ $stmt->execute([$addressBookId]);
+
+ $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
+ }
+ return $result;
+ }
+
+ /**
+ * Adds a change record to the addressbookchanges table.
+ *
+ * @param mixed $addressBookId
+ * @param string $objectUri
+ * @param int $operation 1 = add, 2 = modify, 3 = delete
+ * @return void
+ */
+ protected function addChange($addressBookId, $objectUri, $operation) {
+ $sql = 'INSERT INTO `*PREFIX*addressbookchanges`(`uri`, `synctoken`, `addressbookid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*addressbooks` WHERE `id` = ?';
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute([
+ $objectUri,
+ $addressBookId,
+ $operation,
+ $addressBookId
+ ]);
+ $stmt = $this->db->prepare('UPDATE `*PREFIX*addressbooks` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
+ $stmt->execute([
+ $addressBookId
+ ]);
+ }
+
+ private function readBlob($cardData) {
+ if (is_resource($cardData)) {
+ return stream_get_contents($cardData);
+ }
+
+ return $cardData;
+ }
+
+}
diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php
index 7de2c2aabe3..850180d8481 100644
--- a/apps/dav/lib/rootcollection.php
+++ b/apps/dav/lib/rootcollection.php
@@ -2,8 +2,10 @@
namespace OCA\DAV;
+use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Connector\Sabre\Principal;
use Sabre\CalDAV\Principal\Collection;
+use Sabre\CardDAV\AddressBookRoot;
use Sabre\DAV\SimpleCollection;
class RootCollection extends SimpleCollection {
@@ -22,10 +24,14 @@ class RootCollection extends SimpleCollection {
$principalCollection->disableListing = $disableListing;
$filesCollection = new Files\RootCollection($principalBackend);
$filesCollection->disableListing = $disableListing;
+ $cardDavBackend = new CardDavBackend(\OC::$server->getDatabaseConnection());
+ $addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend);
+ $addressBookRoot->disableListing = $disableListing;
$children = [
$principalCollection,
$filesCollection,
+ $addressBookRoot,
];
parent::__construct('root', $children);
diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php
index 055c5a5fc2c..22171b74d37 100644
--- a/apps/dav/lib/server.php
+++ b/apps/dav/lib/server.php
@@ -33,6 +33,8 @@ class Server {
$this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig()));
$this->server->addPlugin(new Plugin($authBackend, 'ownCloud'));
+ $this->server->addPlugin(new \Sabre\DAVACL\Plugin());
+
// wait with registering these until auth is handled and the filesystem is setup
$this->server->on('beforeMethod', function () {
// custom properties plugin must be the last one
diff --git a/apps/dav/tests/unit/bootstrap.php b/apps/dav/tests/unit/bootstrap.php
new file mode 100644
index 00000000000..28f6b971dec
--- /dev/null
+++ b/apps/dav/tests/unit/bootstrap.php
@@ -0,0 +1,13 @@
+<?php
+
+define('PHPUNIT_RUN', 1);
+
+require_once __DIR__.'/../../../../lib/base.php';
+
+if(!class_exists('PHPUnit_Framework_TestCase')) {
+ require_once('PHPUnit/Autoload.php');
+}
+
+\OC_App::loadApp('dav');
+
+OC_Hook::clear();
diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php
new file mode 100644
index 00000000000..f7456e9634c
--- /dev/null
+++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Tests\Unit\CardDAV;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use Sabre\DAV\PropPatch;
+use Test\TestCase;
+
+class CardDavBackendTest extends TestCase {
+
+ /** @var CardDavBackend */
+ private $backend;
+
+ const UNIT_TEST_USER = 'carddav-unit-test';
+
+
+ public function setUp() {
+ parent::setUp();
+
+ $db = \OC::$server->getDatabaseConnection();
+ $this->backend = new CardDavBackend($db);
+
+ $this->tearDown();
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+
+ if (is_null($this->backend)) {
+ return;
+ }
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ foreach ($books as $book) {
+ $this->backend->deleteAddressBook($book['id']);
+ }
+ }
+
+ public function testAddressBookOperations() {
+
+ // create a new address book
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+
+ // update it's display name
+ $patch = new PropPatch([
+ '{DAV:}displayname' => 'Unit test',
+ '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Addressbook used for unit testing'
+ ]);
+ $this->backend->updateAddressBook($books[0]['id'], $patch);
+ $patch->commit();
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
+ $this->assertEquals('Addressbook used for unit testing', $books[0]['{urn:ietf:params:xml:ns:carddav}addressbook-description']);
+
+ // delete the address book
+ $this->backend->deleteAddressBook($books[0]['id']);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(0, count($books));
+ }
+
+ public function testCardOperations() {
+ // create a new address book
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $bookId = $books[0]['id'];
+
+ // create a card
+ $uri = $this->getUniqueID('card');
+ $this->backend->createCard($bookId, $uri, '');
+
+ // get all the cards
+ $cards = $this->backend->getCards($bookId);
+ $this->assertEquals(1, count($cards));
+ $this->assertEquals('', $cards[0]['carddata']);
+
+ // get the cards
+ $card = $this->backend->getCard($bookId, $uri);
+ $this->assertNotNull($card);
+ $this->assertArrayHasKey('id', $card);
+ $this->assertArrayHasKey('uri', $card);
+ $this->assertArrayHasKey('lastmodified', $card);
+ $this->assertArrayHasKey('etag', $card);
+ $this->assertArrayHasKey('size', $card);
+ $this->assertEquals('', $card['carddata']);
+
+ // update the card
+ $this->backend->updateCard($bookId, $uri, '***');
+ $card = $this->backend->getCard($bookId, $uri);
+ $this->assertEquals('***', $card['carddata']);
+
+ // delete the card
+ $this->backend->deleteCard($bookId, $uri);
+ $cards = $this->backend->getCards($bookId);
+ $this->assertEquals(0, count($cards));
+ }
+
+ public function testMultiCard() {
+ // create a new address book
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $bookId = $books[0]['id'];
+
+ // create a card
+ $uri0 = $this->getUniqueID('card');
+ $this->backend->createCard($bookId, $uri0, '');
+ $uri1 = $this->getUniqueID('card');
+ $this->backend->createCard($bookId, $uri1, '');
+ $uri2 = $this->getUniqueID('card');
+ $this->backend->createCard($bookId, $uri2, '');
+
+ // get all the cards
+ $cards = $this->backend->getCards($bookId);
+ $this->assertEquals(3, count($cards));
+ $this->assertEquals('', $cards[0]['carddata']);
+ $this->assertEquals('', $cards[1]['carddata']);
+ $this->assertEquals('', $cards[2]['carddata']);
+
+ // get the cards
+ $cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
+ $this->assertEquals(2, count($cards));
+ foreach($cards as $card) {
+ $this->assertArrayHasKey('id', $card);
+ $this->assertArrayHasKey('uri', $card);
+ $this->assertArrayHasKey('lastmodified', $card);
+ $this->assertArrayHasKey('etag', $card);
+ $this->assertArrayHasKey('size', $card);
+ $this->assertEquals('', $card['carddata']);
+ }
+
+ // delete the card
+ $this->backend->deleteCard($bookId, $uri0);
+ $this->backend->deleteCard($bookId, $uri1);
+ $this->backend->deleteCard($bookId, $uri2);
+ $cards = $this->backend->getCards($bookId);
+ $this->assertEquals(0, count($cards));
+ }
+
+ public function testSyncSupport() {
+ // create a new address book
+ $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
+ $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
+ $this->assertEquals(1, count($books));
+ $bookId = $books[0]['id'];
+
+ // fist call without synctoken
+ $changes = $this->backend->getChangesForAddressBook($bookId, '', 1);
+ $syncToken = $changes['syncToken'];
+
+ // add a change
+ $uri0 = $this->getUniqueID('card');
+ $this->backend->createCard($bookId, $uri0, '');
+
+ // look for changes
+ $changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
+ $this->assertEquals($uri0, $changes['added'][0]);
+ }
+}
diff --git a/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php b/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
index 1e390cf15f7..3004c03b266 100644
--- a/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/BlockLegacyClientPluginTest.php
@@ -19,7 +19,7 @@
*
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
use Test\TestCase;
diff --git a/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php b/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
index 1fd89c84ff6..d2d4a849a51 100644
--- a/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/DummyGetResponsePluginTest.php
@@ -19,7 +19,7 @@
*
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\DummyGetResponsePlugin;
use Test\TestCase;
diff --git a/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php b/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
index c0acd4fc3de..34fa7f7eef9 100644
--- a/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
+++ b/apps/dav/tests/unit/connector/sabre/MaintenancePluginTest.php
@@ -19,7 +19,7 @@
*
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\MaintenancePlugin;
use Test\TestCase;
diff --git a/apps/dav/tests/unit/connector/sabre/auth.php b/apps/dav/tests/unit/connector/sabre/auth.php
index 0466f3aab77..d18747d732a 100644
--- a/apps/dav/tests/unit/connector/sabre/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/auth.php
@@ -18,7 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-namespace Tests\Connector\Sabre;
+
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use Test\TestCase;
use OCP\ISession;
diff --git a/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php b/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
index 2080755cd51..74dd4edd8cf 100644
--- a/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
+++ b/apps/dav/tests/unit/connector/sabre/copyetagheaderplugintest.php
@@ -1,6 +1,6 @@
<?php
-namespace Tests\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
diff --git a/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php b/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
index 973a5d4c27b..e1bcc996908 100644
--- a/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
+++ b/apps/dav/tests/unit/connector/sabre/custompropertiesbackend.php
@@ -1,6 +1,6 @@
<?php
-namespace Tests\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
@@ -16,7 +16,7 @@ class CustomPropertiesBackend extends \Test\TestCase {
private $server;
/**
- * @var \Sabre\DAV\ObjectTree
+ * @var \Sabre\DAV\Tree
*/
private $tree;
diff --git a/apps/dav/tests/unit/connector/sabre/directory.php b/apps/dav/tests/unit/connector/sabre/directory.php
index d85290df80a..148a91d26db 100644
--- a/apps/dav/tests/unit/connector/sabre/directory.php
+++ b/apps/dav/tests/unit/connector/sabre/directory.php
@@ -6,11 +6,14 @@
* later.
* See the COPYING-README file.
*/
-class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
- /** @var OC\Files\View | PHPUnit_Framework_MockObject_MockObject */
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+
+class Directory extends \Test\TestCase {
+
+ /** @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject */
private $view;
- /** @var OC\Files\FileInfo | PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OC\Files\FileInfo | \PHPUnit_Framework_MockObject_MockObject */
private $info;
protected function setUp() {
diff --git a/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php b/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
index 4c0af58ffea..19e82320d55 100644
--- a/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
+++ b/apps/dav/tests/unit/connector/sabre/exception/invalidpathtest.php
@@ -1,6 +1,6 @@
<?php
-namespace Test\Connector\Sabre\Exception;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre\Exception;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
diff --git a/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php b/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
index d85aa5a9cc3..0c364df012b 100644
--- a/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/exceptionloggerplugin.php
@@ -7,7 +7,7 @@
* See the COPYING-README file.
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin as PluginToTest;
diff --git a/apps/dav/tests/unit/connector/sabre/file.php b/apps/dav/tests/unit/connector/sabre/file.php
index d874b7f33c2..94dadf88fe4 100644
--- a/apps/dav/tests/unit/connector/sabre/file.php
+++ b/apps/dav/tests/unit/connector/sabre/file.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OC\Files\Storage\Local;
use Test\HookHelper;
diff --git a/apps/dav/tests/unit/connector/sabre/filesplugin.php b/apps/dav/tests/unit/connector/sabre/filesplugin.php
index db3bbabefd0..f3c862941c0 100644
--- a/apps/dav/tests/unit/connector/sabre/filesplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/filesplugin.php
@@ -1,6 +1,6 @@
<?php
-namespace Tests\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
diff --git a/apps/dav/tests/unit/connector/sabre/node.php b/apps/dav/tests/unit/connector/sabre/node.php
index a9610fd84b3..cee64fb7dff 100644
--- a/apps/dav/tests/unit/connector/sabre/node.php
+++ b/apps/dav/tests/unit/connector/sabre/node.php
@@ -7,7 +7,7 @@
* See the COPYING-README file.
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
class Node extends \Test\TestCase {
public function davPermissionsProvider() {
diff --git a/apps/dav/tests/unit/connector/sabre/objecttree.php b/apps/dav/tests/unit/connector/sabre/objecttree.php
index 2691385c1c1..3a56404e552 100644
--- a/apps/dav/tests/unit/connector/sabre/objecttree.php
+++ b/apps/dav/tests/unit/connector/sabre/objecttree.php
@@ -6,11 +6,10 @@
* See the COPYING-README file.
*/
-namespace Test\OCA\DAV\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use OC\Files\FileInfo;
-use OCA\DAV\Connector\Sabre\Directory;
use OC\Files\Storage\Temporary;
class TestDoubleFileView extends \OC\Files\View {
@@ -103,7 +102,7 @@ class ObjectTree extends \Test\TestCase {
$info = new FileInfo('', null, null, array(), null);
- $rootDir = new Directory($view, $info);
+ $rootDir = new \OCA\DAV\Connector\Sabre\Directory($view, $info);
$objectTree = $this->getMock('\OCA\DAV\Connector\Sabre\ObjectTree',
array('nodeExists', 'getNodeForPath'),
array($rootDir, $view));
diff --git a/apps/dav/tests/unit/connector/sabre/principal.php b/apps/dav/tests/unit/connector/sabre/principal.php
index 3c0abeac3f1..2fbab124fb7 100644
--- a/apps/dav/tests/unit/connector/sabre/principal.php
+++ b/apps/dav/tests/unit/connector/sabre/principal.php
@@ -8,7 +8,7 @@
* See the COPYING-README file.
*/
-namespace Test\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
use \Sabre\DAV\PropPatch;
use OCP\IUserManager;
diff --git a/apps/dav/tests/unit/connector/sabre/quotaplugin.php b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
index 5d3364e1f8c..470fd9cbf85 100644
--- a/apps/dav/tests/unit/connector/sabre/quotaplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/quotaplugin.php
@@ -1,12 +1,13 @@
<?php
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
-class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
+class QuotaPlugin extends \Test\TestCase {
/**
* @var \Sabre\DAV\Server
diff --git a/apps/dav/tests/unit/connector/sabre/tagsplugin.php b/apps/dav/tests/unit/connector/sabre/tagsplugin.php
index 4731e770cfa..f1f6cc40dab 100644
--- a/apps/dav/tests/unit/connector/sabre/tagsplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/tagsplugin.php
@@ -1,6 +1,6 @@
<?php
-namespace Tests\Connector\Sabre;
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
/**
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
@@ -20,7 +20,7 @@ class TagsPlugin extends \Test\TestCase {
private $server;
/**
- * @var \Sabre\DAV\ObjectTree
+ * @var \Sabre\DAV\Tree
*/
private $tree;
diff --git a/apps/dav/tests/unit/phpunit.xml b/apps/dav/tests/unit/phpunit.xml
new file mode 100644
index 00000000000..46c3cdfb345
--- /dev/null
+++ b/apps/dav/tests/unit/phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<phpunit bootstrap="bootstrap.php"
+ verbose="true"
+ timeoutForSmallTests="900"
+ timeoutForMediumTests="900"
+ timeoutForLargeTests="900"
+ >
+ <testsuite name='unit'>
+ <directory suffix='test.php'>.</directory>
+ </testsuite>
+ <!-- filters for code coverage -->
+ <filter>
+ <whitelist>
+ <directory suffix=".php">../../dav</directory>
+ <exclude>
+ <directory suffix=".php">../../dav/tests</directory>
+ </exclude>
+ </whitelist>
+ </filter>
+ <logging>
+ <!-- and this is where your report will be written -->
+ <log type="coverage-clover" target="./clover.xml"/>
+ </logging>
+</phpunit>
+
diff --git a/apps/files/l10n/el.js b/apps/files/l10n/el.js
index 063c9f0fe44..113f10266a4 100644
--- a/apps/files/l10n/el.js
+++ b/apps/files/l10n/el.js
@@ -10,7 +10,7 @@ OC.L10N.register(
"The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
"The name %s is already used in the folder %s. Please choose a different name." : "Το όνομα %s χρησιμοποιείτε ήδη στον φάκελο %s. Παρακαλώ επιλέξτε ένα άλλο όνομα.",
"Error when creating the file" : "Σφάλμα κατά τη δημιουργία του αρχείου",
- "Error when creating the folder" : "Σφάλμα δημιουργίας φακέλου",
+ "Error when creating the folder" : "Σφάλμα κατά τη δημιουργία του φακέλου",
"Unable to set upload directory." : "Αδυναμία ορισμού καταλόγου αποστολής.",
"Invalid Token" : "Μη έγκυρο Token",
"No file was uploaded. Unknown error" : "Δεν ανέβηκε κάποιο αρχείο. Άγνωστο σφάλμα",
@@ -21,19 +21,19 @@ OC.L10N.register(
"No file was uploaded" : "Κανένα αρχείο δεν στάλθηκε",
"Missing a temporary folder" : "Λείπει ο προσωρινός φάκελος",
"Failed to write to disk" : "Αποτυχία εγγραφής στο δίσκο",
- "Not enough storage available" : "Μη επαρκής διαθέσιμος αποθηκευτικός χώρος",
+ "Not enough storage available" : "Ο διαθέσιμος αποθηκευτικός χώρος δεν επαρκεί",
"Upload failed. Could not find uploaded file" : "Η φόρτωση απέτυχε. Αδυναμία εύρεσης αρχείου προς φόρτωση.",
"Upload failed. Could not get file info." : "Η φόρτωση απέτυχε. Αδυναμία λήψης πληροφοριών αρχείων.",
"Invalid directory." : "Μη έγκυρος φάκελος.",
"Files" : "Αρχεία",
"All files" : "Όλα τα αρχεία",
- "Favorites" : "Αγαπημένες",
+ "Favorites" : "Αγαπημένα",
"Home" : "Σπίτι",
"Close" : "Κλείσιμο",
+ "Upload cancelled." : "Η αποστολή ακυρώθηκε.",
"Unable to upload {filename} as it is a directory or has 0 bytes" : "Αδυναμία φόρτωσης {filename} καθώς είναι κατάλογος αρχείων ή έχει 0 bytes",
"Total file size {size1} exceeds upload limit {size2}" : "Το συνολικό μέγεθος αρχείου {size1} υπερβαίνει το όριο μεταφόρτωσης {size2}",
"Not enough free space, you are uploading {size1} but only {size2} is left" : "Δεν υπάρχει αρκετός ελεύθερος χώρος, μεταφορτώνετε μέγεθος {size1} αλλά υπάρχει χώρος μόνο {size2}",
- "Upload cancelled." : "Η αποστολή ακυρώθηκε.",
"Could not get result from server." : "Αδυναμία λήψης αποτελέσματος από το διακομιστή.",
"File upload is in progress. Leaving the page now will cancel the upload." : "Η αποστολή του αρχείου βρίσκεται σε εξέλιξη. Το κλείσιμο της σελίδας θα ακυρώσει την αποστολή.",
"Actions" : "Ενέργειες",
@@ -44,62 +44,62 @@ OC.L10N.register(
"Select" : "Επιλογή",
"Pending" : "Εκκρεμεί",
"Unable to determine date" : "Αδυναμία προσδιορισμού ημερομηνίας ",
- "This operation is forbidden" : "Αυτή η ενέργεια απαγορεύεται",
+ "This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
"This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
"Error moving file." : "Σφάλμα κατά τη μετακίνηση του αρχείου.",
"Error moving file" : "Σφάλμα κατά τη μετακίνηση του αρχείου",
"Error" : "Σφάλμα",
- "{new_name} already exists" : "{new_name} υπάρχει ήδη",
+ "{new_name} already exists" : "το {new_name} υπάρχει ήδη",
"Could not rename file" : "Αδυναμία μετονομασίας αρχείου",
"Could not create file" : "Αδυναμία δημιουργίας αρχείου",
"Could not create folder" : "Αδυναμία δημιουργίας φακέλου",
- "Error deleting file." : "Σφάλμα διαγραφής αρχείου.",
+ "Error deleting file." : "Σφάλμα κατά τη διαγραφή του αρχείου.",
"No entries in this folder match '{filter}'" : "Δεν ταιριάζουν καταχωρήσεις σε αυτόν το φάκελο '{filter}'",
"Name" : "Όνομα",
"Size" : "Μέγεθος",
"Modified" : "Τροποποιήθηκε",
"_%n folder_::_%n folders_" : ["%n φάκελος","%n φάκελοι"],
"_%n file_::_%n files_" : ["%n αρχείο","%n αρχεία"],
- "{dirs} and {files}" : "{Κατάλογοι αρχείων} και {αρχεία}",
+ "{dirs} and {files}" : "{dirs} και {files}",
"You don’t have permission to upload or create files here" : "Δεν έχετε δικαιώματα φόρτωσης ή δημιουργίας αρχείων εδώ",
"_Uploading %n file_::_Uploading %n files_" : ["Ανέβασμα %n αρχείου","Ανέβασμα %n αρχείων"],
"New" : "Νέο",
- "\"{name}\" is an invalid file name." : "Το \"{name}\" είναι μη έγκυρο όνομα αρχείου.",
+ "\"{name}\" is an invalid file name." : "Το \"{name}\" δεν είναι έγκυρο όνομα αρχείου.",
"File name cannot be empty." : "Το όνομα αρχείου δεν μπορεί να είναι κενό.",
- "Storage of {owner} is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός χώρος του {owner} είναι πλήρης, τα αρχεία δεν δύναται να ενημερωθούν ή να συγχρονίσουν!",
- "Your storage is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός σας χώρος είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν πια!",
- "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος του {owner} είναι σχεδόν πλήρης ({usedSpacePercent}%)",
+ "Storage of {owner} is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός χώρος του {owner} είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν!",
+ "Your storage is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός σας χώρος είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν!",
+ "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος του {owner} είναι σχεδόν γεμάτος ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος είναι σχεδόν γεμάτος ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["ταιριάζουν '{filter}' ","ταιριάζουν '{filter}'"],
"Path" : "Διαδρομή",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Προτιμώμενα",
"Favorite" : "Αγαπημένο",
- "{newname} already exists" : "το {newname} υπάρχει ήδη",
- "Upload" : "Μεταφόρτωση",
"Text file" : "Αρχείο κειμένου",
"New text file.txt" : "Νέο αρχείο κειμένου.txt",
"Folder" : "Φάκελος",
- "New folder" : "Νέος κατάλογος",
+ "New folder" : "Νέος φάκελος",
+ "{newname} already exists" : "το {newname} υπάρχει ήδη",
+ "Upload" : "Μεταφόρτωση",
"An error occurred while trying to update the tags" : "Ένα σφάλμα προέκυψε κατά τη διάρκεια ενημέρωσης των ετικετών",
"A new file or folder has been <strong>created</strong>" : "Ένα νέο αρχείο ή κατάλογος έχουν <strong>δημιουργηθεί</strong>",
"A file or folder has been <strong>changed</strong>" : "Ένα αρχείο ή κατάλογος έχουν <strong>αλλάξει</strong>",
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Βάλτε όριο στις ειδοποιήσεις για τη δημιουργία και αλλαγές στα <strong>αγαπημένα σας αρχεία</strong> <em>(Μόνο Stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Ένα αρχείο ή κατάλογος έχουν <strong>διαγραφεί</strong>",
"A file or folder has been <strong>restored</strong>" : "Ένα αρχείο ή φάκελος <strong>επαναφέρθηκε</ strong>",
- "You created %1$s" : "Δημιουργήσατε %1$s",
- "%2$s created %1$s" : "Ο %2$s δημιούργησε %1$s",
+ "You created %1$s" : "Δημιουργήσατε το %1$s",
+ "%2$s created %1$s" : "Ο χρήστης %2$s δημιούργησε το %1$s",
"%1$s was created in a public folder" : "Το %1$s δημιουργήθηκε σε έναν δημόσιο φάκελο",
- "You changed %1$s" : "Αλλάξατε %1$s",
- "%2$s changed %1$s" : "Ο %2$s άλλαξε %1$s",
- "You deleted %1$s" : "Διαγράψατε %1$s",
- "%2$s deleted %1$s" : "Ο %2$s διέγραψε %1$s",
- "You restored %1$s" : "Επαναφέρατε %1$s",
- "%2$s restored %1$s" : "%2$s επανέφερε %1$s",
- "Changed by %2$s" : "Άλλαξε από %2$s",
- "Deleted by %2$s" : "Διαγράφηκε από %2$s",
- "Restored by %2$s" : "Επαναφορά απο %2$s",
- "%s could not be renamed as it has been deleted" : "%s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
+ "You changed %1$s" : "Αλλάξατε το %1$s",
+ "%2$s changed %1$s" : "Ο χρήστης %2$s άλλαξε το %1$s",
+ "You deleted %1$s" : "Διαγράψατε το %1$s",
+ "%2$s deleted %1$s" : "Ο χρήστης %2$s διέγραψε το %1$s",
+ "You restored %1$s" : "Επαναφέρατε το %1$s",
+ "%2$s restored %1$s" : "Ο χρήστης %2$s επανέφερε το %1$s",
+ "Changed by %2$s" : "Άλλαξε από το χρήστη %2$s",
+ "Deleted by %2$s" : "Διαγράφηκε από το χρήστη %2$s",
+ "Restored by %2$s" : "Επαναφορά από το χρήστη %2$s",
+ "%s could not be renamed as it has been deleted" : "Το %s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
"%s could not be renamed" : "Αδυναμία μετονομασίας του %s",
"Upload (max. %s)" : "Διαμοιρασμός (max. %s)",
"File handling" : "Διαχείριση αρχείων",
@@ -107,7 +107,7 @@ OC.L10N.register(
"max. possible: " : "μέγιστο δυνατό:",
"With PHP-FPM this value may take up to 5 minutes to take effect after saving." : "Με την PHP-FPM αυτή η τιμή μπορεί να χρειαστεί μέχρι και 5 λεπτά για να ενεργοποιηθεί μετά την αποθήκευση.",
"Save" : "Αποθήκευση",
- "Can not be edited from here due to insufficient permissions." : "Δεν υπάρχει εδώ η δυνατότητα επεξεργασίας λόγω μη επαρκών δικαιωμάτων",
+ "Can not be edited from here due to insufficient permissions." : "Δεν είναι δυνατή η επεξεργασία λόγω μη επαρκών δικαιωμάτων",
"Settings" : "Ρυθμίσεις",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Χρησιμοποιήστε αυτήν την διεύθυνση για να αποκτήσετε <a href=\"%s\" target=\"_blank\">πρόσβαση στα αρχεία σας μέσω WebDAV</a>",
diff --git a/apps/files/l10n/el.json b/apps/files/l10n/el.json
index b374964c8b6..baaea21511c 100644
--- a/apps/files/l10n/el.json
+++ b/apps/files/l10n/el.json
@@ -8,7 +8,7 @@
"The target folder has been moved or deleted." : "Ο φάκελος προορισμού έχει μετακινηθεί ή διαγραφεί.",
"The name %s is already used in the folder %s. Please choose a different name." : "Το όνομα %s χρησιμοποιείτε ήδη στον φάκελο %s. Παρακαλώ επιλέξτε ένα άλλο όνομα.",
"Error when creating the file" : "Σφάλμα κατά τη δημιουργία του αρχείου",
- "Error when creating the folder" : "Σφάλμα δημιουργίας φακέλου",
+ "Error when creating the folder" : "Σφάλμα κατά τη δημιουργία του φακέλου",
"Unable to set upload directory." : "Αδυναμία ορισμού καταλόγου αποστολής.",
"Invalid Token" : "Μη έγκυρο Token",
"No file was uploaded. Unknown error" : "Δεν ανέβηκε κάποιο αρχείο. Άγνωστο σφάλμα",
@@ -19,19 +19,19 @@
"No file was uploaded" : "Κανένα αρχείο δεν στάλθηκε",
"Missing a temporary folder" : "Λείπει ο προσωρινός φάκελος",
"Failed to write to disk" : "Αποτυχία εγγραφής στο δίσκο",
- "Not enough storage available" : "Μη επαρκής διαθέσιμος αποθηκευτικός χώρος",
+ "Not enough storage available" : "Ο διαθέσιμος αποθηκευτικός χώρος δεν επαρκεί",
"Upload failed. Could not find uploaded file" : "Η φόρτωση απέτυχε. Αδυναμία εύρεσης αρχείου προς φόρτωση.",
"Upload failed. Could not get file info." : "Η φόρτωση απέτυχε. Αδυναμία λήψης πληροφοριών αρχείων.",
"Invalid directory." : "Μη έγκυρος φάκελος.",
"Files" : "Αρχεία",
"All files" : "Όλα τα αρχεία",
- "Favorites" : "Αγαπημένες",
+ "Favorites" : "Αγαπημένα",
"Home" : "Σπίτι",
"Close" : "Κλείσιμο",
+ "Upload cancelled." : "Η αποστολή ακυρώθηκε.",
"Unable to upload {filename} as it is a directory or has 0 bytes" : "Αδυναμία φόρτωσης {filename} καθώς είναι κατάλογος αρχείων ή έχει 0 bytes",
"Total file size {size1} exceeds upload limit {size2}" : "Το συνολικό μέγεθος αρχείου {size1} υπερβαίνει το όριο μεταφόρτωσης {size2}",
"Not enough free space, you are uploading {size1} but only {size2} is left" : "Δεν υπάρχει αρκετός ελεύθερος χώρος, μεταφορτώνετε μέγεθος {size1} αλλά υπάρχει χώρος μόνο {size2}",
- "Upload cancelled." : "Η αποστολή ακυρώθηκε.",
"Could not get result from server." : "Αδυναμία λήψης αποτελέσματος από το διακομιστή.",
"File upload is in progress. Leaving the page now will cancel the upload." : "Η αποστολή του αρχείου βρίσκεται σε εξέλιξη. Το κλείσιμο της σελίδας θα ακυρώσει την αποστολή.",
"Actions" : "Ενέργειες",
@@ -42,62 +42,62 @@
"Select" : "Επιλογή",
"Pending" : "Εκκρεμεί",
"Unable to determine date" : "Αδυναμία προσδιορισμού ημερομηνίας ",
- "This operation is forbidden" : "Αυτή η ενέργεια απαγορεύεται",
+ "This operation is forbidden" : "Αυτή η ενέργεια δεν επιτρέπεται",
"This directory is unavailable, please check the logs or contact the administrator" : "Ο κατάλογος δεν είναι διαθέσιμος, παρακαλώ ελέγξτε τα αρχεία καταγραφής ή επικοινωνήστε με το διαχειριστή",
"Error moving file." : "Σφάλμα κατά τη μετακίνηση του αρχείου.",
"Error moving file" : "Σφάλμα κατά τη μετακίνηση του αρχείου",
"Error" : "Σφάλμα",
- "{new_name} already exists" : "{new_name} υπάρχει ήδη",
+ "{new_name} already exists" : "το {new_name} υπάρχει ήδη",
"Could not rename file" : "Αδυναμία μετονομασίας αρχείου",
"Could not create file" : "Αδυναμία δημιουργίας αρχείου",
"Could not create folder" : "Αδυναμία δημιουργίας φακέλου",
- "Error deleting file." : "Σφάλμα διαγραφής αρχείου.",
+ "Error deleting file." : "Σφάλμα κατά τη διαγραφή του αρχείου.",
"No entries in this folder match '{filter}'" : "Δεν ταιριάζουν καταχωρήσεις σε αυτόν το φάκελο '{filter}'",
"Name" : "Όνομα",
"Size" : "Μέγεθος",
"Modified" : "Τροποποιήθηκε",
"_%n folder_::_%n folders_" : ["%n φάκελος","%n φάκελοι"],
"_%n file_::_%n files_" : ["%n αρχείο","%n αρχεία"],
- "{dirs} and {files}" : "{Κατάλογοι αρχείων} και {αρχεία}",
+ "{dirs} and {files}" : "{dirs} και {files}",
"You don’t have permission to upload or create files here" : "Δεν έχετε δικαιώματα φόρτωσης ή δημιουργίας αρχείων εδώ",
"_Uploading %n file_::_Uploading %n files_" : ["Ανέβασμα %n αρχείου","Ανέβασμα %n αρχείων"],
"New" : "Νέο",
- "\"{name}\" is an invalid file name." : "Το \"{name}\" είναι μη έγκυρο όνομα αρχείου.",
+ "\"{name}\" is an invalid file name." : "Το \"{name}\" δεν είναι έγκυρο όνομα αρχείου.",
"File name cannot be empty." : "Το όνομα αρχείου δεν μπορεί να είναι κενό.",
- "Storage of {owner} is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός χώρος του {owner} είναι πλήρης, τα αρχεία δεν δύναται να ενημερωθούν ή να συγχρονίσουν!",
- "Your storage is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός σας χώρος είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν πια!",
- "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος του {owner} είναι σχεδόν πλήρης ({usedSpacePercent}%)",
+ "Storage of {owner} is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός χώρος του {owner} είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν!",
+ "Your storage is full, files can not be updated or synced anymore!" : "Ο αποθηκευτικός σας χώρος είναι γεμάτος, τα αρχεία δεν μπορούν να ενημερωθούν ή να συγχρονιστούν!",
+ "Storage of {owner} is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος του {owner} είναι σχεδόν γεμάτος ({usedSpacePercent}%)",
"Your storage is almost full ({usedSpacePercent}%)" : "Ο αποθηκευτικός χώρος είναι σχεδόν γεμάτος ({usedSpacePercent}%)",
"_matches '{filter}'_::_match '{filter}'_" : ["ταιριάζουν '{filter}' ","ταιριάζουν '{filter}'"],
"Path" : "Διαδρομή",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Προτιμώμενα",
"Favorite" : "Αγαπημένο",
- "{newname} already exists" : "το {newname} υπάρχει ήδη",
- "Upload" : "Μεταφόρτωση",
"Text file" : "Αρχείο κειμένου",
"New text file.txt" : "Νέο αρχείο κειμένου.txt",
"Folder" : "Φάκελος",
- "New folder" : "Νέος κατάλογος",
+ "New folder" : "Νέος φάκελος",
+ "{newname} already exists" : "το {newname} υπάρχει ήδη",
+ "Upload" : "Μεταφόρτωση",
"An error occurred while trying to update the tags" : "Ένα σφάλμα προέκυψε κατά τη διάρκεια ενημέρωσης των ετικετών",
"A new file or folder has been <strong>created</strong>" : "Ένα νέο αρχείο ή κατάλογος έχουν <strong>δημιουργηθεί</strong>",
"A file or folder has been <strong>changed</strong>" : "Ένα αρχείο ή κατάλογος έχουν <strong>αλλάξει</strong>",
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Βάλτε όριο στις ειδοποιήσεις για τη δημιουργία και αλλαγές στα <strong>αγαπημένα σας αρχεία</strong> <em>(Μόνο Stream)</em>",
"A file or folder has been <strong>deleted</strong>" : "Ένα αρχείο ή κατάλογος έχουν <strong>διαγραφεί</strong>",
"A file or folder has been <strong>restored</strong>" : "Ένα αρχείο ή φάκελος <strong>επαναφέρθηκε</ strong>",
- "You created %1$s" : "Δημιουργήσατε %1$s",
- "%2$s created %1$s" : "Ο %2$s δημιούργησε %1$s",
+ "You created %1$s" : "Δημιουργήσατε το %1$s",
+ "%2$s created %1$s" : "Ο χρήστης %2$s δημιούργησε το %1$s",
"%1$s was created in a public folder" : "Το %1$s δημιουργήθηκε σε έναν δημόσιο φάκελο",
- "You changed %1$s" : "Αλλάξατε %1$s",
- "%2$s changed %1$s" : "Ο %2$s άλλαξε %1$s",
- "You deleted %1$s" : "Διαγράψατε %1$s",
- "%2$s deleted %1$s" : "Ο %2$s διέγραψε %1$s",
- "You restored %1$s" : "Επαναφέρατε %1$s",
- "%2$s restored %1$s" : "%2$s επανέφερε %1$s",
- "Changed by %2$s" : "Άλλαξε από %2$s",
- "Deleted by %2$s" : "Διαγράφηκε από %2$s",
- "Restored by %2$s" : "Επαναφορά απο %2$s",
- "%s could not be renamed as it has been deleted" : "%s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
+ "You changed %1$s" : "Αλλάξατε το %1$s",
+ "%2$s changed %1$s" : "Ο χρήστης %2$s άλλαξε το %1$s",
+ "You deleted %1$s" : "Διαγράψατε το %1$s",
+ "%2$s deleted %1$s" : "Ο χρήστης %2$s διέγραψε το %1$s",
+ "You restored %1$s" : "Επαναφέρατε το %1$s",
+ "%2$s restored %1$s" : "Ο χρήστης %2$s επανέφερε το %1$s",
+ "Changed by %2$s" : "Άλλαξε από το χρήστη %2$s",
+ "Deleted by %2$s" : "Διαγράφηκε από το χρήστη %2$s",
+ "Restored by %2$s" : "Επαναφορά από το χρήστη %2$s",
+ "%s could not be renamed as it has been deleted" : "Το %s δεν μπορούσε να μετονομαστεί εφόσον είχε διαγραφεί",
"%s could not be renamed" : "Αδυναμία μετονομασίας του %s",
"Upload (max. %s)" : "Διαμοιρασμός (max. %s)",
"File handling" : "Διαχείριση αρχείων",
@@ -105,7 +105,7 @@
"max. possible: " : "μέγιστο δυνατό:",
"With PHP-FPM this value may take up to 5 minutes to take effect after saving." : "Με την PHP-FPM αυτή η τιμή μπορεί να χρειαστεί μέχρι και 5 λεπτά για να ενεργοποιηθεί μετά την αποθήκευση.",
"Save" : "Αποθήκευση",
- "Can not be edited from here due to insufficient permissions." : "Δεν υπάρχει εδώ η δυνατότητα επεξεργασίας λόγω μη επαρκών δικαιωμάτων",
+ "Can not be edited from here due to insufficient permissions." : "Δεν είναι δυνατή η επεξεργασία λόγω μη επαρκών δικαιωμάτων",
"Settings" : "Ρυθμίσεις",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Χρησιμοποιήστε αυτήν την διεύθυνση για να αποκτήσετε <a href=\"%s\" target=\"_blank\">πρόσβαση στα αρχεία σας μέσω WebDAV</a>",
diff --git a/apps/files_external/ajax/oauth2.php b/apps/files_external/ajax/oauth2.php
index e3e32c4b912..fbe60e16e26 100644
--- a/apps/files_external/ajax/oauth2.php
+++ b/apps/files_external/ajax/oauth2.php
@@ -41,6 +41,7 @@ if (isset($_POST['client_id']) && isset($_POST['client_secret']) && isset($_POST
$client->setClientSecret((string)$_POST['client_secret']);
$client->setRedirectUri((string)$_POST['redirect']);
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
+ $client->setApprovalPrompt('force');
$client->setAccessType('offline');
if (isset($_POST['step'])) {
$step = $_POST['step'];
diff --git a/apps/files_external/l10n/cs_CZ.js b/apps/files_external/l10n/cs_CZ.js
index 5ede97f70db..3e9a14f9998 100644
--- a/apps/files_external/l10n/cs_CZ.js
+++ b/apps/files_external/l10n/cs_CZ.js
@@ -47,6 +47,8 @@ OC.L10N.register(
"OpenStack" : "OpenStack",
"Username" : "Uživatelské jméno",
"Password" : "Heslo",
+ "Tenant name" : "Jméno vlastníka",
+ "Identity endpoint URL" : "Identifikační koncový bod URL",
"Rackspace" : "Rackspace",
"API key" : "Klíč API",
"Username and password" : "Uživatelské jméno a heslo",
diff --git a/apps/files_external/l10n/cs_CZ.json b/apps/files_external/l10n/cs_CZ.json
index d15e2424bc7..4c6f940666e 100644
--- a/apps/files_external/l10n/cs_CZ.json
+++ b/apps/files_external/l10n/cs_CZ.json
@@ -45,6 +45,8 @@
"OpenStack" : "OpenStack",
"Username" : "Uživatelské jméno",
"Password" : "Heslo",
+ "Tenant name" : "Jméno vlastníka",
+ "Identity endpoint URL" : "Identifikační koncový bod URL",
"Rackspace" : "Rackspace",
"API key" : "Klíč API",
"Username and password" : "Uživatelské jméno a heslo",
diff --git a/apps/files_external/l10n/el.js b/apps/files_external/l10n/el.js
index df3bdcedcfd..a83c241af7a 100644
--- a/apps/files_external/l10n/el.js
+++ b/apps/files_external/l10n/el.js
@@ -102,6 +102,7 @@ OC.L10N.register(
"Advanced settings" : "Ρυθμίσεις για προχωρημένους",
"Delete" : "Διαγραφή",
"Add storage" : "Προσθηκη αποθηκευσης",
+ "Allow users to mount external storage" : "Να επιτρέπεται στους χρήστες η σύνδεση εξωτερικού χώρου",
"Allow users to mount the following external storage" : "Χορήγηση άδειας στους χρήστες να συνδέσουν τα παρακάτω εξωτερικά μέσα αποθήκευσης"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/el.json b/apps/files_external/l10n/el.json
index ee5131b9f64..32f223cf8c0 100644
--- a/apps/files_external/l10n/el.json
+++ b/apps/files_external/l10n/el.json
@@ -100,6 +100,7 @@
"Advanced settings" : "Ρυθμίσεις για προχωρημένους",
"Delete" : "Διαγραφή",
"Add storage" : "Προσθηκη αποθηκευσης",
+ "Allow users to mount external storage" : "Να επιτρέπεται στους χρήστες η σύνδεση εξωτερικού χώρου",
"Allow users to mount the following external storage" : "Χορήγηση άδειας στους χρήστες να συνδέσουν τα παρακάτω εξωτερικά μέσα αποθήκευσης"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/fr.js b/apps/files_external/l10n/fr.js
index 3358b36cf8e..1389cd1233b 100644
--- a/apps/files_external/l10n/fr.js
+++ b/apps/files_external/l10n/fr.js
@@ -102,7 +102,7 @@ OC.L10N.register(
"Advanced settings" : "Paramètres avancés",
"Delete" : "Supprimer",
"Add storage" : "Ajouter un support de stockage",
- "Allow users to mount external storage" : "Autoriser les utilisateurs à monter l'espace de stockage externe",
+ "Allow users to mount external storage" : "Autoriser les utilisateurs à monter des espaces de stockage externes",
"Allow users to mount the following external storage" : "Autoriser les utilisateurs à monter les stockages externes suivants"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_external/l10n/fr.json b/apps/files_external/l10n/fr.json
index 684f2b51970..9d078bf13fc 100644
--- a/apps/files_external/l10n/fr.json
+++ b/apps/files_external/l10n/fr.json
@@ -100,7 +100,7 @@
"Advanced settings" : "Paramètres avancés",
"Delete" : "Supprimer",
"Add storage" : "Ajouter un support de stockage",
- "Allow users to mount external storage" : "Autoriser les utilisateurs à monter l'espace de stockage externe",
+ "Allow users to mount external storage" : "Autoriser les utilisateurs à monter des espaces de stockage externes",
"Allow users to mount the following external storage" : "Autoriser les utilisateurs à monter les stockages externes suivants"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/ja.js b/apps/files_external/l10n/ja.js
index c9f489928cb..4481c7fdd2e 100644
--- a/apps/files_external/l10n/ja.js
+++ b/apps/files_external/l10n/ja.js
@@ -102,6 +102,7 @@ OC.L10N.register(
"Advanced settings" : "詳細設定",
"Delete" : "削除",
"Add storage" : "ストレージを追加",
+ "Allow users to mount external storage" : "ユーザーに外部ストレージの接続を許可する",
"Allow users to mount the following external storage" : "ユーザーに以下の外部ストレージのマウントを許可する"
},
"nplurals=1; plural=0;");
diff --git a/apps/files_external/l10n/ja.json b/apps/files_external/l10n/ja.json
index 1e52d429a2c..5573c11fe84 100644
--- a/apps/files_external/l10n/ja.json
+++ b/apps/files_external/l10n/ja.json
@@ -100,6 +100,7 @@
"Advanced settings" : "詳細設定",
"Delete" : "削除",
"Add storage" : "ストレージを追加",
+ "Allow users to mount external storage" : "ユーザーに外部ストレージの接続を許可する",
"Allow users to mount the following external storage" : "ユーザーに以下の外部ストレージのマウントを許可する"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/nl.js b/apps/files_external/l10n/nl.js
index 92f01018a61..57481ce4176 100644
--- a/apps/files_external/l10n/nl.js
+++ b/apps/files_external/l10n/nl.js
@@ -102,6 +102,7 @@ OC.L10N.register(
"Advanced settings" : "Geavanceerde instellingen",
"Delete" : "Verwijder",
"Add storage" : "Toevoegen opslag",
+ "Allow users to mount external storage" : "Sta gebruikers toe om een externe opslag aan te koppelen",
"Allow users to mount the following external storage" : "Sta gebruikers toe de volgende externe opslag aan te koppelen"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/nl.json b/apps/files_external/l10n/nl.json
index 9d56dd127c3..fc80c3bbb2c 100644
--- a/apps/files_external/l10n/nl.json
+++ b/apps/files_external/l10n/nl.json
@@ -100,6 +100,7 @@
"Advanced settings" : "Geavanceerde instellingen",
"Delete" : "Verwijder",
"Add storage" : "Toevoegen opslag",
+ "Allow users to mount external storage" : "Sta gebruikers toe om een externe opslag aan te koppelen",
"Allow users to mount the following external storage" : "Sta gebruikers toe de volgende externe opslag aan te koppelen"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/oc.js b/apps/files_external/l10n/oc.js
index 4809cf92352..a45aebf81ba 100644
--- a/apps/files_external/l10n/oc.js
+++ b/apps/files_external/l10n/oc.js
@@ -16,6 +16,7 @@ OC.L10N.register(
"Not permitted to use authentication mechanism \"%s\"" : "Pas autorizat a utilizar lo mecanisme d'autentificacion \"%s\"",
"Unsatisfied backend parameters" : "Paramètres mancants pel servici",
"Unsatisfied authentication mechanism parameters" : "Paramètres mancants pel metòde d'autentificacion",
+ "Insufficient data: %s" : "Donadas insufisentas : %s",
"Personal" : "Personal",
"System" : "Sistèma",
"Grant access" : "Autorizar l'accès",
@@ -101,6 +102,7 @@ OC.L10N.register(
"Advanced settings" : "Paramètres avançats",
"Delete" : "Suprimir",
"Add storage" : "Apondre un supòrt d'emmagazinatge",
+ "Allow users to mount external storage" : "Autorizar los utilizaires a montar l'espaci d'emmagazinatge extèrne",
"Allow users to mount the following external storage" : "Autorizar los utilizaires a montar los emmagazinatges extèrnes seguents"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_external/l10n/oc.json b/apps/files_external/l10n/oc.json
index 30163f958fc..c49326a955f 100644
--- a/apps/files_external/l10n/oc.json
+++ b/apps/files_external/l10n/oc.json
@@ -14,6 +14,7 @@
"Not permitted to use authentication mechanism \"%s\"" : "Pas autorizat a utilizar lo mecanisme d'autentificacion \"%s\"",
"Unsatisfied backend parameters" : "Paramètres mancants pel servici",
"Unsatisfied authentication mechanism parameters" : "Paramètres mancants pel metòde d'autentificacion",
+ "Insufficient data: %s" : "Donadas insufisentas : %s",
"Personal" : "Personal",
"System" : "Sistèma",
"Grant access" : "Autorizar l'accès",
@@ -99,6 +100,7 @@
"Advanced settings" : "Paramètres avançats",
"Delete" : "Suprimir",
"Add storage" : "Apondre un supòrt d'emmagazinatge",
+ "Allow users to mount external storage" : "Autorizar los utilizaires a montar l'espaci d'emmagazinatge extèrne",
"Allow users to mount the following external storage" : "Autorizar los utilizaires a montar los emmagazinatges extèrnes seguents"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 56a7e547ec6..6c900f0f224 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -269,7 +269,7 @@ class OC_Mount_Config {
}
} catch (Exception $exception) {
\OCP\Util::logException('files_external', $exception);
- throw $e;
+ throw $exception;
}
}
return self::STATUS_ERROR;
diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php
new file mode 100644
index 00000000000..8c0d8f7d150
--- /dev/null
+++ b/apps/files_sharing/api/ocssharewrapper.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files_Sharing\API;
+
+class OCSShareWrapper {
+
+ /**
+ * @return Share20OCS
+ */
+ private function getShare20OCS() {
+ return new Share20OCS(new \OC\Share20\Manager(
+ \OC::$server->getUserSession()->getUser(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getLogger(),
+ \OC::$server->getAppConfig(),
+ \OC::$server->getUserFolder(),
+ new \OC\Share20\DefaultShareProvider(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getUserFolder()
+ )
+ ),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getRequest(),
+ \OC::$server->getUserFolder());
+ }
+
+ public function getAllShares($params) {
+ return \OCA\Files_Sharing\API\Local::getAllShares($params);
+ }
+
+ public function createShare($params) {
+ return \OCA\Files_Sharing\API\Local::createShare($params);
+ }
+
+ public function getShare($params) {
+ return \OCA\Files_Sharing\API\Local::getShare($params);
+ }
+
+ public function updateShare($params) {
+ return \OCA\Files_Sharing\API\Local::updateShare($params);
+ }
+
+ public function deleteShare($params) {
+ $id = (int)$params['id'];
+ return $this->getShare20OCS()->deleteShare($id);
+ }
+}
diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php
new file mode 100644
index 00000000000..8a7f90c0023
--- /dev/null
+++ b/apps/files_sharing/api/share20ocs.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files_Sharing\API;
+
+class Share20OCS {
+
+ /** @var OC\Share20\Manager */
+ private $shareManager;
+
+ /** @var OCP\IGroupManager */
+ private $groupManager;
+
+ /** @var OCP\IUserManager */
+ private $userManager;
+
+ /** @var OCP\IRequest */
+ private $request;
+
+ /** @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) {
+ $this->shareManager = $shareManager;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->request = $request;
+ $this->userFolder = $userFolder;
+ }
+
+ /**
+ * Delete a share
+ *
+ * @param int $id
+ * @return \OC_OCS_Result
+ */
+ public function deleteShare($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.');
+ }
+
+ /*
+ * FIXME
+ * User the old code path for remote shares until we have our remoteshareprovider
+ */
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
+ \OCA\Files_Sharing\API\Local::deleteShare(['id' => $id]);
+ }
+
+ try {
+ $this->shareManager->deleteShare($share);
+ } catch (\OC\Share20\Exception\BackendError $e) {
+ return new \OC_OCS_Result(null, 404, 'could not delete share');
+ }
+
+ return new \OC_OCS_Result();
+ }
+}
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index db7aa126c4e..8755691c1e8 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -61,29 +61,31 @@ $this->create('sharing_external_add', '/external')
//TODO: SET: mail notification, waiting for PR #4689 to be accepted
+$OCSShare = new \OCA\Files_Sharing\API\OCSShareWrapper();
+
API::register('get',
'/apps/files_sharing/api/v1/shares',
- array('\OCA\Files_Sharing\API\Local', 'getAllShares'),
+ [$OCSShare, 'getAllShares'],
'files_sharing');
API::register('post',
'/apps/files_sharing/api/v1/shares',
- array('\OCA\Files_Sharing\API\Local', 'createShare'),
+ [$OCSShare, 'createShare'],
'files_sharing');
API::register('get',
'/apps/files_sharing/api/v1/shares/{id}',
- array('\OCA\Files_Sharing\API\Local', 'getShare'),
+ [$OCSShare, 'getShare'],
'files_sharing');
API::register('put',
'/apps/files_sharing/api/v1/shares/{id}',
- array('\OCA\Files_Sharing\API\Local', 'updateShare'),
+ [$OCSShare, 'updateShare'],
'files_sharing');
API::register('delete',
'/apps/files_sharing/api/v1/shares/{id}',
- array('\OCA\Files_Sharing\API\Local', 'deleteShare'),
+ [$OCSShare, 'deleteShare'],
'files_sharing');
API::register('get',
@@ -130,3 +132,4 @@ API::register('get',
'/apps/files_sharing/api/v1/sharees',
[$sharees, 'search'],
'files_sharing', API::USER_AUTH);
+
diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php
new file mode 100644
index 00000000000..9c4377a2a7f
--- /dev/null
+++ b/apps/files_sharing/tests/api/share20ocstest.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files_Sharing\Tests\API;
+
+use OCA\Files_Sharing\API\Share20OCS;
+
+class Share20OCSTest extends \Test\TestCase {
+
+ /** @var OC\Share20\Manager */
+ private $shareManager;
+
+ /** @var OCP\IGroupManager */
+ private $groupManager;
+
+ /** @var OCP\IUserManager */
+ private $userManager;
+
+ /** @var OCP\IRequest */
+ private $request;
+
+ /** @var OCP\Files\Folder */
+ private $userFolder;
+
+ /** @var OCS */
+ private $ocs;
+
+ protected function setUp() {
+ $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->ocs = new Share20OCS($this->shareManager,
+ $this->groupManager,
+ $this->userManager,
+ $this->request,
+ $this->userFolder);
+ }
+
+ public function testDeleteShareShareNotFound() {
+ $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->deleteShare(42));
+ }
+
+ public function testDeleteShareCouldNotDelete() {
+ $share = $this->getMock('OC\Share20\IShare');
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->willReturn($share);
+ $this->shareManager
+ ->expects($this->once())
+ ->method('deleteShare')
+ ->with($share)
+ ->will($this->throwException(new \OC\Share20\Exception\BackendError()));
+
+
+ $expected = new \OC_OCS_Result(null, 404, 'could not delete share');
+ $this->assertEquals($expected, $this->ocs->deleteShare(42));
+ }
+
+ public function testDeleteShare() {
+ $share = $this->getMock('OC\Share20\IShare');
+ $this->shareManager
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->willReturn($share);
+ $this->shareManager
+ ->expects($this->once())
+ ->method('deleteShare')
+ ->with($share);
+
+ $expected = new \OC_OCS_Result();
+ $this->assertEquals($expected, $this->ocs->deleteShare(42));
+ }
+}
diff --git a/apps/provisioning_api/lib/users.php b/apps/provisioning_api/lib/users.php
index a9fafb48912..304fe901cfd 100644
--- a/apps/provisioning_api/lib/users.php
+++ b/apps/provisioning_api/lib/users.php
@@ -388,11 +388,16 @@ class Users {
return new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED);
}
- $group = $this->groupManager->get(!empty($parameters['_delete']['groupid']) ? $parameters['_delete']['groupid'] : null);
+ $group = !empty($parameters['_delete']['groupid']) ? $parameters['_delete']['groupid'] : null;
if($group === null) {
return new OC_OCS_Result(null, 101);
}
+ $group = $this->groupManager->get($group);
+ if($group === null) {
+ return new OC_OCS_Result(null, 102);
+ }
+
$targetUser = $this->userManager->get($parameters['userid']);
if($targetUser === null) {
return new OC_OCS_Result(null, 103);
diff --git a/apps/provisioning_api/tests/userstest.php b/apps/provisioning_api/tests/userstest.php
index c5a1ac3061e..ba4ed8a2e2f 100644
--- a/apps/provisioning_api/tests/userstest.php
+++ b/apps/provisioning_api/tests/userstest.php
@@ -1357,6 +1357,16 @@ class UsersTest extends OriginalTest {
$this->assertEquals($expected, $this->api->removeFromGroup(['userid' => 'TargetUser', '_delete' => ['groupid' => 'TargetGroup']]));
}
+ public function testRemoveFromGroupWithNoTargetGroup() {
+ $loggedInUser = $this->getMock('\OCP\IUser');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($loggedInUser));
+ $expected = new \OC_OCS_Result(null, 101);
+ $this->assertEquals($expected, $this->api->removeFromGroup(['userid' => 'TargetUser', '_delete' => []]));
+ }
+
public function testRemoveFromGroupWithNotExistingTargetGroup() {
$loggedInUser = $this->getMock('\OCP\IUser');
$this->userSession
@@ -1369,7 +1379,7 @@ class UsersTest extends OriginalTest {
->with('TargetGroup')
->will($this->returnValue(null));
- $expected = new \OC_OCS_Result(null, 101);
+ $expected = new \OC_OCS_Result(null, 102);
$this->assertEquals($expected, $this->api->removeFromGroup(['userid' => 'TargetUser', '_delete' => ['groupid' => 'TargetGroup']]));
}
diff --git a/apps/user_ldap/l10n/hu_HU.js b/apps/user_ldap/l10n/hu_HU.js
index 25035fb32cf..36fdcad3806 100644
--- a/apps/user_ldap/l10n/hu_HU.js
+++ b/apps/user_ldap/l10n/hu_HU.js
@@ -64,7 +64,7 @@ OC.L10N.register(
"Turn off SSL certificate validation." : "Ne ellenőrizzük az SSL-tanúsítvány érvényességét",
"Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." : "Használata nem javasolt (kivéve tesztelési céllal). Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát a(z) %s kiszolgálóra!",
"Cache Time-To-Live" : "A gyorsítótár tárolási időtartama",
- "in seconds. A change empties the cache." : "másodpercben. A változtatás törli a cache tartalmát.",
+ "in seconds. A change empties the cache." : "másodpercen belül. A változtatás törli a gyorsítótár tartalmát.",
"Directory Settings" : "Címtár beállítások",
"User Display Name Field" : "A felhasználónév mezője",
"The LDAP attribute to use to generate the user's display name." : "Ebből az LDAP attribútumból képződik a felhasználó megjelenítendő neve.",
diff --git a/apps/user_ldap/l10n/hu_HU.json b/apps/user_ldap/l10n/hu_HU.json
index 0778e627e2c..14f16217ee3 100644
--- a/apps/user_ldap/l10n/hu_HU.json
+++ b/apps/user_ldap/l10n/hu_HU.json
@@ -62,7 +62,7 @@
"Turn off SSL certificate validation." : "Ne ellenőrizzük az SSL-tanúsítvány érvényességét",
"Not recommended, use it for testing only! If connection only works with this option, import the LDAP server's SSL certificate in your %s server." : "Használata nem javasolt (kivéve tesztelési céllal). Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát a(z) %s kiszolgálóra!",
"Cache Time-To-Live" : "A gyorsítótár tárolási időtartama",
- "in seconds. A change empties the cache." : "másodpercben. A változtatás törli a cache tartalmát.",
+ "in seconds. A change empties the cache." : "másodpercen belül. A változtatás törli a gyorsítótár tartalmát.",
"Directory Settings" : "Címtár beállítások",
"User Display Name Field" : "A felhasználónév mezője",
"The LDAP attribute to use to generate the user's display name." : "Ebből az LDAP attribútumból képződik a felhasználó megjelenítendő neve.",
diff --git a/apps/user_ldap/l10n/zh_TW.js b/apps/user_ldap/l10n/zh_TW.js
index 569cbf24128..c6830f96a83 100644
--- a/apps/user_ldap/l10n/zh_TW.js
+++ b/apps/user_ldap/l10n/zh_TW.js
@@ -108,11 +108,13 @@ OC.L10N.register(
"in seconds. A change empties the cache." : "以秒為單位。變更後會清空快取。",
"Directory Settings" : "目錄設定",
"User Display Name Field" : "使用者顯示名稱欄位",
+ "The LDAP attribute to use to generate the user's display name." : "LDAP設定值,用於產生使用者的顯示名稱",
"Base User Tree" : "Base User Tree",
"One User Base DN per line" : "一行一個使用者 Base DN",
"User Search Attributes" : "User Search Attributes",
"Optional; one attribute per line" : "非必要,一行一項屬性",
"Group Display Name Field" : "群組顯示名稱欄位",
+ "The LDAP attribute to use to generate the groups's display name." : "LDAP設定值,用於產生使用者群組的顯示名稱",
"Base Group Tree" : "Base Group Tree",
"One Group Base DN per line" : "一行一個 Group Base DN",
"Group Search Attributes" : "Group Search Attributes",
@@ -126,6 +128,7 @@ OC.L10N.register(
"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." : "使用者名稱請留白(預設)。若不留白請指定一個LDAP/AD屬性。",
"Internal Username" : "內部使用者名稱",
"Internal Username Attribute:" : "內部使用者名稱屬性:",
+ "Override UUID detection" : "偵測覆寫UUID",
"UUID Attribute for Users:" : "使用者的UUID值:",
"UUID Attribute for Groups:" : "群組的UUID值:"
},
diff --git a/apps/user_ldap/l10n/zh_TW.json b/apps/user_ldap/l10n/zh_TW.json
index e012c3003ac..0661836bac2 100644
--- a/apps/user_ldap/l10n/zh_TW.json
+++ b/apps/user_ldap/l10n/zh_TW.json
@@ -106,11 +106,13 @@
"in seconds. A change empties the cache." : "以秒為單位。變更後會清空快取。",
"Directory Settings" : "目錄設定",
"User Display Name Field" : "使用者顯示名稱欄位",
+ "The LDAP attribute to use to generate the user's display name." : "LDAP設定值,用於產生使用者的顯示名稱",
"Base User Tree" : "Base User Tree",
"One User Base DN per line" : "一行一個使用者 Base DN",
"User Search Attributes" : "User Search Attributes",
"Optional; one attribute per line" : "非必要,一行一項屬性",
"Group Display Name Field" : "群組顯示名稱欄位",
+ "The LDAP attribute to use to generate the groups's display name." : "LDAP設定值,用於產生使用者群組的顯示名稱",
"Base Group Tree" : "Base Group Tree",
"One Group Base DN per line" : "一行一個 Group Base DN",
"Group Search Attributes" : "Group Search Attributes",
@@ -124,6 +126,7 @@
"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." : "使用者名稱請留白(預設)。若不留白請指定一個LDAP/AD屬性。",
"Internal Username" : "內部使用者名稱",
"Internal Username Attribute:" : "內部使用者名稱屬性:",
+ "Override UUID detection" : "偵測覆寫UUID",
"UUID Attribute for Users:" : "使用者的UUID值:",
"UUID Attribute for Groups:" : "群組的UUID值:"
},"pluralForm" :"nplurals=1; plural=0;"
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index f6b123babd0..3f3953bb28b 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -526,30 +526,41 @@ class Connection extends LDAPUtility {
\OCP\Util::WARN);
}
}
- if(!$this->configuration->ldapOverrideMainServer
- && !$this->getFromCache('overrideMainServer')) {
- $this->doConnect($this->configuration->ldapHost,
- $this->configuration->ldapPort);
- $bindStatus = $this->bind();
- $error = $this->ldap->isResource($this->ldapConnectionRes) ?
- $this->ldap->errno($this->ldapConnectionRes) : -1;
- } else {
- $bindStatus = false;
- $error = null;
+
+ $bindStatus = false;
+ $error = null;
+ try {
+ if (!$this->configuration->ldapOverrideMainServer
+ && !$this->getFromCache('overrideMainServer')
+ ) {
+ $this->doConnect($this->configuration->ldapHost,
+ $this->configuration->ldapPort);
+ $bindStatus = $this->bind();
+ $error = $this->ldap->isResource($this->ldapConnectionRes) ?
+ $this->ldap->errno($this->ldapConnectionRes) : -1;
+ }
+ if($bindStatus === true) {
+ return $bindStatus;
+ }
+ } catch (\OC\ServerNotAvailableException $e) {
+ if(trim($this->configuration->ldapBackupHost) === "") {
+ throw $e;
+ }
}
//if LDAP server is not reachable, try the Backup (Replica!) Server
- if((!$bindStatus && ($error !== 0))
+ if( $error !== 0
|| $this->configuration->ldapOverrideMainServer
- || $this->getFromCache('overrideMainServer')) {
- $this->doConnect($this->configuration->ldapBackupHost,
- $this->configuration->ldapBackupPort);
- $bindStatus = $this->bind();
- if(!$bindStatus && $error === -1) {
- //when bind to backup server succeeded and failed to main server,
- //skip contacting him until next cache refresh
- $this->writeToCache('overrideMainServer', true);
- }
+ || $this->getFromCache('overrideMainServer'))
+ {
+ $this->doConnect($this->configuration->ldapBackupHost,
+ $this->configuration->ldapBackupPort);
+ $bindStatus = $this->bind();
+ if($bindStatus && $error === -1) {
+ //when bind to backup server succeeded and failed to main server,
+ //skip contacting him until next cache refresh
+ $this->writeToCache('overrideMainServer', true);
+ }
}
return $bindStatus;
}
diff --git a/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php b/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php
new file mode 100644
index 00000000000..95cb4b8f270
--- /dev/null
+++ b/apps/user_ldap/tests/integration/lib/integrationtestbackupserver.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\user_ldap\tests\integration\lib;
+
+use OCA\user_ldap\lib\user\Manager as LDAPUserManager;
+use OCA\user_ldap\tests\integration\AbstractIntegrationTest;
+use OCA\User_LDAP\Mapping\UserMapping;
+use OCA\user_ldap\USER_LDAP;
+
+require_once __DIR__ . '/../../../../../lib/base.php';
+
+class IntegrationBackupServer extends AbstractIntegrationTest {
+ /** @var UserMapping */
+ protected $mapping;
+
+ /** @var USER_LDAP */
+ protected $backend;
+
+ /**
+ * sets up the LDAP configuration to be used for the test
+ */
+ protected function initConnection() {
+ parent::initConnection();
+ $originalHost = $this->connection->ldapHost;
+ $originalPort = $this->connection->ldapPort;
+ $this->connection->setConfiguration([
+ 'ldapHost' => 'qwertz.uiop',
+ 'ldapPort' => '32123',
+ 'ldap_backup_host' => $originalHost,
+ 'ldap_backup_port' => $originalPort,
+ ]);
+ }
+
+ /**
+ * tests that a backup connection is being used when the main LDAP server
+ * is offline
+ *
+ * Beware: after starting docker, the LDAP host might not be ready yet, thus
+ * causing a false positive. Retry in that case… or increase the sleep time
+ * in run-test.sh
+ *
+ * @return bool
+ */
+ protected function case1() {
+ try {
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * ensures that an exception is thrown if LDAP main server and LDAP backup
+ * server are not available
+ *
+ * @return bool
+ */
+ protected function case2() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ try {
+ $this->connection->setConfiguration([
+ 'ldap_backup_host' => 'qwertz.uiop',
+ 'ldap_backup_port' => '32123',
+ ]);
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * ensures that an exception is thrown if main LDAP server is down and a
+ * backup server is not given
+ *
+ * @return bool
+ */
+ protected function case3() {
+ // reset possible LDAP connection
+ $this->initConnection();
+ try {
+ $this->connection->setConfiguration([
+ 'ldap_backup_host' => '',
+ 'ldap_backup_port' => '',
+ ]);
+ $this->connection->getConnectionResource();
+ } catch (\OC\ServerNotAvailableException $e) {
+ return true;
+ }
+ return false;
+ }
+}
+
+require_once(__DIR__ . '/../setup-scripts/config.php');
+$test = new IntegrationBackupServer($host, $port, $adn, $apwd, $bdn);
+$test->init();
+$test->run();
diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php
index 8633727ee04..69fa018d0e6 100644
--- a/build/integration/features/bootstrap/FeatureContext.php
+++ b/build/integration/features/bootstrap/FeatureContext.php
@@ -24,12 +24,18 @@ class FeatureContext implements Context, SnippetAcceptingContext {
/** @var int */
private $apiVersion = 1;
+ /** @var int */
+ private $sharingApiVersion = 1;
+
/** @var SimpleXMLElement */
private $lastShareData = null;
/** @var array */
private $createdUsers = [];
+ /** @var array */
+ private $createdGroups = [];
+
public function __construct($baseUrl, $admin, $regular_user_password) {
// Initialize your context here
@@ -354,23 +360,35 @@ class FeatureContext implements Context, SnippetAcceptingContext {
}
public function createUser($user) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
$this->creatingTheUser($user);
$this->userExists($user);
+ $this->currentUser = $previous_user;
}
public function deleteUser($user) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
$this->deletingTheUser($user);
$this->userDoesNotExist($user);
+ $this->currentUser = $previous_user;
}
public function createGroup($group) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
$this->creatingTheGroup($group);
$this->groupExists($group);
+ $this->currentUser = $previous_user;
}
public function deleteGroup($group) {
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
$this->deletingTheGroup($group);
$this->groupDoesNotExist($group);
+ $this->currentUser = $previous_user;
}
public function creatingTheUser($user) {
@@ -406,6 +424,7 @@ class FeatureContext implements Context, SnippetAcceptingContext {
];
$this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ $this->createdGroups[$group] = $group;
}
/**
@@ -589,7 +608,7 @@ class FeatureContext implements Context, SnippetAcceptingContext {
*/
public function addingExpirationDate() {
$share_id = $this->lastShareData->data[0]->id;
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->apiVersion}/shares/$share_id";
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
$client = new Client();
$options = [];
if ($this->currentUser === 'admin') {
@@ -603,6 +622,157 @@ class FeatureContext implements Context, SnippetAcceptingContext {
PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
}
+ public function createShare($user,
+ $path = null,
+ $shareType = null,
+ $shareWith = null,
+ $publicUpload = null,
+ $password = null,
+ $permissions = null){
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares";
+ $client = new Client();
+ $options = [];
+
+ if ($user === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user, $this->regularUser];
+ }
+ $fd = [];
+ if (!is_null($path)){
+ $fd['path'] = $path;
+ }
+ if (!is_null($shareType)){
+ $fd['shareType'] = $shareType;
+ }
+ if (!is_null($shareWith)){
+ $fd['shareWith'] = $shareWith;
+ }
+ if (!is_null($publicUpload)){
+ $fd['publicUpload'] = $publicUpload;
+ }
+ if (!is_null($password)){
+ $fd['password'] = $password;
+ }
+ if (!is_null($permissions)){
+ $fd['permissions'] = $permissions;
+ }
+
+ $options['body'] = $fd;
+
+ try {
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ $this->lastShareData = $this->response->xml();
+ } catch (\GuzzleHttp\Exception\ClientException $ex) {
+ $this->response = $ex->getResponse();
+ }
+
+ }
+
+ public function isFieldInResponse($field, $content_expected){
+ $data = $this->response->xml()->data[0];
+ foreach($data as $element) {
+ if ($element->$field == $content_expected){
+ return True;
+ }
+ }
+ return False;
+ }
+
+ /**
+ * @Then /^File "([^"]*)" should be included in the response$/
+ */
+ public function checkSharedFileInResponse($filename){
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('file_target', "/$filename"));
+ }
+
+ /**
+ * @Then /^File "([^"]*)" should not be included in the response$/
+ */
+ public function checkSharedFileNotInResponse($filename){
+ PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('file_target', "/$filename"));
+ }
+
+ /**
+ * @Then /^User "([^"]*)" should be included in the response$/
+ */
+ public function checkSharedUserInResponse($user){
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('share_with', "$user"));
+ }
+
+ /**
+ * @Then /^User "([^"]*)" should not be included in the response$/
+ */
+ public function checkSharedUserNotInResponse($user){
+ PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('share_with', "$user"));
+ }
+
+ public function isUserInSharedData($user){
+ $data = $this->response->xml()->data[0];
+ foreach($data as $element) {
+ if ($element->share_with == $user){
+ return True;
+ }
+ }
+ return False;
+ }
+
+ /**
+ * @Given /^file "([^"]*)" from user "([^"]*)" is shared with user "([^"]*)"$/
+ */
+ public function assureFileIsShared($filepath, $user1, $user2){
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
+ $client = new Client();
+ $options = [];
+ if ($user1 === 'admin') {
+ $options['auth'] = $this->adminUser;
+ } else {
+ $options['auth'] = [$user1, $this->regularUser];
+ }
+ $this->response = $client->get($fullUrl, $options);
+ if ($this->isUserInSharedData($user2)){
+ return;
+ } else {
+ $this->createShare($user1, $filepath, 0, $user2, null, null, null);
+ }
+ $this->response = $client->get($fullUrl, $options);
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isUserInSharedData($user2));
+ }
+
+ /**
+ * @When /^Deleting last share$/
+ */
+ public function deletingLastShare(){
+ $share_id = $this->lastShareData->data[0]->id;
+ $url = "/apps/files_sharing/api/v{$this->apiVersion}/shares/$share_id";
+ $this->sendingToWith("DELETE", $url, null);
+ }
+
+ public static function removeFile($path, $filename){
+ if (file_exists("$path" . "$filename")) {
+ unlink("$path" . "$filename");
+ }
+ }
+
+ /**
+ * @BeforeSuite
+ */
+ public static function addFilesToSkeleton(){
+ for ($i=0; $i<5; $i++){
+ file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "ownCloud test text file\n");
+ }
+
+ }
+
+ /**
+ * @AfterSuite
+ */
+ public static function removeFilesFromSkeleton(){
+ for ($i=0; $i<5; $i++){
+ self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt");
+ }
+ }
+
/**
* @BeforeScenario
* @AfterScenario
@@ -614,4 +784,15 @@ class FeatureContext implements Context, SnippetAcceptingContext {
}
}
+
+ /**
+ * @BeforeScenario
+ * @AfterScenario
+ */
+ public function cleanupGroups()
+ {
+ foreach($this->createdGroups as $group) {
+ $this->deleteGroup($group);
+ }
+ }
}
diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature
index 91050e82c28..2a3e8e07fc4 100644
--- a/build/integration/features/provisioning-v1.feature
+++ b/build/integration/features/provisioning-v1.feature
@@ -159,6 +159,14 @@ Feature: provisioning
And the OCS status code should be "100"
And the HTTP status code should be "200"
+ Scenario: removing a user from a group which doesn't exists
+ Given As an "admin"
+ And user "brand-new-user" exists
+ And group "not-group" does not exist
+ When sending "DELETE" to "/cloud/users/brand-new-user/groups" with
+ | groupid | not-group |
+ Then the OCS status code should be "102"
+
Scenario: removing a user from a group
Given As an "admin"
And user "brand-new-user" exists
diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature
index abf9fe1c8d8..b73fb39d5da 100644
--- a/build/integration/features/sharing-v1.feature
+++ b/build/integration/features/sharing-v1.feature
@@ -58,3 +58,72 @@ Feature: sharing
And the HTTP status code should be "200"
And Public shared file "welcome.txt" with password "publicpw" can be downloaded
+ Scenario: getting all shares of a user using that user
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And As an "user0"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And File "textfile0.txt" should be included in the response
+
+ Scenario: getting all shares of a user using another user
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And As an "admin"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And File "textfile0.txt" should not be included in the response
+
+ Scenario: getting all shares of a file
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And file "textfile0.txt" from user "user0" is shared with user "user2"
+ And As an "user0"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?path=textfile0.txt"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And User "user1" should be included in the response
+ And User "user2" should be included in the response
+ And User "user3" should not be included in the response
+
+ Scenario: getting all shares of a file with reshares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And file "textfile0.txt" from user "user1" is shared with user "user2"
+ And As an "user0"
+ When sending "GET" to "/apps/files_sharing/api/v1/shares?reshares=true&path=textfile0.txt"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And User "user1" should be included in the response
+ And User "user2" should be included in the response
+ And User "user3" should not be included in the response
+
+ Scenario: delete a share
+ Given user "user0" exists
+ And user "user1" exists
+ And file "textfile0.txt" from user "user0" is shared with user "user1"
+ And As an "user0"
+ When Deleting last share
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/command/app/checkcode.php b/core/command/app/checkcode.php
index a04f4bb5e03..e186d458c01 100644
--- a/core/command/app/checkcode.php
+++ b/core/command/app/checkcode.php
@@ -131,6 +131,10 @@ class CheckCode extends Command {
}
});
+ $infoChecker->listen('InfoChecker', 'duplicateRequirement', function($minMax) use ($output) {
+ $output->writeln("<error>Duplicate $minMax ownCloud version requirement found</error>");
+ });
+
$infoChecker->listen('InfoChecker', 'differentVersions', function($versionFile, $infoXML) use ($output) {
$output->writeln("<error>Different versions provided (appinfo/version: $versionFile - appinfo/info.xml: $infoXML)</error>");
});
diff --git a/core/img/favicon-mask.svg b/core/img/favicon-mask.svg
new file mode 100644
index 00000000000..24dff74ef89
--- /dev/null
+++ b/core/img/favicon-mask.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xml:space="preserve" height="16" width="16" enable-background="new 0 0 595.275 311.111" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 16 15.999999"><g transform="matrix(.125 0 0 .125 0 14)"><path d="m20-112c-11.08 0-20 8.92-20 20v88c0 11.08 8.92 20 20 20h88c11.08 0 20-8.92 20-20v-88c0-11.08-8.92-20-20-20h-88zm38.328 29.125c8.932 0 16.156 7.2089 16.156 16.141 0 1.2073-0.14055 2.3846-0.39062 3.5156-3.0889-1.4114-6.51-2.2188-10.125-2.2188-7.389 0-14 3.3102-18.484 8.5-2.0669-2.7134-3.2969-6.1152-3.2969-9.7969 0-8.932 7.2089-16.141 16.141-16.141zm-21.078 7.4688c1.7281 0 3.325 0.4979 4.6562 1.3906-0.98881 2.2266-1.5625 4.6906-1.5625 7.2812-0.000001 0.481 0.0253 0.96598 0.0625 1.4375-0.3285-0.02-0.63611-0.03125-0.96875-0.03125-3.4468 0-6.6932 0.9166-9.5 2.5-0.68798-1.2188-1.0781-2.6502-1.0781-4.1562 0-4.6514 3.7392-8.4219 8.3906-8.4219zm39.828 5.7969c8.4592 0 15.31 6.5054 16.016 14.781-2.7381 0.1835-5.3124 0.95225-7.625 2.1562-2.2297-4.0909-5.6126-7.4636-9.6875-9.7188 0.34758-1.3914 0.53125-2.8444 0.53125-4.3438 0-0.9636-0.10364-1.8898-0.25-2.8125 0.33833-0.0212 0.67198-0.0625 1.0156-0.0625zm-13.109 6.0156c12.498 0 22.609 10.11 22.609 22.609 0 12.498-10.11 22.609-22.609 22.609s-22.609-10.111-22.609-22.609c0-12.499 10.111-22.609 22.609-22.609zm-24.531 0.09375c0.41458 0 0.827 0.0345 1.2344 0.0625 0.5497 2.9515 1.8386 5.6671 3.6406 7.9219-3.0103 4.063-4.7813 9.0916-4.7813 14.531 0.000001 1.1378 0.06803 2.2628 0.21875 3.3594-0.48017-0.0664-0.95496-0.125-1.4531-0.125-4.1218 0-7.6921 2.3232-9.4688 5.75-4.2144-3.202-6.9375-8.2451-6.9375-13.953 0-9.6963 7.8507-17.547 17.547-17.547zm54.953 10.453c9.6963 0 17.547 7.8038 17.547 17.5-0.00001 9.6964-7.8507 17.547-17.547 17.547-5.1793 0-9.8376-2.2339-13.047-5.7969 4.3686-4.417 7.0625-10.492 7.0625-17.188 0-3.5761-0.75792-6.9842-2.1406-10.047 2.435-1.2747 5.1808-2.0156 8.125-2.0156zm-74.219 2.3125h0.01563c0.15552 0.0017 0.31393 0.02738 0.46875 0.03125-0.38539 1.5224-0.60937 3.1094-0.60937 4.75 0 6.4567 3.1766 12.183 8.0469 15.703-0.31205 1.0019-0.46875 2.0524-0.46875 3.1562 0 2.1267 0.62812 4.1265 1.7031 5.7969-2.6015 1.7904-5.7566 2.8594-9.1562 2.8594-8.9316 0-16.172-7.2555-16.172-16.187 0-8.9267 7.2462-16.102 16.172-16.109zm94.969 13.859c4.8964 0 8.8594 3.9786 8.8594 8.875 0 4.8965-3.963 8.8281-8.8594 8.8281-2.6882 0-5.0703-1.1975-6.6875-3.0781 3.2872-3.4734 5.3281-8.1468 5.3281-13.297 0-0.40912-0.0217-0.80036-0.0469-1.2031 0.45554-0.0724 0.92976-0.125 1.4062-0.125zm-76.844 0.95312c0.6229 0 1.2103 0.0663 1.7969 0.1875 1.0023 4.5568 3.2654 8.6601 6.4219 11.875-1.2936 3.2941-4.4657 5.6406-8.2187 5.6406-4.8962 0-8.8438-3.9788-8.8438-8.875s3.9476-8.8281 8.8438-8.8281z"/></g></svg>
diff --git a/core/img/favicon.ico b/core/img/favicon.ico
new file mode 100644
index 00000000000..96bee5656a9
--- /dev/null
+++ b/core/img/favicon.ico
Binary files differ
diff --git a/core/l10n/cs_CZ.js b/core/l10n/cs_CZ.js
index a1680a1dea3..ff173b8e06e 100644
--- a/core/l10n/cs_CZ.js
+++ b/core/l10n/cs_CZ.js
@@ -114,6 +114,8 @@ OC.L10N.register(
"No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
"/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
"Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
"Error occurred while checking server setup" : "Při ověřování nastavení serveru došlo k chybě",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP hlavička \"{header}\" není nakonfigurována ve shodě s \"{expected}\". To značí možné ohrožení bezpečnosti a soukromí a je doporučeno toto nastavení upravit.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP hlavička \"Strict-Transport-Security\" není nakonfigurována na minimum \"{seconds}\" sekund. Pro vylepšení bezpečnosti doporučujeme povolit HSTS dle popisu v našich <a href=\"{docUrl}\">bezpečnostních tipech</a>.",
diff --git a/core/l10n/cs_CZ.json b/core/l10n/cs_CZ.json
index bff75145c2c..a13624e2c18 100644
--- a/core/l10n/cs_CZ.json
+++ b/core/l10n/cs_CZ.json
@@ -112,6 +112,8 @@
"No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Nebyla nakonfigurována paměťová cache. Pro zlepšení výkonu a dostupnosti ji prosím nakonfigurujte. Další informace lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
"/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "PHP nemá práva pro čtení v /dev/urandom, to je ale z bezpečnostních důvodů velmi doporučováno. Více informací lze nalézt v <a href=\"{docLink}\">dokumentaci</a>.",
"Your PHP version ({version}) is no longer <a href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "Vaše verze PHP ({version}) již není <a href=\"{phpLink}\">podporována</a>. Doporučujeme aktualizovat na poslední verzi PHP pro využití vylepšení výkonu a bezpečnosti.",
+ "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a href=\"{docLink}\">documentation</a>." : "Konfigurace hlaviček zpětné proxy není správná nebo přistupujete na ownCloud přes důvěryhodnou proxy. Pokud přistupujete na ownCloud přes nedůvěryhodnou proxy je toto považováno za bezpečnostní problém který může útočníkovi umožnit záměnu IP adresy viděné ownCloudem. Více informací lze nalézt v naší <a href=\"{docLink}\">dokumentaci</a>.",
+ "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached je nakonfigurován jako distribuovaná cache, ale je nainstalován nesprávný PHP modul \"memcache\". \\OC\\Memcache\\Memcached podporuje pouze \"memcached\" a ne \"memcache\". Projděte si <a href=\"{wikiLink}\">memcached wiki popisující oba moduly</a>.",
"Error occurred while checking server setup" : "Při ověřování nastavení serveru došlo k chybě",
"The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "HTTP hlavička \"{header}\" není nakonfigurována ve shodě s \"{expected}\". To značí možné ohrožení bezpečnosti a soukromí a je doporučeno toto nastavení upravit.",
"The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "HTTP hlavička \"Strict-Transport-Security\" není nakonfigurována na minimum \"{seconds}\" sekund. Pro vylepšení bezpečnosti doporučujeme povolit HSTS dle popisu v našich <a href=\"{docUrl}\">bezpečnostních tipech</a>.",
diff --git a/core/l10n/es.js b/core/l10n/es.js
index 4b7243ef6ea..774ff7ef9d2 100644
--- a/core/l10n/es.js
+++ b/core/l10n/es.js
@@ -256,7 +256,7 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Por favor reintente nuevamente o contáctese con su administrador.",
"Log in" : "Ingresar",
"Wrong password. Reset it?" : "Contraseña incorrecta. ¿Restablecerla?",
- "Stay logged in" : "Permanecer autentificado",
+ "Stay logged in" : "Permanecer autenticado",
"Alternative Logins" : "Inicios de sesión alternativos",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
diff --git a/core/l10n/es.json b/core/l10n/es.json
index d6a0bd329b2..850e82d4195 100644
--- a/core/l10n/es.json
+++ b/core/l10n/es.json
@@ -254,7 +254,7 @@
"Please try again or contact your administrator." : "Por favor reintente nuevamente o contáctese con su administrador.",
"Log in" : "Ingresar",
"Wrong password. Reset it?" : "Contraseña incorrecta. ¿Restablecerla?",
- "Stay logged in" : "Permanecer autentificado",
+ "Stay logged in" : "Permanecer autenticado",
"Alternative Logins" : "Inicios de sesión alternativos",
"This ownCloud instance is currently in single user mode." : "Esta instalación de ownCloud se encuentra en modo de usuario único.",
"This means only administrators can use the instance." : "Esto quiere decir que solo un administrador puede usarla.",
diff --git a/core/l10n/hu_HU.js b/core/l10n/hu_HU.js
index 6e10778b821..52c13fd96cd 100644
--- a/core/l10n/hu_HU.js
+++ b/core/l10n/hu_HU.js
@@ -6,14 +6,20 @@ OC.L10N.register(
"Turned on maintenance mode" : "A karbantartási mód bekapcsolva",
"Turned off maintenance mode" : "A karbantartási mód kikapcsolva",
"Maintenance mode is kept active" : "Karbantartási mód aktiválva marad",
+ "Updating database schema" : "Adatbázis séma frissítése",
"Updated database" : "Az adatbázis frissítése megtörtént",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Annak ellenőrzése, hogy az adatbázis sémát lehet-e frissíteni (ez hosszabb ideig is eltarthat az adatbázis méretétől függően)",
"Checked database schema update" : "Az adatbázis séma frissítését ellenőriztük",
+ "Checking updates of apps" : "Alkalmazások frissítésének ellenőrzése",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Annak ellenőrzése, hogy a(z) %s adatbázis sémáját lehet-e frissíteni (ez hosszabb ideig is eltarthat az adatbázis méretétől függően)",
"Checked database schema update for apps" : "Az adatbázis séma frissítését ellenőriztük az alkalmazásokra vontakozóan",
"Updated \"%s\" to %s" : "Frissítettük \"%s\"-t erre: %s",
"Repair warning: " : "Javítás figyelmeztetés:",
"Repair error: " : "Javítás hiba:",
"Set log level to debug - current level: \"%s\"" : "Hibakeresési naplózási szint beállítása - jelenlegi szint: \"%s\"",
"Reset log level to \"%s\"" : "Naplózási szint visszaállítása \"%s\"-re",
+ "%s (3rdparty)" : "%s (harmadik fél által)",
+ "%s (incompatible)" : "%s (nem kompatibilis)",
"Following apps have been disabled: %s" : "A következő applikációk lettek tiltva: %s",
"Already up to date" : "Már a legfrissebb változat",
"File is too big" : "A fájl túl nagy",
@@ -121,7 +127,7 @@ OC.L10N.register(
"Error while unsharing" : "Nem sikerült visszavonni a megosztást",
"Error while changing permissions" : "Nem sikerült módosítani a jogosultságokat",
"Error setting expiration date" : "Nem sikerült a lejárati időt beállítani",
- "The public link will expire no later than {days} days after it is created" : "A nyilvános link érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
+ "The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
"Set expiration date" : "Legyen lejárati idő",
"Expiration" : "Lejárat",
"Expiration date" : "A lejárati idő",
@@ -171,6 +177,7 @@ OC.L10N.register(
"Hello {name}" : "Hello {name}",
"_download %n file_::_download %n files_" : ["%n fájl letöltése","%n fájl letöltése"],
"{version} is available. Get more information on how to update." : "{version} rendelkezésre áll. További információ a frissítéshez.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "A frissítés folyamatban van, az oldal elhagyása néhány környezetben lehet, hogy megszakítja a folyamatot.",
"Updating {productName} to version {version}, this may take a while." : " {productName} frissítése zajlik erre a verzióra: {version}. Ez eltarthat egy darabig.",
"An error occurred." : "Hiba történt.",
"Please reload the page." : "Kérjük frissítse az oldalt!",
@@ -245,6 +252,7 @@ OC.L10N.register(
"Finishing …" : "Befejezés ...",
"Need help?" : "Segítségre van szüksége?",
"See the documentation" : "Nézze meg a dokumentációt",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Üdvözöljük!<br><br>\n\nÉrtesítjük, hogy %s megosztotta Önnel ezt az állományt: <strong>%s</strong><br>\n<a href=\"%s\">Itt lehet megnézni!</a><br><br>",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Az alkalmazás megfelelő működéséhez JavaScript szükséges. Kérem {linkstart}engedélyezze a JavaScript-et{linkend} és frissítse a lapot.",
"Log out" : "Kilépés",
"Search" : "Keresés",
@@ -254,8 +262,8 @@ OC.L10N.register(
"Please try again or contact your administrator." : "Kérem próbálja újra, vagy vegye fel a kapcsolatot a rendszergazdával.",
"Log in" : "Bejelentkezés",
"Wrong password. Reset it?" : "Hibás jelszó. Visszaállítja?",
+ "Stay logged in" : "Maradjon bejelentkezve",
"Alternative Logins" : "Alternatív bejelentkezés",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Üdvözöljük!<br><br>\n\nÉrtesítjük, hogy %s megosztotta Önnel ezt az állományt: <strong>%s</strong><br>\n<a href=\"%s\">Itt lehet megnézni!</a><br><br>",
"This ownCloud instance is currently in single user mode." : "Ez az ownCloud szolgáltatás jelenleg egyfelhasználós üzemmódban működik.",
"This means only administrators can use the instance." : "Ez azt jelenti, hogy csak az adminisztrátor használhatja ezt a példányt",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ha ez az üzenet ismételten vagy indokolatlanul megjelenik, akkor keresse a rendszergazda segítségét!",
diff --git a/core/l10n/hu_HU.json b/core/l10n/hu_HU.json
index 2629c04d507..6c48c51b6d3 100644
--- a/core/l10n/hu_HU.json
+++ b/core/l10n/hu_HU.json
@@ -4,14 +4,20 @@
"Turned on maintenance mode" : "A karbantartási mód bekapcsolva",
"Turned off maintenance mode" : "A karbantartási mód kikapcsolva",
"Maintenance mode is kept active" : "Karbantartási mód aktiválva marad",
+ "Updating database schema" : "Adatbázis séma frissítése",
"Updated database" : "Az adatbázis frissítése megtörtént",
+ "Checking whether the database schema can be updated (this can take a long time depending on the database size)" : "Annak ellenőrzése, hogy az adatbázis sémát lehet-e frissíteni (ez hosszabb ideig is eltarthat az adatbázis méretétől függően)",
"Checked database schema update" : "Az adatbázis séma frissítését ellenőriztük",
+ "Checking updates of apps" : "Alkalmazások frissítésének ellenőrzése",
+ "Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)" : "Annak ellenőrzése, hogy a(z) %s adatbázis sémáját lehet-e frissíteni (ez hosszabb ideig is eltarthat az adatbázis méretétől függően)",
"Checked database schema update for apps" : "Az adatbázis séma frissítését ellenőriztük az alkalmazásokra vontakozóan",
"Updated \"%s\" to %s" : "Frissítettük \"%s\"-t erre: %s",
"Repair warning: " : "Javítás figyelmeztetés:",
"Repair error: " : "Javítás hiba:",
"Set log level to debug - current level: \"%s\"" : "Hibakeresési naplózási szint beállítása - jelenlegi szint: \"%s\"",
"Reset log level to \"%s\"" : "Naplózási szint visszaállítása \"%s\"-re",
+ "%s (3rdparty)" : "%s (harmadik fél által)",
+ "%s (incompatible)" : "%s (nem kompatibilis)",
"Following apps have been disabled: %s" : "A következő applikációk lettek tiltva: %s",
"Already up to date" : "Már a legfrissebb változat",
"File is too big" : "A fájl túl nagy",
@@ -119,7 +125,7 @@
"Error while unsharing" : "Nem sikerült visszavonni a megosztást",
"Error while changing permissions" : "Nem sikerült módosítani a jogosultságokat",
"Error setting expiration date" : "Nem sikerült a lejárati időt beállítani",
- "The public link will expire no later than {days} days after it is created" : "A nyilvános link érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
+ "The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le",
"Set expiration date" : "Legyen lejárati idő",
"Expiration" : "Lejárat",
"Expiration date" : "A lejárati idő",
@@ -169,6 +175,7 @@
"Hello {name}" : "Hello {name}",
"_download %n file_::_download %n files_" : ["%n fájl letöltése","%n fájl letöltése"],
"{version} is available. Get more information on how to update." : "{version} rendelkezésre áll. További információ a frissítéshez.",
+ "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "A frissítés folyamatban van, az oldal elhagyása néhány környezetben lehet, hogy megszakítja a folyamatot.",
"Updating {productName} to version {version}, this may take a while." : " {productName} frissítése zajlik erre a verzióra: {version}. Ez eltarthat egy darabig.",
"An error occurred." : "Hiba történt.",
"Please reload the page." : "Kérjük frissítse az oldalt!",
@@ -243,6 +250,7 @@
"Finishing …" : "Befejezés ...",
"Need help?" : "Segítségre van szüksége?",
"See the documentation" : "Nézze meg a dokumentációt",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Üdvözöljük!<br><br>\n\nÉrtesítjük, hogy %s megosztotta Önnel ezt az állományt: <strong>%s</strong><br>\n<a href=\"%s\">Itt lehet megnézni!</a><br><br>",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Az alkalmazás megfelelő működéséhez JavaScript szükséges. Kérem {linkstart}engedélyezze a JavaScript-et{linkend} és frissítse a lapot.",
"Log out" : "Kilépés",
"Search" : "Keresés",
@@ -252,8 +260,8 @@
"Please try again or contact your administrator." : "Kérem próbálja újra, vagy vegye fel a kapcsolatot a rendszergazdával.",
"Log in" : "Bejelentkezés",
"Wrong password. Reset it?" : "Hibás jelszó. Visszaállítja?",
+ "Stay logged in" : "Maradjon bejelentkezve",
"Alternative Logins" : "Alternatív bejelentkezés",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Üdvözöljük!<br><br>\n\nÉrtesítjük, hogy %s megosztotta Önnel ezt az állományt: <strong>%s</strong><br>\n<a href=\"%s\">Itt lehet megnézni!</a><br><br>",
"This ownCloud instance is currently in single user mode." : "Ez az ownCloud szolgáltatás jelenleg egyfelhasználós üzemmódban működik.",
"This means only administrators can use the instance." : "Ez azt jelenti, hogy csak az adminisztrátor használhatja ezt a példányt",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Ha ez az üzenet ismételten vagy indokolatlanul megjelenik, akkor keresse a rendszergazda segítségét!",
diff --git a/core/l10n/nl.js b/core/l10n/nl.js
index 5391e2b9966..90dfb6c66a7 100644
--- a/core/l10n/nl.js
+++ b/core/l10n/nl.js
@@ -252,6 +252,7 @@ OC.L10N.register(
"Finishing …" : "Afronden ...",
"Need help?" : "Hulp nodig?",
"See the documentation" : "Zie de documentatie",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Hallo,<br><br>%s deelt <strong>%s</strong> met u.<br><a href=\"%s\">Bekijk hier!</a><br><br>",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Deze applicatie heeft JavaScript nodig. {linkstart}Activeer JavaScript{linkend} en ververs deze pagina.",
"Log out" : "Afmelden",
"Search" : "Zoeken",
@@ -263,7 +264,6 @@ OC.L10N.register(
"Wrong password. Reset it?" : "Onjuist wachtwoord. Resetten?",
"Stay logged in" : "Ingelogd blijven",
"Alternative Logins" : "Alternatieve inlogs",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Hallo,<br><br>%s deelt <strong>%s</strong> met u.<br><a href=\"%s\">Bekijk hier!</a><br><br>",
"This ownCloud instance is currently in single user mode." : "Deze ownCloud werkt momenteel in enkele gebruiker modus.",
"This means only administrators can use the instance." : "Dat betekent dat alleen beheerders deze installatie kunnen gebruiken.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Neem contact op met uw systeembeheerder als deze melding aanhoudt of onverwacht verscheen.",
diff --git a/core/l10n/nl.json b/core/l10n/nl.json
index f0fa15c88af..a65c6f7c001 100644
--- a/core/l10n/nl.json
+++ b/core/l10n/nl.json
@@ -250,6 +250,7 @@
"Finishing …" : "Afronden ...",
"Need help?" : "Hulp nodig?",
"See the documentation" : "Zie de documentatie",
+ "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Hallo,<br><br>%s deelt <strong>%s</strong> met u.<br><a href=\"%s\">Bekijk hier!</a><br><br>",
"This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "Deze applicatie heeft JavaScript nodig. {linkstart}Activeer JavaScript{linkend} en ververs deze pagina.",
"Log out" : "Afmelden",
"Search" : "Zoeken",
@@ -261,7 +262,6 @@
"Wrong password. Reset it?" : "Onjuist wachtwoord. Resetten?",
"Stay logged in" : "Ingelogd blijven",
"Alternative Logins" : "Alternatieve inlogs",
- "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "Hallo,<br><br>%s deelt <strong>%s</strong> met u.<br><a href=\"%s\">Bekijk hier!</a><br><br>",
"This ownCloud instance is currently in single user mode." : "Deze ownCloud werkt momenteel in enkele gebruiker modus.",
"This means only administrators can use the instance." : "Dat betekent dat alleen beheerders deze installatie kunnen gebruiken.",
"Contact your system administrator if this message persists or appeared unexpectedly." : "Neem contact op met uw systeembeheerder als deze melding aanhoudt of onverwacht verscheen.",
diff --git a/core/shipped.json b/core/shipped.json
index b6f08a8b96d..49a649f3c9e 100644
--- a/core/shipped.json
+++ b/core/shipped.json
@@ -8,6 +8,7 @@
"external",
"files",
"files_antivirus",
+ "files_drop",
"files_external",
"files_ldap_home",
"files_locking",
diff --git a/core/templates/layout.base.php b/core/templates/layout.base.php
index b01820a05bb..b12121b6088 100644
--- a/core/templates/layout.base.php
+++ b/core/templates/layout.base.php
@@ -11,8 +11,9 @@
<meta name="referrer" content="never">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<meta name="theme-color" content="<?php p($theme->getMailHeaderColor()); ?>">
- <link rel="shortcut icon" type="image/png" href="<?php print_unescaped(image_path('', 'favicon.png')); ?>">
+ <link rel="shortcut icon" href="<?php print_unescaped(image_path('', 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>">
+ <link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path('', 'favicon-mask.svg')); ?>" color="#1d2d44">
<?php foreach ($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="screen">
<?php endforeach; ?>
diff --git a/core/templates/layout.guest.php b/core/templates/layout.guest.php
index 56b762d3266..d5e9680eda2 100644
--- a/core/templates/layout.guest.php
+++ b/core/templates/layout.guest.php
@@ -12,8 +12,9 @@
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-itunes-app" content="app-id=<?php p($theme->getiTunesAppId()); ?>">
<meta name="theme-color" content="<?php p($theme->getMailHeaderColor()); ?>">
- <link rel="shortcut icon" type="image/png" href="<?php print_unescaped(image_path('', 'favicon.png')); ?>">
+ <link rel="shortcut icon" href="<?php print_unescaped(image_path('', 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>">
+ <link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path('', 'favicon-mask.svg')); ?>" color="#1d2d44">
<?php foreach($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="screen">
<?php endforeach; ?>
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index fcdebc03c97..5e13d9329f3 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -23,8 +23,9 @@
<meta name="apple-mobile-web-app-title" content="<?php p((!empty($_['application']) && $_['appid']!='files')? $_['application']:'ownCloud'); ?>">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="<?php p($theme->getMailHeaderColor()); ?>">
- <link rel="shortcut icon" type="image/png" href="<?php print_unescaped(image_path($_['appid'], 'favicon.png')); ?>">
+ <link rel="shortcut icon" href="<?php print_unescaped(image_path($_['appid'], 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path($_['appid'], 'favicon-touch.png')); ?>">
+ <link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path($_['appid'], 'favicon-mask.svg')); ?>" color="#1d2d44">
<?php foreach($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="screen">
<?php endforeach; ?>
diff --git a/core/templates/update.admin.php b/core/templates/update.admin.php
index fbd3025f2e0..ae88350bdc5 100644
--- a/core/templates/update.admin.php
+++ b/core/templates/update.admin.php
@@ -1,9 +1,9 @@
<div class="update" data-productname="<?php p($_['productName']) ?>" data-version="<?php p($_['version']) ?>">
<div class="updateOverview">
<?php if ($_['isAppsOnlyUpgrade']) { ?>
- <h2 class="title bold"><?php p($l->t('App update required')); ?></h2>
+ <h2 class="title"><?php p($l->t('App update required')); ?></h2>
<?php } else { ?>
- <h2 class="title bold"><?php p($l->t('%s will be updated to version %s',
+ <h2 class="title"><?php p($l->t('%s will be updated to version %s',
array($_['productName'], $_['version']))); ?></h2>
<?php } ?>
<?php if (!empty($_['appsToUpgrade'])) { ?>
diff --git a/cron.php b/cron.php
index 3caa50a94a8..008a02b6d3e 100644
--- a/cron.php
+++ b/cron.php
@@ -132,7 +132,9 @@ try {
$jobList = \OC::$server->getJobList();
$jobs = $jobList->getAll();
foreach ($jobs as $job) {
+ $logger->debug('Run job with ID ' . $job->getId(), ['app' => 'cron']);
$job->execute($jobList, $logger);
+ $logger->debug('Finished job with ID ' . $job->getId(), ['app' => 'cron']);
}
// unlock the file
diff --git a/lib/autoloader.php b/lib/autoloader.php
index b91681946a5..f0fbd9e9f27 100644
--- a/lib/autoloader.php
+++ b/lib/autoloader.php
@@ -100,14 +100,30 @@ class Autoloader {
$paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
}
} elseif (strpos($class, 'OC_') === 0) {
- // first check for legacy classes if underscores are used
- $paths[] = 'private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
- $paths[] = 'private/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
+ $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
+ $paths[] = \OC::$SERVERROOT . '/lib/private/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
} elseif (strpos($class, 'OC\\') === 0) {
- $paths[] = 'private/' . strtolower(str_replace('\\', '/', substr($class, 3)) . '.php');
- $paths[] = strtolower(str_replace('\\', '/', substr($class, 3)) . '.php');
+ $split = explode('\\', $class, 3);
+
+ if (count($split) === 3) {
+ $split[1] = strtolower($split[1]);
+
+ if ($split[1] === 'core') {
+ $paths[] = \OC::$SERVERROOT . '/core/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
+ } else if ($split[1] === 'settings') {
+ $paths[] = \OC::$SERVERROOT . '/settings/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
+ } else if ($split[1] === 'repair') {
+ $paths[] = \OC::$SERVERROOT . '/lib/repair/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
+
+ } else {
+ $paths[] = \OC::$SERVERROOT . '/lib/private/' . $split[1] . '/' . strtolower(str_replace('\\', '/', $split[2])) . '.php';
+ }
+
+ } else {
+ $paths[] = \OC::$SERVERROOT . '/lib/private/' . strtolower(str_replace('\\', '/', $split[1])) . '.php';
+ }
} elseif (strpos($class, 'OCP\\') === 0) {
- $paths[] = 'public/' . strtolower(str_replace('\\', '/', substr($class, 4)) . '.php');
+ $paths[] = \OC::$SERVERROOT . '/lib/public/' . strtolower(str_replace('\\', '/', substr($class, 4)) . '.php');
} elseif (strpos($class, 'OCA\\') === 0) {
list(, $app, $rest) = explode('\\', $class, 3);
$app = strtolower($app);
@@ -118,9 +134,9 @@ class Autoloader {
$paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
}
} elseif (strpos($class, 'Test_') === 0) {
- $paths[] = 'tests/lib/' . strtolower(str_replace('_', '/', substr($class, 5)) . '.php');
+ $paths[] = \OC::$SERVERROOT . '/tests/lib/' . strtolower(str_replace('_', '/', substr($class, 5)) . '.php');
} elseif (strpos($class, 'Test\\') === 0) {
- $paths[] = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($class, 5)) . '.php');
+ $paths[] = \OC::$SERVERROOT . '/tests/lib/' . strtolower(str_replace('\\', '/', substr($class, 5)) . '.php');
}
return $paths;
}
diff --git a/lib/base.php b/lib/base.php
index 95a47dec1e2..f44c4ff5bf2 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -117,12 +117,6 @@ class OC {
* the app path list is empty or contains an invalid path
*/
public static function initPaths() {
- // ensure we can find OC_Config
- set_include_path(
- OC::$SERVERROOT . '/lib' . PATH_SEPARATOR .
- get_include_path()
- );
-
if(defined('PHPUNIT_CONFIG_DIR')) {
self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
diff --git a/lib/l10n/hu_HU.js b/lib/l10n/hu_HU.js
index 7f4bc21063a..66d53932d38 100644
--- a/lib/l10n/hu_HU.js
+++ b/lib/l10n/hu_HU.js
@@ -25,10 +25,11 @@ OC.L10N.register(
"yesterday" : "tegnap",
"_%n day ago_::_%n days ago_" : ["%n napja","%n napja"],
"last month" : "múlt hónapban",
- "_%n month ago_::_%n months ago_" : ["%n hónappal ezelőtt","%n hónappal ezelőtt"],
+ "_%n month ago_::_%n months ago_" : ["%n hónapja","%n hónapja"],
"last year" : "tavaly",
"_%n year ago_::_%n years ago_" : ["%n éve","%n éve"],
- "_%n hour ago_::_%n hours ago_" : ["%n órával ezelőtt","%n órával ezelőtt"],
+ "_%n hour ago_::_%n hours ago_" : ["%n órája","%n órája"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n perce","%n perce"],
"seconds ago" : "pár másodperce",
"web services under your control" : "webszolgáltatások saját kézben",
"Empty filename is not allowed" : "Üres fájlnév nem engedétlyezett",
diff --git a/lib/l10n/hu_HU.json b/lib/l10n/hu_HU.json
index 180b65181c2..91a95213444 100644
--- a/lib/l10n/hu_HU.json
+++ b/lib/l10n/hu_HU.json
@@ -23,10 +23,11 @@
"yesterday" : "tegnap",
"_%n day ago_::_%n days ago_" : ["%n napja","%n napja"],
"last month" : "múlt hónapban",
- "_%n month ago_::_%n months ago_" : ["%n hónappal ezelőtt","%n hónappal ezelőtt"],
+ "_%n month ago_::_%n months ago_" : ["%n hónapja","%n hónapja"],
"last year" : "tavaly",
"_%n year ago_::_%n years ago_" : ["%n éve","%n éve"],
- "_%n hour ago_::_%n hours ago_" : ["%n órával ezelőtt","%n órával ezelőtt"],
+ "_%n hour ago_::_%n hours ago_" : ["%n órája","%n órája"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n perce","%n perce"],
"seconds ago" : "pár másodperce",
"web services under your control" : "webszolgáltatások saját kézben",
"Empty filename is not allowed" : "Üres fájlnév nem engedétlyezett",
diff --git a/lib/private/app/codechecker/infochecker.php b/lib/private/app/codechecker/infochecker.php
index 91580bde07d..24835d8148f 100644
--- a/lib/private/app/codechecker/infochecker.php
+++ b/lib/private/app/codechecker/infochecker.php
@@ -77,6 +77,21 @@ class InfoChecker extends BasicEmitter {
$info = $this->infoParser->parse($appPath . '/appinfo/info.xml');
+ if (isset($info['dependencies']['owncloud']['@attributes']['min-version']) && ($info['requiremin'] || $info['require'])) {
+ $this->emit('InfoChecker', 'duplicateRequirement', ['min']);
+ $errors[] = [
+ 'type' => 'duplicateRequirement',
+ 'field' => 'min',
+ ];
+ }
+ if (isset($info['dependencies']['owncloud']['@attributes']['max-version']) && $info['requiremax']) {
+ $this->emit('InfoChecker', 'duplicateRequirement', ['max']);
+ $errors[] = [
+ 'type' => 'duplicateRequirement',
+ 'field' => 'max',
+ ];
+ }
+
foreach ($info as $key => $value) {
if(is_array($value)) {
$value = json_encode($value);
diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php
index 24b0ca4acac..8f5a7a05f01 100644
--- a/lib/private/files/storage/wrapper/encryption.php
+++ b/lib/private/files/storage/wrapper/encryption.php
@@ -480,6 +480,7 @@ class Encryption extends Wrapper {
* @param bool $preserveMtime
* @param bool $isRename
* @return bool
+ * @throws \Exception
*/
private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) {
@@ -487,7 +488,18 @@ class Encryption extends Wrapper {
// key from the original file. Just create a 1:1 copy and done
if ($this->isVersion($targetInternalPath) ||
$this->isVersion($sourceInternalPath)) {
- return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ if ($result) {
+ $info = $this->getCache('', $sourceStorage)->get($sourceInternalPath);
+ // make sure that we update the unencrypted size for the version
+ if (isset($info['encrypted']) && $info['encrypted'] === true) {
+ $this->updateUnencryptedSize(
+ $this->getFullPath($targetInternalPath),
+ $info['size']
+ );
+ }
+ }
+ return $result;
}
// first copy the keys that we reuse the existing file key on the target location
diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php
index 0f6ba7f24e0..73ff0e537c6 100644
--- a/lib/private/group/manager.php
+++ b/lib/private/group/manager.php
@@ -263,7 +263,9 @@ class Manager extends PublicEmitter implements IGroupManager {
* @return array with group ids
*/
public function getUserGroupIds($user) {
- return array_keys($this->getUserGroups($user));
+ return array_map(function($value) {
+ return (string) $value;
+ }, array_keys($this->getUserGroups($user)));
}
/**
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 0693a9c08fb..4503818a9ec 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -697,8 +697,8 @@ class Share extends Constants {
if (empty($inGroup)) {
$message = 'Sharing %s failed, because the user '
.'%s is not a member of any groups that %s is a member of';
- $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemSourceName, $shareWith, $uidOwner));
- \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
+ $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
+ \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
throw new \Exception($message_t);
}
}
diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php
new file mode 100644
index 00000000000..79bc809b9b2
--- /dev/null
+++ b/lib/private/share20/defaultshareprovider.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+use OC\Share20\Exception\ShareNotFound;
+use OC\Share20\Exception\BackendError;
+use OCP\IUser;
+
+class DefaultShareProvider implements IShareProvider {
+
+ /** @var \OCP\IDBConnection */
+ private $dbConn;
+
+ /** @var \OCP\IUserManager */
+ private $userManager;
+
+ /** @var \OCP\IGroupManager */
+ private $groupManager;
+
+ /** @var \OCP\Files\Folder */
+ private $userFolder;
+
+ public function __construct(\OCP\IDBConnection $connection,
+ \OCP\IUserManager $userManager,
+ \OCP\IGroupManager $groupManager,
+ \OCP\Files\Folder $userFolder) {
+ $this->dbConn = $connection;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->userFolder = $userFolder;
+ }
+
+ /**
+ * Share a path
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function create(Share $share) {
+ throw new \Exception();
+ }
+
+ /**
+ * Update a share
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function update(Share $share) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get all childre of this share
+ *
+ * @param IShare $share
+ * @return IShare[]
+ */
+ private function getChildren(IShare $share) {
+ $children = [];
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('parent', $qb->createParameter('parent')))
+ ->setParameter(':parent', $share->getId());
+
+ $cursor = $qb->execute();
+ while($data = $cursor->fetch()) {
+ $children[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+
+ return $children;
+ }
+
+ /**
+ * Delete all the children of this share
+ *
+ * @param IShare $share
+ */
+ protected function deleteChildren(IShare $share) {
+ foreach($this->getChildren($share) as $child) {
+ $this->delete($child);
+ }
+ }
+
+ /**
+ * Delete a share
+ *
+ * @param Share $share
+ * @throws BackendError
+ */
+ public function delete(IShare $share) {
+ $this->deleteChildren($share);
+
+ // Fetch share to make sure it exists
+ $share = $this->getShareById($share->getId());
+
+ $shareType = $share->getShareType();
+ $sharedWith = '';
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ $sharedWith = $share->getSharedWith()->getUID();
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $sharedWith = $share->getSharedWith()->getGID();
+ }
+
+ $hookParams = [
+ 'id' => $share->getId(),
+ 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getPath()->getId(),
+ 'shareType' => $shareType,
+ 'shareWith' => $sharedWith,
+ 'itemparent' => $share->getParent(),
+ 'uidOwner' => $share->getSharedBy()->getUID(),
+ 'fileSource' => $share->getPath()->getId(),
+ 'fileTarget' => $share->getTarget()
+ ];
+
+ \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('share')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $share->getId());
+
+ try {
+ $qb->execute();
+ } catch (\Exception $e) {
+ throw new BackendError();
+ }
+
+ \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
+ }
+
+ /**
+ * Get all shares by the given user
+ *
+ * @param IUser $user
+ * @param int $shareType
+ * @param int $offset
+ * @param int $limit
+ * @return Share[]
+ */
+ public function getShares(IUser $user, $shareType, $offset, $limit) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get share by id
+ *
+ * @param int $id
+ * @return IShare
+ * @throws ShareNotFound
+ */
+ public function getShareById($id) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter(':id', $id);
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ $share = $this->createShare($data);
+
+ return $share;
+ }
+
+ /**
+ * Get shares for a given path
+ *
+ * @param \OCP\Files\Node $path
+ * @param Share[]
+ */
+ public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get shared with the given user
+ *
+ * @param IUser $user
+ * @param int $shareType
+ * @param Share
+ */
+ public function getSharedWithMe(IUser $user, $shareType = null) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get a share by token and if present verify the password
+ *
+ * @param string $token
+ * @param string $password
+ * @param Share
+ */
+ public function getShareByToken($token, $password = null) {
+ throw new \Exception();
+ }
+
+ /**
+ * Create a share object from an database row
+ *
+ * @param mixed[] $data
+ * @return Share
+ */
+ private function createShare($data) {
+ $share = new Share();
+ $share->setId((int)$data['id'])
+ ->setShareType((int)$data['share_type'])
+ ->setPermissions((int)$data['permissions'])
+ ->setTarget($data['file_target']);
+
+ 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->setToken($data['token']);
+ } else {
+ $share->setSharedWith($data['share_with']);
+ }
+
+ $share->setSharedBy($this->userManager->get($data['uid_owner']));
+
+ // TODO: getById can return an array. How to handle this properly??
+ $path = $this->userFolder->getById($data['file_source']);
+ $path = $path[0];
+ $share->setPath($path);
+
+ $owner = $path->getStorage()->getOwner('.');
+ if ($owner !== false) {
+ $share->setShareOwner($this->userManager->get($owner));
+ }
+
+ if ($data['expiration'] !== null) {
+ $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
+ $share->setExpirationDate($expiration);
+ }
+
+ return $share;
+ }
+
+
+}
diff --git a/lib/private/share20/exception/backenderror.php b/lib/private/share20/exception/backenderror.php
new file mode 100644
index 00000000000..2d661533171
--- /dev/null
+++ b/lib/private/share20/exception/backenderror.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20\Exception;
+
+class BackendError extends \Exception {
+
+}
diff --git a/lib/private/share20/exception/sharenotfound.php b/lib/private/share20/exception/sharenotfound.php
new file mode 100644
index 00000000000..0e18a96be68
--- /dev/null
+++ b/lib/private/share20/exception/sharenotfound.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20\Exception;
+
+class ShareNotFound extends \Exception {
+
+}
diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php
new file mode 100644
index 00000000000..fa7c1ea614c
--- /dev/null
+++ b/lib/private/share20/ishare.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\Node;
+use OCP\IUser;
+use OCP\IGroup;
+
+interface IShare {
+
+ /**
+ * Get the id of the share
+ *
+ * @return string
+ */
+ public function getId();
+
+ /**
+ * Set the path of this share
+ *
+ * @param File|Folder $path
+ * @return Share The modified object
+ */
+ public function setPath(Node $path);
+
+ /**
+ * Get the path of this share for the current user
+ *
+ * @return File|Folder
+ */
+ public function getPath();
+
+ /**
+ * Set the shareType
+ *
+ * @param int $shareType
+ * @return Share The modified object
+ */
+ public function setShareType($shareType);
+
+ /**
+ * Get the shareType
+ *
+ * @return int
+ */
+ public function getShareType();
+
+ /**
+ * Set the receiver of this share
+ *
+ * @param IUser|IGroup|string
+ * @return Share The modified object
+ */
+ public function setSharedWith($sharedWith);
+
+ /**
+ * Get the receiver of this share
+ *
+ * @return IUser|IGroup|string
+ */
+ public function getSharedWith();
+
+ /**
+ * Set the permissions
+ *
+ * @param int $permissions
+ * @return Share The modified object
+ */
+ public function setPermissions($permissions);
+
+ /**
+ * Get the share permissions
+ *
+ * @return int
+ */
+ public function getPermissions();
+
+ /**
+ * Set the expiration date
+ *
+ * @param \DateTime $expireDate
+ * @return Share The modified object
+ */
+ public function setExpirationDate(\DateTime $expireDate);
+
+ /**
+ * Get the share expiration date
+ *
+ * @return \DateTime
+ */
+ public function getExpirationDate();
+
+ /**
+ * Get share sharer
+ *
+ * @return IUser|string
+ */
+ public function getSharedBy();
+
+ /**
+ * Get the original share owner (who owns the path)
+ *
+ * @return IUser|string
+ */
+ public function getShareOwner();
+
+ /**
+ * Set the password
+ *
+ * @param string $password
+ *
+ * @return Share The modified object
+ */
+ public function setPassword($password);
+
+ /**
+ * Get the token
+ *
+ * @return string
+ */
+ public function getToken();
+
+ /**
+ * Get the parent it
+ *
+ * @return int
+ */
+ public function getParent();
+
+ /**
+ * Get the target of this share
+ *
+ * @return string
+ */
+ public function getTarget();
+}
diff --git a/lib/private/share20/ishareprovider.php b/lib/private/share20/ishareprovider.php
new file mode 100644
index 00000000000..b3f4eb6868f
--- /dev/null
+++ b/lib/private/share20/ishareprovider.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+use OC\Share20\Exception\ShareNotFound;
+use OC\Share20\Exception\BackendError;
+use OCP\IUser;
+
+interface IShareProvider {
+
+ /**
+ * Share a path
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function create(Share $share);
+
+ /**
+ * Update a share
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function update(Share $share);
+
+ /**
+ * Delete a share
+ *
+ * @param Share $share
+ * @throws BackendError
+ */
+ public function delete(IShare $share);
+
+ /**
+ * Get all shares by the given user
+ *
+ * @param IUser $user
+ * @param int $shareType
+ * @param int $offset
+ * @param int $limit
+ * @return Share[]
+ */
+ public function getShares(IUser $user, $shareType, $offset, $limit);
+
+ /**
+ * Get share by id
+ *
+ * @param int $id
+ * @return IShare
+ * @throws ShareNotFound
+ */
+ public function getShareById($id);
+
+ /**
+ * Get shares for a given path
+ *
+ * @param \OCP\Files\Node $path
+ * @param Share[]
+ */
+ public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path);
+
+ /**
+ * Get shared with the given user
+ *
+ * @param IUser $user
+ * @param int $shareType
+ * @param Share
+ */
+ public function getSharedWithMe(IUser $user, $shareType = null);
+
+ /**
+ * Get a share by token and if present verify the password
+ *
+ * @param string $token
+ * @param string $password
+ * @param Share
+ */
+ public function getShareByToken($token, $password = null);
+}
diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php
new file mode 100644
index 00000000000..52e43a9aa9f
--- /dev/null
+++ b/lib/private/share20/manager.php
@@ -0,0 +1,212 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+
+use OCP\IAppConfig;
+use OCP\IUserManager;
+use OCP\IGroupManager;
+use OCP\IUser;
+use OCP\ILogger;
+use OCP\Files\Folder;
+
+use OC\Share20\Exception\ShareNotFound;
+
+/**
+ * This class is the communication hub for all sharing related operations.
+ */
+class Manager {
+
+ /**
+ * @var IShareProvider[]
+ */
+ private $defaultProvider;
+
+ /** @var IUser */
+ private $currentUser;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IGroupManager */
+ private $groupManager;
+
+ /** @var ILogger */
+ private $logger;
+
+ /** @var IAppConfig */
+ private $appConfig;
+
+ /** @var IFolder */
+ private $userFolder;
+
+ public function __construct(IUser $user,
+ IUserManager $userManager,
+ IGroupManager $groupManager,
+ ILogger $logger,
+ IAppConfig $appConfig,
+ Folder $userFolder,
+ IShareProvider $defaultProvider) {
+ $this->currentUser = $user;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->logger = $logger;
+ $this->appConfig = $appConfig;
+ $this->userFolder = $userFolder;
+
+ // TEMP SOLUTION JUST TO GET STARTED
+ $this->defaultProvider = $defaultProvider;
+ }
+
+ /**
+ * Share a path
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function createShare(Share $share) {
+ throw new \Exception();
+ }
+
+ /**
+ * Update a share
+ *
+ * @param Share $share
+ * @return Share The share object
+ */
+ public function updateShare(Share $share) {
+ throw new \Exception();
+ }
+
+ /**
+ * Delete a share
+ *
+ * @param Share $share
+ * @throws ShareNotFound
+ * @throws \OC\Share20\Exception\BackendError
+ */
+ public function deleteShare(IShare $share) {
+ if ($share->getId() === null) {
+ throw new ShareNotFound();
+ }
+
+ $this->defaultProvider->delete($share);
+ }
+
+ /**
+ * Retrieve all shares by the current user
+ *
+ * @param int $page
+ * @param int $perPage
+ * @return Share[]
+ */
+ public function getShares($page=0, $perPage=50) {
+ throw new \Exception();
+ }
+
+ /**
+ * Retrieve a share by the share id
+ *
+ * @param string $id
+ * @return Share
+ *
+ * @throws ShareNotFound
+ */
+ public function getShareById($id) {
+ $share = $this->defaultProvider->getShareById($id);
+
+ if ($share->getSharedWith() !== $this->currentUser &&
+ $share->getSharedBy() !== $this->currentUser &&
+ $share->getShareOwner() !== $this->currentUser) {
+ throw new ShareNotFound();
+ }
+
+ return $share;
+ }
+
+ /**
+ * Get all the shares for a given path
+ *
+ * @param \OCP\Files\Node $path
+ * @param int $page
+ * @param int $perPage
+ *
+ * @return Share[]
+ */
+ public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get all shares that are shared with the current user
+ *
+ * @param int $shareType
+ * @param int $page
+ * @param int $perPage
+ *
+ * @return Share[]
+ */
+ public function getSharedWithMe($shareType = null, $page=0, $perPage=50) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get the share by token possible with password
+ *
+ * @param string $token
+ * @param string $password
+ *
+ * @return Share
+ *
+ * @throws ShareNotFoundException
+ */
+ public function getShareByToken($token, $password=null) {
+ throw new \Exception();
+ }
+
+ /**
+ * Get access list to a path. This means
+ * all the users and groups that can access a given path.
+ *
+ * Consider:
+ * -root
+ * |-folder1
+ * |-folder2
+ * |-fileA
+ *
+ * fileA is shared with user1
+ * folder2 is shared with group2
+ * folder1 is shared with user2
+ *
+ * Then the access list will to '/folder1/folder2/fileA' is:
+ * [
+ * 'users' => ['user1', 'user2'],
+ * 'groups' => ['group2']
+ * ]
+ *
+ * This is required for encryption
+ *
+ * @param \OCP\Files\Node $path
+ */
+ public function getAccessList(\OCP\Files\Node $path) {
+ throw new \Exception();
+ }
+}
diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php
new file mode 100644
index 00000000000..989edd3c079
--- /dev/null
+++ b/lib/private/share20/share.php
@@ -0,0 +1,318 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+use OCP\Files\Node;
+use OCP\IUser;
+use OCP\IGroup;
+
+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;
+
+ /**
+ * Set the id of the share
+ *
+ * @param int id
+ * @return Share The modified object
+ */
+ public function setId($id) {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * Get the id of the share
+ *
+ * @return string
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * Set the path of this share
+ *
+ * @param Node $path
+ * @return Share The modified object
+ */
+ public function setPath(Node $path) {
+ $this->path = $path;
+ return $this;
+ }
+
+ /**
+ * Get the path of this share for the current user
+ *
+ * @return Node
+ */
+ public function getPath() {
+ return $this->path;
+ }
+
+ /**
+ * Set the shareType
+ *
+ * @param int $shareType
+ * @return Share The modified object
+ */
+ public function setShareType($shareType) {
+ $this->shareType = $shareType;
+ return $this;
+ }
+
+ /**
+ * Get the shareType
+ *
+ * @return int
+ */
+ public function getShareType() {
+ return $this->shareType;
+ }
+
+ /**
+ * Set the receiver of this share
+ *
+ * @param IUser|IGroup|string
+ * @return Share The modified object
+ */
+ public function setSharedWith($sharedWith) {
+ $this->sharedWith = $sharedWith;
+ return $this;
+ }
+
+ /**
+ * Get the receiver of this share
+ *
+ * @return IUser|IGroup|string
+ */
+ public function getSharedWith() {
+ return $this->sharedWith;
+ }
+
+ /**
+ * Set the permissions
+ *
+ * @param int $permissions
+ * @return Share The modified object
+ */
+ public function setPermissions($permissions) {
+ //TODO checkes
+
+ $this->permissions = $permissions;
+ return $this;
+ }
+
+ /**
+ * Get the share permissions
+ *
+ * @return int
+ */
+ public function getPermissions() {
+ return $this->permissions;
+ }
+
+ /**
+ * Set the expiration date
+ *
+ * @param \DateTime $expireDate
+ * @return Share The modified object
+ */
+ public function setExpirationDate(\DateTime $expireDate) {
+ //TODO checks
+
+ $this->expireDate = $expireDate;
+ return $this;
+ }
+
+ /**
+ * Get the share expiration date
+ *
+ * @return \DateTime
+ */
+ public function getExpirationDate() {
+ return $this->expireDate;
+ }
+
+ /**
+ * Set the sharer of the path
+ *
+ * @param IUser|string $sharedBy
+ * @return Share The modified object
+ */
+ public function setSharedBy($sharedBy) {
+ //TODO checks
+ $this->sharedBy = $sharedBy;
+
+ return $this;
+ }
+
+ /**
+ * Get share sharer
+ *
+ * @return IUser|string
+ */
+ public function getSharedBy() {
+ //TODO check if set
+ return $this->sharedBy;
+ }
+
+ /**
+ * Set the original share owner (who owns the path)
+ *
+ * @param IUser|string
+ *
+ * @return Share The modified object
+ */
+ public function setShareOwner($shareOwner) {
+ //TODO checks
+
+ $this->shareOwner = $shareOwner;
+ return $this;
+ }
+
+ /**
+ * Get the original share owner (who owns the path)
+ *
+ * @return IUser|string
+ */
+ public function getShareOwner() {
+ //TODO check if set
+ return $this->shareOwner;
+ }
+
+ /**
+ * Set the password
+ *
+ * @param string $password
+ *
+ * @return Share The modified object
+ */
+ public function setPassword($password) {
+ //TODO verify
+
+ $this->password = $password;
+ return $this;
+ }
+
+ /**
+ * Get the password
+ *
+ * @return string
+ */
+ public function getPassword($password) {
+ return $this->password;
+ }
+
+ /**
+ * Set the token
+ *
+ * @param string $token
+ * @return Share The modified object
+ */
+ public function setToken($token) {
+ $this->token = $token;
+ return $this;
+ }
+
+ /**
+ * Get the token
+ *
+ * @return string
+ */
+ public function getToken() {
+ return $this->token;
+ }
+
+ /**
+ * Set the parent id of this share
+ *
+ * @param int $parent
+ * @return Share The modified object
+ */
+ public function setParent($parent) {
+ $this->parent = $parent;
+ return $this;
+ }
+
+ /**
+ * Get the parent id of this share
+ *
+ * @return int
+ */
+ public function getParent() {
+ return $this->parent;
+ }
+
+ /**
+ * Set the target of this share
+ *
+ * @param string target
+ * @return Share The modified object
+ */
+ public function setTarget($target) {
+ $this->target = $target;
+ return $this;
+ }
+
+ /**
+ * Get the target of this share
+ *
+ * @return string
+ */
+ public function getTarget() {
+ return $this->target;
+ }
+}
diff --git a/lib/private/subadmin.php b/lib/private/subadmin.php
index c00a2b24669..c96275e3b87 100644
--- a/lib/private/subadmin.php
+++ b/lib/private/subadmin.php
@@ -119,7 +119,10 @@ class SubAdmin extends PublicEmitter {
$groups = [];
while($row = $result->fetch()) {
- $groups[] = $this->groupManager->get($row['gid']);
+ $group = $this->groupManager->get($row['gid']);
+ if(!is_null($group)) {
+ $groups[] = $group;
+ }
}
$result->closeCursor();
@@ -141,7 +144,10 @@ class SubAdmin extends PublicEmitter {
$users = [];
while($row = $result->fetch()) {
- $users[] = $this->userManager->get($row['uid']);
+ $user = $this->userManager->get($row['uid']);
+ if(!is_null($user)) {
+ $users[] = $user;
+ }
}
$result->closeCursor();
@@ -161,10 +167,14 @@ class SubAdmin extends PublicEmitter {
$subadmins = [];
while($row = $result->fetch()) {
- $subadmins[] = [
- 'user' => $this->userManager->get($row['uid']),
- 'group' => $this->groupManager->get($row['gid'])
- ];
+ $user = $this->userManager->get($row['uid']);
+ $group = $this->groupManager->get($row['gid']);
+ if(!is_null($user) && !is_null($group)) {
+ $subadmins[] = [
+ 'user' => $user,
+ 'group' => $group
+ ];
+ }
}
$result->closeCursor();
diff --git a/settings/js/admin.js b/settings/js/admin.js
index 9f7133c6571..eb3b756bf0f 100644
--- a/settings/js/admin.js
+++ b/settings/js/admin.js
@@ -174,38 +174,46 @@ $(document).ready(function(){
var messages = [].concat(check1, check2, check3);
var $el = $('#postsetupchecks');
$el.find('.loading').addClass('hidden');
- if (messages.length === 0) {
+
+ var hasMessages = false;
+ var $errorsEl = $el.find('.errors');
+ var $warningsEl = $el.find('.warnings');
+ var $infoEl = $el.find('.info');
+
+ for (var i = 0; i < messages.length; i++ ) {
+ switch(messages[i].type) {
+ case OC.SetupChecks.MESSAGE_TYPE_INFO:
+ $infoEl.append('<li>' + messages[i].msg + '</li>');
+ break;
+ case OC.SetupChecks.MESSAGE_TYPE_WARNING:
+ $warningsEl.append('<li>' + messages[i].msg + '</li>');
+ break;
+ case OC.SetupChecks.MESSAGE_TYPE_ERROR:
+ default:
+ $errorsEl.append('<li>' + messages[i].msg + '</li>');
+ }
+ }
+
+ if ($errorsEl.find('li').length > 0) {
+ $errorsEl.removeClass('hidden');
+ hasMessages = true;
+ }
+ if ($warningsEl.find('li').length > 0) {
+ $warningsEl.removeClass('hidden');
+ hasMessages = true;
+ }
+ if ($infoEl.find('li').length > 0) {
+ $infoEl.removeClass('hidden');
+ hasMessages = true;
+ }
+
+ if (hasMessages) {
+ $el.find('.hint').removeClass('hidden');
+ } else {
var securityWarning = $('#security-warning');
if (securityWarning.children('ul').children().length === 0) {
$('#security-warning-state').find('span').removeClass('hidden');
}
- } else {
- var $errorsEl = $el.find('.errors');
- var $warningsEl = $el.find('.warnings');
- var $infoEl = $el.find('.info');
- for (var i = 0; i < messages.length; i++ ) {
- switch(messages[i].type) {
- case OC.SetupChecks.MESSAGE_TYPE_INFO:
- $infoEl.append('<li>' + messages[i].msg + '</li>');
- break;
- case OC.SetupChecks.MESSAGE_TYPE_WARNING:
- $warningsEl.append('<li>' + messages[i].msg + '</li>');
- break;
- case OC.SetupChecks.MESSAGE_TYPE_ERROR:
- default:
- $errorsEl.append('<li>' + messages[i].msg + '</li>');
- }
- }
- if ($errorsEl.find('li').length > 0) {
- $errorsEl.removeClass('hidden');
- }
- if ($warningsEl.find('li').length > 0) {
- $warningsEl.removeClass('hidden');
- }
- if ($infoEl.find('li').length > 0) {
- $infoEl.removeClass('hidden');
- }
- $el.find('.hint').removeClass('hidden');
}
});
});
diff --git a/settings/l10n/cs_CZ.js b/settings/l10n/cs_CZ.js
index e4411c6faa0..fc819461f4f 100644
--- a/settings/l10n/cs_CZ.js
+++ b/settings/l10n/cs_CZ.js
@@ -129,11 +129,13 @@ OC.L10N.register(
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Server běží v prostředí Microsoft Windows. Pro optimální uživatelské pohodlí doporučujeme přejít na Linux.",
"%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Je nainstalován %1$s nižší verze než %2$s, z důvodu lepší stability a výkonu doporučujeme aktualizovat na novější verzi %1$s.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Schází PHP modul 'fileinfo'. Doporučujeme jej povolit pro nejlepší výsledky detekce typů MIME.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů je vypnuto, což může vést k problémům s \"race\" podmínkami. Pro zabránění těmto problémům povolte 'filelocking.enabled' v souboru config.php. Více informací lze nalézt v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"System locale can not be set to a one which supports UTF-8." : "Není možné nastavit znakovou sadu, která podporuje UTF-8.",
"This means that there might be problems with certain characters in file names." : "To znamená, že se mohou vyskytnout problémy s určitými znaky v názvech souborů.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Velmi doporučujeme nainstalovat požadované balíčky do systému, pro podporu jednoho z následujících národních prostředí: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Instalace mimo kořenový adresář domény a používání systémového příkazu cron může způsobit problém s generováním správné URL. Pro zabránění těmto chybám nastavte prosím správnou cestu ve svém config.php souboru v hodnotě \"overwrite.cli.url\" (Je doporučena tato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Nebylo možné spustit službu cron v CLI. Došlo k následujícím technickým chybám:",
+ "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů používá databázi jako uzamykací mechanismus, pro co nejlepší výkon nakonfigurujte uzamykání pomocí memcache. Více informací najdete v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Ověřte znovu prosím informace z <a target=\"_blank\" href=\"%s\">instalační příručky ↗</a> a zkontrolujte <a href=\"#log-section\">log</a> na výskyt chyb a varování.",
"All checks passed." : "Všechny testy byly úspěšné.",
"Open documentation" : "Otevřít dokumentaci",
diff --git a/settings/l10n/cs_CZ.json b/settings/l10n/cs_CZ.json
index 94a0fa65262..598267f3de7 100644
--- a/settings/l10n/cs_CZ.json
+++ b/settings/l10n/cs_CZ.json
@@ -127,11 +127,13 @@
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Server běží v prostředí Microsoft Windows. Pro optimální uživatelské pohodlí doporučujeme přejít na Linux.",
"%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Je nainstalován %1$s nižší verze než %2$s, z důvodu lepší stability a výkonu doporučujeme aktualizovat na novější verzi %1$s.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Schází PHP modul 'fileinfo'. Doporučujeme jej povolit pro nejlepší výsledky detekce typů MIME.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů je vypnuto, což může vést k problémům s \"race\" podmínkami. Pro zabránění těmto problémům povolte 'filelocking.enabled' v souboru config.php. Více informací lze nalézt v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"System locale can not be set to a one which supports UTF-8." : "Není možné nastavit znakovou sadu, která podporuje UTF-8.",
"This means that there might be problems with certain characters in file names." : "To znamená, že se mohou vyskytnout problémy s určitými znaky v názvech souborů.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Velmi doporučujeme nainstalovat požadované balíčky do systému, pro podporu jednoho z následujících národních prostředí: %s.",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Instalace mimo kořenový adresář domény a používání systémového příkazu cron může způsobit problém s generováním správné URL. Pro zabránění těmto chybám nastavte prosím správnou cestu ve svém config.php souboru v hodnotě \"overwrite.cli.url\" (Je doporučena tato: \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Nebylo možné spustit službu cron v CLI. Došlo k následujícím technickým chybám:",
+ "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Transakční uzamykání souborů používá databázi jako uzamykací mechanismus, pro co nejlepší výkon nakonfigurujte uzamykání pomocí memcache. Více informací najdete v <a target=\"_blank\" href=\"%s\">dokumentaci ↗</a>.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Ověřte znovu prosím informace z <a target=\"_blank\" href=\"%s\">instalační příručky ↗</a> a zkontrolujte <a href=\"#log-section\">log</a> na výskyt chyb a varování.",
"All checks passed." : "Všechny testy byly úspěšné.",
"Open documentation" : "Otevřít dokumentaci",
diff --git a/settings/l10n/fi_FI.js b/settings/l10n/fi_FI.js
index 5755fae91bb..0099a3f3221 100644
--- a/settings/l10n/fi_FI.js
+++ b/settings/l10n/fi_FI.js
@@ -106,6 +106,7 @@ OC.L10N.register(
"A valid password must be provided" : "Anna kelvollinen salasana",
"A valid email must be provided" : "Tarvitaan kelvollinen sähköpostiosoite",
"__language_name__" : "_kielen_nimi_",
+ "Sync clients" : "Synkronointisovellukset",
"Personal info" : "Henkilökohtaiset tiedot",
"SSL root certificates" : "SSL-juurivarmenteet",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kaikki (vakavat ongelmat, virheet, varoitukset, tiedot, vianjäljitys)",
diff --git a/settings/l10n/fi_FI.json b/settings/l10n/fi_FI.json
index 2aa969f688a..8305ac79050 100644
--- a/settings/l10n/fi_FI.json
+++ b/settings/l10n/fi_FI.json
@@ -104,6 +104,7 @@
"A valid password must be provided" : "Anna kelvollinen salasana",
"A valid email must be provided" : "Tarvitaan kelvollinen sähköpostiosoite",
"__language_name__" : "_kielen_nimi_",
+ "Sync clients" : "Synkronointisovellukset",
"Personal info" : "Henkilökohtaiset tiedot",
"SSL root certificates" : "SSL-juurivarmenteet",
"Everything (fatal issues, errors, warnings, info, debug)" : "Kaikki (vakavat ongelmat, virheet, varoitukset, tiedot, vianjäljitys)",
diff --git a/settings/l10n/ja.js b/settings/l10n/ja.js
index 1fb55d63bdb..a1827392f86 100644
--- a/settings/l10n/ja.js
+++ b/settings/l10n/ja.js
@@ -10,7 +10,7 @@ OC.L10N.register(
"Cron" : "Cron",
"Email server" : "メールサーバー",
"Log" : "ログ",
- "Tips & tricks" : "Tips & tricks",
+ "Tips & tricks" : "ヒントとコツ",
"Updates" : "アップデート",
"Authentication error" : "認証エラー",
"Your full name has been changed." : "名前を変更しました。",
diff --git a/settings/l10n/ja.json b/settings/l10n/ja.json
index 2fbcf3a953f..a2597c026fe 100644
--- a/settings/l10n/ja.json
+++ b/settings/l10n/ja.json
@@ -8,7 +8,7 @@
"Cron" : "Cron",
"Email server" : "メールサーバー",
"Log" : "ログ",
- "Tips & tricks" : "Tips & tricks",
+ "Tips & tricks" : "ヒントとコツ",
"Updates" : "アップデート",
"Authentication error" : "認証エラー",
"Your full name has been changed." : "名前を変更しました。",
diff --git a/settings/l10n/oc.js b/settings/l10n/oc.js
index 1d4473babf1..70c66652e42 100644
--- a/settings/l10n/oc.js
+++ b/settings/l10n/oc.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"settings",
{
"APCu" : "APCu",
+ "Redis" : "Redis",
"Security & setup warnings" : "Avertiments de seguretat & configuracion",
"Sharing" : "Partiment",
"Server-side encryption" : "Chiframent costat servidor",
@@ -29,7 +30,9 @@ OC.L10N.register(
"Unable to change password" : "Impossible de modificar lo senhal",
"Enabled" : "Activadas",
"Not enabled" : "Desactivadas",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "lo partiment Federated Cloud o l'installacion e la mesa a jorn d'aplicacions per l'app store",
"Federated Cloud Sharing" : "Federated Cloud Sharing",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL utiliza %s version (%s), qu'es una version obsolèta. Metètz a jorn vòstre sistèma operatiu, o de foncionalitats talas coma %s foncionaràn pas corrèctament.",
"A problem occurred, please check your log files (Error: %s)" : "Una error s'es produsida, verificatz vòstres fichièrs de log (Error: %s)",
"Migration Completed" : "Migracion acabada",
"Group already exists." : "Aqueste grop existís ja.",
@@ -62,6 +65,7 @@ OC.L10N.register(
"No apps found for your version" : "Pas d'aplicacion trobada per vòstra version",
"Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Las aplicacions oficialas son desvolopadas per e amb la comunautat ownCloud. Ofrisson sas foncionalitats principalas a ownCloud e son prèstas per una utilizacion en produccion. ",
"Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Las aplicacions aprovadas son creadas per de desvolopaires de fisança e an passat los tèst de seguretat. Son activament mantengudas dins un depaus dobèrt e lors desvolopaires pensan que son establas per una utilizacion normala.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Aquesta aplicacion es novèla o instabla, e sa seguretat es pas estada verificada. Installatz-la a vòstras riscas e perilhs !",
"Update to %s" : "Metre a nivèl cap a la version %s",
"Please wait...." : "Pacientatz…",
"Error while disabling app" : "Error al moment de la desactivacion de l'aplicacion",
@@ -74,6 +78,9 @@ OC.L10N.register(
"Uninstalling ...." : "Desinstallacion...",
"Error while uninstalling app" : "Error al moment de la desinstallacion de l'aplicacion",
"Uninstall" : "Desinstallar",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'aplicacion es estada activada mas deu èsser mesa a jorn. Seretz redirigit cap a la pagina de las mesas a jorn dins 5 segondas.",
+ "App update" : "Mesa a jorn",
+ "No apps found for \"{query}\"" : "Cap d'aplicacion pas trobada per \"{query}\"",
"An error occurred: {message}" : "Una error s'es produsida : {message}",
"Select a profile picture" : "Seleccionar una fòto de perfil ",
"Very weak password" : "Senhal de fòrt febla seguretat",
@@ -115,17 +122,22 @@ OC.L10N.register(
"SSL" : "SSL",
"TLS" : "TLS",
"php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "sembla que php es pas configurat de manièra a recuperar las valors de las variablas d’environament. Lo test de la comanda getenv(\"PATH\") torna solament una responsa voida. ",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "Consultatz <a target=\"_blank\" href=\"%s\">la documentacion d'installacion ↗</a> per saber cossí configurar php sus vòstre servidor, en particular en cas d'utilizacion de php-fpm.",
"The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "La configuracion es en mòde lectura sola. Aquò empacha la modificacion de certanas configuracions via l'interfàcia web. Amai, lo fichièr deu èsser passat manualament en lectura-escritura per cada mesa a jorn.",
"PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP es aparentament configurat per suprimir los blòts de documentacion intèrnes. Aquò rendrà mantuna aplicacion de basa inaccessiblas.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "La rason es probablament l'utilizacion d'un escondedor / accelerador tal coma Zend OPcache o eAccelerator.",
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Vòstre servidor fonciona actualament sus una plataforma Microsoft Windows. Vos recomandam fòrtament d'utilizar una plataforma Linux per una experiéncia utilizaire optimala.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Una version de %1$s mai anciana que %2$s es installada. Per melhorar l'estabilitat e las performàncias, recomandam de metre %1$s a jorn.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Lo modul PHP 'fileinfo' es mancant. Es bravament recomandat de l'activar per fin d'obténer de melhors resultats de deteccion mime-type.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "La verrolhatge transaccional de fichièrs es desactivat. Aquò pòt causar de conflictes en cas d'accès concurrent. Configuratz 'filelocking.enabled' dins config.php per evitar aquestes problèmes. Consultatz la <a target=\"_blank\" href=\"%s\">documentacion ↗</a> per mai d'informacions.",
"System locale can not be set to a one which supports UTF-8." : "Los paramètres regionals pòdon pas èsser configurats amb presa en carga d'UTF-8.",
"This means that there might be problems with certain characters in file names." : "Aquò significa qu'i poiriá aver de problèmas amb certans caractèrs dins los noms de fichièr.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vos recomandam d'installar sus vòstre sistèma los paquets requesits a la presa en carga d'un dels paramètres regionals seguents : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se vòstra installacion es pas estada efectuada a la raiç del domeni e qu'utiliza lo cron del sistèma, i pòt aver de problèmas amb la generacion d'URL. Per los evitar, configuratz l'opcion \"overwrite.cli.url\" de vòstre fichièr config.php amb lo camin de la raiç de vòstra installacion (suggerit : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Lo prètzfach cron a pas pogut s'executar via CLI. Aquelas errors tecnicas son aparegudas :",
+ "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performànciasmelhor il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultatz los <a target=\"_blank\" href=\"%s\">guidas d'installacion ↗</a>, e cercatz d'errors o avertiments dins <a href=\"#log-section\">los logs</a>.",
+ "All checks passed." : "Totes los tèsts an capitat.",
"Open documentation" : "Veire la documentacion",
"Allow apps to use the Share API" : "Autorizar las aplicacions a utilizar l'API de partiment",
"Allow users to share via link" : "Autorizar los utilizaires a partejar per ligam",
@@ -141,6 +153,7 @@ OC.L10N.register(
"Allow users to send mail notification for shared files to other users" : "Autorizar los utilizaires a mandar una notificacion per corrièl a prepaus dels fichièrs partejats",
"Exclude groups from sharing" : "Empachar certans gropes de partejar",
"These groups will still be able to receive shares, but not to initiate them." : "Aqueles gropes poiràn pas mai iniciar cap de partiment, mas poiràn totjorn rejónher los partiments faches per d'autres. ",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performàncias melhoras, es recomandat d'utilizar puslèu memcache. Consultatz la <a target=\"_blank\" href=\"%s\">documentacion ↗</a> per mai d'informacions.",
"Last cron job execution: %s." : "Darrièr prètzfach cron d'executat : %s.",
"Last cron job execution: %s. Something seems wrong." : "Darrièr prètzfach cron d'executat : %s. Quicòm a trucat.",
"Cron was not executed yet!" : "Lo cron es pas encara estat executat !",
@@ -148,6 +161,12 @@ OC.L10N.register(
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php es enregistrat alprèp d'un servici webcron que l'executarà a cada 15 minutas via http.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Utilizatz lo servici cron del sistèma per apelar lo fichièr cron.php a cada 15 minutas.",
"Enable server-side encryption" : "Activar lo chiframent costat servidor",
+ "Please read carefully before activating server-side encryption: " : "Legissètz aquò amb atencion abans d'activar lo chiframent :",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Un còp lo chiframent activat, los fichièrs mandats sul servidor a partir d'aqueste moment seràn emmagazinats jos forma chifrada. Es pas possible de desactivar lo chiframent que se lo modul utilizat o permet especificament, e que totas las condicions prealablas son reünidas per aquò far (per exemple la creacion d'una clau de recuperacion).",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Lo chiframent sol pòt pas garantir la seguretat del sistèma. Consultatz la documentacion ownCloud per comprene cossí fonciona l'aplicacion de chiframent, e los cases d'utilizacion preses en carga.",
+ "Be aware that encryption always increases the file size." : "Notatz que lo chiframent aumenta totjorn la talha dels fichièrs.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Es oportun de salvar regularament vòstras donadas. Se aquestas donadas son chifradas, doblidetz pas de salvar tanben las claus de chiframent.",
+ "This is the final warning: Do you really want to enable encryption?" : "Darrièr avertiment : Sètz segur que volètz activar lo chiframent ?",
"Enable encryption" : "Activar lo chiframent",
"No encryption module loaded, please enable an encryption module in the app menu." : "Cap de modul de chiframent es pas cargat. Mercé d'activar un modul de chiframent dins lo menú de las aplicacions.",
"Select default encryption module:" : "Seleccionatz lo modul de chiframent per defaut :",
@@ -181,6 +200,7 @@ OC.L10N.register(
"Advanced monitoring" : "Susvelhança avançada",
"Performance tuning" : "Ajustament de las performàncias",
"Improving the config.php" : "Melhorament del config.php ",
+ "Theming" : "Personalizacion de l'aparéncia",
"Hardening and security guidance" : "Guida pel renforçament e la seguretat",
"Version" : "Version",
"Developer documentation" : "Documentacion pels desvolopaires",
@@ -190,6 +210,7 @@ OC.L10N.register(
"licensed" : "Jos licéncia",
"Documentation:" : "Documentacion :",
"User documentation" : "Documentacion utilizaire",
+ "Admin documentation" : "Documentacion administrator",
"Show description …" : "Afichar la descripcion...",
"Hide description …" : "Amagar la descripcion...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aquesta aplicacion pòt pas èsser installada a causa d'aquelas dependéncias pas satisfachas :",
@@ -227,6 +248,7 @@ OC.L10N.register(
"Upload new" : "Novèla dempuèi vòstre ordenador",
"Select new from Files" : "Novèla dempuèi los Fichièrs",
"Remove image" : "Suprimir l'imatge",
+ "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png o jpg de maximum 20 Mo. Idealament carrada, mas la poiretz requadrar.",
"Your avatar is provided by your original account." : "Vòstre avatar es provesit per vòstre compte original.",
"Cancel" : "Anullar",
"Choose as profile image" : "Causir en tant que fòto de perfil",
diff --git a/settings/l10n/oc.json b/settings/l10n/oc.json
index 299fcb5ccf7..a7e987f9787 100644
--- a/settings/l10n/oc.json
+++ b/settings/l10n/oc.json
@@ -1,5 +1,6 @@
{ "translations": {
"APCu" : "APCu",
+ "Redis" : "Redis",
"Security & setup warnings" : "Avertiments de seguretat & configuracion",
"Sharing" : "Partiment",
"Server-side encryption" : "Chiframent costat servidor",
@@ -27,7 +28,9 @@
"Unable to change password" : "Impossible de modificar lo senhal",
"Enabled" : "Activadas",
"Not enabled" : "Desactivadas",
+ "installing and updating apps via the app store or Federated Cloud Sharing" : "lo partiment Federated Cloud o l'installacion e la mesa a jorn d'aplicacions per l'app store",
"Federated Cloud Sharing" : "Federated Cloud Sharing",
+ "cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably." : "cURL utiliza %s version (%s), qu'es una version obsolèta. Metètz a jorn vòstre sistèma operatiu, o de foncionalitats talas coma %s foncionaràn pas corrèctament.",
"A problem occurred, please check your log files (Error: %s)" : "Una error s'es produsida, verificatz vòstres fichièrs de log (Error: %s)",
"Migration Completed" : "Migracion acabada",
"Group already exists." : "Aqueste grop existís ja.",
@@ -60,6 +63,7 @@
"No apps found for your version" : "Pas d'aplicacion trobada per vòstra version",
"Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Las aplicacions oficialas son desvolopadas per e amb la comunautat ownCloud. Ofrisson sas foncionalitats principalas a ownCloud e son prèstas per una utilizacion en produccion. ",
"Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Las aplicacions aprovadas son creadas per de desvolopaires de fisança e an passat los tèst de seguretat. Son activament mantengudas dins un depaus dobèrt e lors desvolopaires pensan que son establas per una utilizacion normala.",
+ "This app is not checked for security issues and is new or known to be unstable. Install at your own risk." : "Aquesta aplicacion es novèla o instabla, e sa seguretat es pas estada verificada. Installatz-la a vòstras riscas e perilhs !",
"Update to %s" : "Metre a nivèl cap a la version %s",
"Please wait...." : "Pacientatz…",
"Error while disabling app" : "Error al moment de la desactivacion de l'aplicacion",
@@ -72,6 +76,9 @@
"Uninstalling ...." : "Desinstallacion...",
"Error while uninstalling app" : "Error al moment de la desinstallacion de l'aplicacion",
"Uninstall" : "Desinstallar",
+ "The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds." : "L'aplicacion es estada activada mas deu èsser mesa a jorn. Seretz redirigit cap a la pagina de las mesas a jorn dins 5 segondas.",
+ "App update" : "Mesa a jorn",
+ "No apps found for \"{query}\"" : "Cap d'aplicacion pas trobada per \"{query}\"",
"An error occurred: {message}" : "Una error s'es produsida : {message}",
"Select a profile picture" : "Seleccionar una fòto de perfil ",
"Very weak password" : "Senhal de fòrt febla seguretat",
@@ -113,17 +120,22 @@
"SSL" : "SSL",
"TLS" : "TLS",
"php does not seem to be setup properly to query system environment variables. The test with getenv(\"PATH\") only returns an empty response." : "sembla que php es pas configurat de manièra a recuperar las valors de las variablas d’environament. Lo test de la comanda getenv(\"PATH\") torna solament una responsa voida. ",
+ "Please check the <a target=\"_blank\" href=\"%s\">installation documentation ↗</a> for php configuration notes and the php configuration of your server, especially when using php-fpm." : "Consultatz <a target=\"_blank\" href=\"%s\">la documentacion d'installacion ↗</a> per saber cossí configurar php sus vòstre servidor, en particular en cas d'utilizacion de php-fpm.",
"The Read-Only config has been enabled. This prevents setting some configurations via the web-interface. Furthermore, the file needs to be made writable manually for every update." : "La configuracion es en mòde lectura sola. Aquò empacha la modificacion de certanas configuracions via l'interfàcia web. Amai, lo fichièr deu èsser passat manualament en lectura-escritura per cada mesa a jorn.",
"PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible." : "PHP es aparentament configurat per suprimir los blòts de documentacion intèrnes. Aquò rendrà mantuna aplicacion de basa inaccessiblas.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "La rason es probablament l'utilizacion d'un escondedor / accelerador tal coma Zend OPcache o eAccelerator.",
"Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Vòstre servidor fonciona actualament sus una plataforma Microsoft Windows. Vos recomandam fòrtament d'utilizar una plataforma Linux per una experiéncia utilizaire optimala.",
+ "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Una version de %1$s mai anciana que %2$s es installada. Per melhorar l'estabilitat e las performàncias, recomandam de metre %1$s a jorn.",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Lo modul PHP 'fileinfo' es mancant. Es bravament recomandat de l'activar per fin d'obténer de melhors resultats de deteccion mime-type.",
+ "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "La verrolhatge transaccional de fichièrs es desactivat. Aquò pòt causar de conflictes en cas d'accès concurrent. Configuratz 'filelocking.enabled' dins config.php per evitar aquestes problèmes. Consultatz la <a target=\"_blank\" href=\"%s\">documentacion ↗</a> per mai d'informacions.",
"System locale can not be set to a one which supports UTF-8." : "Los paramètres regionals pòdon pas èsser configurats amb presa en carga d'UTF-8.",
"This means that there might be problems with certain characters in file names." : "Aquò significa qu'i poiriá aver de problèmas amb certans caractèrs dins los noms de fichièr.",
"We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Vos recomandam d'installar sus vòstre sistèma los paquets requesits a la presa en carga d'un dels paramètres regionals seguents : %s",
"If your installation is not installed in the root of the domain and uses system cron, there can be issues with the URL generation. To avoid these problems, please set the \"overwrite.cli.url\" option in your config.php file to the webroot path of your installation (Suggested: \"%s\")" : "Se vòstra installacion es pas estada efectuada a la raiç del domeni e qu'utiliza lo cron del sistèma, i pòt aver de problèmas amb la generacion d'URL. Per los evitar, configuratz l'opcion \"overwrite.cli.url\" de vòstre fichièr config.php amb lo camin de la raiç de vòstra installacion (suggerit : \"%s\")",
"It was not possible to execute the cronjob via CLI. The following technical errors have appeared:" : "Lo prètzfach cron a pas pogut s'executar via CLI. Aquelas errors tecnicas son aparegudas :",
+ "Transactional file locking is using the database as locking backend, for best performance it's advised to configure a memcache for locking. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performànciasmelhor il est recommandé d'utiliser plutôt memcache. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.",
"Please double check the <a target=\"_blank\" href=\"%s\">installation guides ↗</a>, and check for any errors or warnings in the <a href=\"#log-section\">log</a>." : "Consultatz los <a target=\"_blank\" href=\"%s\">guidas d'installacion ↗</a>, e cercatz d'errors o avertiments dins <a href=\"#log-section\">los logs</a>.",
+ "All checks passed." : "Totes los tèsts an capitat.",
"Open documentation" : "Veire la documentacion",
"Allow apps to use the Share API" : "Autorizar las aplicacions a utilizar l'API de partiment",
"Allow users to share via link" : "Autorizar los utilizaires a partejar per ligam",
@@ -139,6 +151,7 @@
"Allow users to send mail notification for shared files to other users" : "Autorizar los utilizaires a mandar una notificacion per corrièl a prepaus dels fichièrs partejats",
"Exclude groups from sharing" : "Empachar certans gropes de partejar",
"These groups will still be able to receive shares, but not to initiate them." : "Aqueles gropes poiràn pas mai iniciar cap de partiment, mas poiràn totjorn rejónher los partiments faches per d'autres. ",
+ "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Lo verrolhatge transaccional de fichièrs utiliza la banca de donadas. Per obténer de performàncias melhoras, es recomandat d'utilizar puslèu memcache. Consultatz la <a target=\"_blank\" href=\"%s\">documentacion ↗</a> per mai d'informacions.",
"Last cron job execution: %s." : "Darrièr prètzfach cron d'executat : %s.",
"Last cron job execution: %s. Something seems wrong." : "Darrièr prètzfach cron d'executat : %s. Quicòm a trucat.",
"Cron was not executed yet!" : "Lo cron es pas encara estat executat !",
@@ -146,6 +159,12 @@
"cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php es enregistrat alprèp d'un servici webcron que l'executarà a cada 15 minutas via http.",
"Use system's cron service to call the cron.php file every 15 minutes." : "Utilizatz lo servici cron del sistèma per apelar lo fichièr cron.php a cada 15 minutas.",
"Enable server-side encryption" : "Activar lo chiframent costat servidor",
+ "Please read carefully before activating server-side encryption: " : "Legissètz aquò amb atencion abans d'activar lo chiframent :",
+ "Once encryption is enabled, all files uploaded to the server from that point forward will be encrypted at rest on the server. It will only be possible to disable encryption at a later date if the active encryption module supports that function, and all pre-conditions (e.g. setting a recover key) are met." : "Un còp lo chiframent activat, los fichièrs mandats sul servidor a partir d'aqueste moment seràn emmagazinats jos forma chifrada. Es pas possible de desactivar lo chiframent que se lo modul utilizat o permet especificament, e que totas las condicions prealablas son reünidas per aquò far (per exemple la creacion d'una clau de recuperacion).",
+ "Encryption alone does not guarantee security of the system. Please see ownCloud documentation for more information about how the encryption app works, and the supported use cases." : "Lo chiframent sol pòt pas garantir la seguretat del sistèma. Consultatz la documentacion ownCloud per comprene cossí fonciona l'aplicacion de chiframent, e los cases d'utilizacion preses en carga.",
+ "Be aware that encryption always increases the file size." : "Notatz que lo chiframent aumenta totjorn la talha dels fichièrs.",
+ "It is always good to create regular backups of your data, in case of encryption make sure to backup the encryption keys along with your data." : "Es oportun de salvar regularament vòstras donadas. Se aquestas donadas son chifradas, doblidetz pas de salvar tanben las claus de chiframent.",
+ "This is the final warning: Do you really want to enable encryption?" : "Darrièr avertiment : Sètz segur que volètz activar lo chiframent ?",
"Enable encryption" : "Activar lo chiframent",
"No encryption module loaded, please enable an encryption module in the app menu." : "Cap de modul de chiframent es pas cargat. Mercé d'activar un modul de chiframent dins lo menú de las aplicacions.",
"Select default encryption module:" : "Seleccionatz lo modul de chiframent per defaut :",
@@ -179,6 +198,7 @@
"Advanced monitoring" : "Susvelhança avançada",
"Performance tuning" : "Ajustament de las performàncias",
"Improving the config.php" : "Melhorament del config.php ",
+ "Theming" : "Personalizacion de l'aparéncia",
"Hardening and security guidance" : "Guida pel renforçament e la seguretat",
"Version" : "Version",
"Developer documentation" : "Documentacion pels desvolopaires",
@@ -188,6 +208,7 @@
"licensed" : "Jos licéncia",
"Documentation:" : "Documentacion :",
"User documentation" : "Documentacion utilizaire",
+ "Admin documentation" : "Documentacion administrator",
"Show description …" : "Afichar la descripcion...",
"Hide description …" : "Amagar la descripcion...",
"This app cannot be installed because the following dependencies are not fulfilled:" : "Aquesta aplicacion pòt pas èsser installada a causa d'aquelas dependéncias pas satisfachas :",
@@ -225,6 +246,7 @@
"Upload new" : "Novèla dempuèi vòstre ordenador",
"Select new from Files" : "Novèla dempuèi los Fichièrs",
"Remove image" : "Suprimir l'imatge",
+ "Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB." : "Format png o jpg de maximum 20 Mo. Idealament carrada, mas la poiretz requadrar.",
"Your avatar is provided by your original account." : "Vòstre avatar es provesit per vòstre compte original.",
"Cancel" : "Anullar",
"Choose as profile image" : "Causir en tant que fòto de perfil",
diff --git a/settings/personal.php b/settings/personal.php
index d6d016c6545..bf1e1ad8793 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -93,6 +93,14 @@ foreach($languageCodes as $lang) {
}
}
+// if user language is not available but set somehow: show the actual code as name
+if (!is_array($userLang)) {
+ $userLang = [
+ 'code' => $userLang,
+ 'name' => $userLang,
+ ];
+}
+
ksort($commonlanguages);
// sort now by displayed language not the iso-code
diff --git a/tests/lib/autoloader.php b/tests/lib/autoloader.php
index 6d9d3bd8eba..9fb717c4f63 100644
--- a/tests/lib/autoloader.php
+++ b/tests/lib/autoloader.php
@@ -20,35 +20,53 @@ class AutoLoader extends TestCase {
}
public function testLeadingSlashOnClassName() {
- $this->assertEquals(array('private/files/storage/local.php', 'files/storage/local.php'), $this->loader->findClass('\OC\Files\Storage\Local'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/private/files/storage/local.php',
+ ], $this->loader->findClass('\OC\Files\Storage\Local'));
}
public function testNoLeadingSlashOnClassName() {
- $this->assertEquals(array('private/files/storage/local.php', 'files/storage/local.php'), $this->loader->findClass('OC\Files\Storage\Local'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/private/files/storage/local.php',
+ ], $this->loader->findClass('OC\Files\Storage\Local'));
}
public function testLegacyPath() {
- $this->assertEquals(array('private/legacy/files.php', 'private/files.php'), $this->loader->findClass('OC_Files'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/private/legacy/files.php',
+ \OC::$SERVERROOT . '/lib/private/files.php',
+ ], $this->loader->findClass('OC_Files'));
}
public function testLoadTestNamespace() {
- $this->assertEquals(array('tests/lib/foo/bar.php'), $this->loader->findClass('Test\Foo\Bar'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/tests/lib/foo/bar.php'
+ ], $this->loader->findClass('Test\Foo\Bar'));
}
public function testLoadTest() {
- $this->assertEquals(array('tests/lib/foo/bar.php'), $this->loader->findClass('Test_Foo_Bar'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/tests/lib/foo/bar.php'
+ ], $this->loader->findClass('Test_Foo_Bar'));
}
public function testLoadCoreNamespace() {
- $this->assertEquals(array('private/foo/bar.php', 'foo/bar.php'), $this->loader->findClass('OC\Foo\Bar'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/private/foo/bar.php',
+ ], $this->loader->findClass('OC\Foo\Bar'));
}
public function testLoadCore() {
- $this->assertEquals(array('private/legacy/foo/bar.php', 'private/foo/bar.php'), $this->loader->findClass('OC_Foo_Bar'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/private/legacy/foo/bar.php',
+ \OC::$SERVERROOT . '/lib/private/foo/bar.php',
+ ], $this->loader->findClass('OC_Foo_Bar'));
}
public function testLoadPublicNamespace() {
- $this->assertEquals(array('public/foo/bar.php'), $this->loader->findClass('OCP\Foo\Bar'));
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/public/foo/bar.php',
+ ], $this->loader->findClass('OCP\Foo\Bar'));
}
public function testLoadAppNamespace() {
@@ -57,4 +75,22 @@ class AutoLoader extends TestCase {
$this->assertStringEndsWith('apps/files/foobar.php', $result[0]);
$this->assertStringEndsWith('apps/files/lib/foobar.php', $result[1]);
}
+
+ public function testLoadCoreNamespaceCore() {
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/core/foo/bar.php',
+ ], $this->loader->findClass('OC\Core\Foo\Bar'));
+ }
+
+ public function testLoadCoreNamespaceSettings() {
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/settings/foo/bar.php',
+ ], $this->loader->findClass('OC\Settings\Foo\Bar'));
+ }
+
+ public function testLoadCoreNamespaceRepair() {
+ $this->assertEquals([
+ \OC::$SERVERROOT . '/lib/repair/foo/bar.php',
+ ], $this->loader->findClass('OC\Repair\Foo\Bar'));
+ }
}
diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php
index 095405462df..2b93aa86db0 100644
--- a/tests/lib/files/storage/wrapper/encryption.php
+++ b/tests/lib/files/storage/wrapper/encryption.php
@@ -560,6 +560,102 @@ class Encryption extends \Test\Files\Storage\Storage {
}
/**
+ * @dataProvider dataTestCopyBetweenStorageVersions
+ *
+ * @param string $sourceInternalPath
+ * @param string $targetInternalPath
+ * @param bool $copyResult
+ * @param bool $encrypted
+ */
+ public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted) {
+
+ $sourceStorage = $this->getMockBuilder('OCP\Files\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $targetStorage = $this->getMockBuilder('OCP\Files\Storage')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
+ ->disableOriginalConstructor()->getMock();
+
+ $mountPoint = '/mountPoint';
+
+ /** @var \OC\Files\Storage\Wrapper\Encryption |\PHPUnit_Framework_MockObject_MockObject $instance */
+ $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
+ ->setConstructorArgs(
+ [
+ [
+ 'storage' => $targetStorage,
+ 'root' => 'foo',
+ 'mountPoint' => $mountPoint,
+ 'mount' => $this->mount
+ ],
+ $this->encryptionManager,
+ $this->util,
+ $this->logger,
+ $this->file,
+ null,
+ $this->keyStore,
+ $this->update,
+ $this->mountManager
+ ]
+ )
+ ->setMethods(['updateUnencryptedSize', 'getCache'])
+ ->getMock();
+
+ $targetStorage->expects($this->once())->method('copyFromStorage')
+ ->with($sourceStorage, $sourceInternalPath, $targetInternalPath)
+ ->willReturn($copyResult);
+
+ if ($copyResult) {
+ $instance->expects($this->once())->method('getCache')
+ ->with('', $sourceStorage)
+ ->willReturn($cache);
+ $cache->expects($this->once())->method('get')
+ ->with($sourceInternalPath)
+ ->willReturn(['encrypted' => $encrypted, 'size' => 42]);
+ if ($encrypted) {
+ $instance->expects($this->once())->method('updateUnencryptedSize')
+ ->with($mountPoint . $targetInternalPath, 42);
+ } else {
+ $instance->expects($this->never())->method('updateUnencryptedSize');
+ }
+ } else {
+ $instance->expects($this->never())->method('updateUnencryptedSize');
+ }
+
+ $result = $this->invokePrivate(
+ $instance,
+ 'copyBetweenStorage',
+ [
+ $sourceStorage,
+ $sourceInternalPath,
+ $targetInternalPath,
+ false,
+ false
+ ]
+ );
+
+ $this->assertSame($copyResult, $result);
+ }
+
+ public function dataTestCopyBetweenStorageVersions() {
+ return [
+ ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true],
+ ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false],
+ ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true],
+ ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false],
+ ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true],
+ ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false],
+ ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true],
+ ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false],
+
+ ];
+ }
+
+ /**
* @dataProvider dataTestIsVersion
* @param string $path
* @param bool $expected
diff --git a/tests/lib/group/manager.php b/tests/lib/group/manager.php
index e3e2a96e46d..6cf473b9156 100644
--- a/tests/lib/group/manager.php
+++ b/tests/lib/group/manager.php
@@ -304,6 +304,32 @@ class Manager extends \Test\TestCase {
$this->assertEquals('group1', $group1->getGID());
}
+ public function testGetUserGroupIds() {
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Group\Manager $manager */
+ $manager = $this->getMockBuilder('OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->setMethods(['getUserGroups'])
+ ->getMock();
+ $manager->expects($this->once())
+ ->method('getUserGroups')
+ ->willReturn([
+ '123' => '123',
+ 'abc' => 'abc',
+ ]);
+
+ /** @var \OC\User\User $user */
+ $user = $this->getMockBuilder('OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $groups = $manager->getUserGroupIds($user);
+ $this->assertEquals(2, count($groups));
+
+ foreach ($groups as $group) {
+ $this->assertInternalType('string', $group);
+ }
+ }
+
public function testInGroup() {
/**
* @var \PHPUnit_Framework_MockObject_MockObject | \OC_Group_Backend $backend
diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php
new file mode 100644
index 00000000000..e99290f6724
--- /dev/null
+++ b/tests/lib/share20/defaultshareprovidertest.php
@@ -0,0 +1,654 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Test\Share20;
+
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use OCP\IGroupManager;
+use OCP\Files\Folder;
+use OC\Share20\DefaultShareProvider;
+
+class DefaultShareProviderTest extends \Test\TestCase {
+
+ /** @var IDBConnection */
+ protected $dbConn;
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var IGroupManager */
+ protected $groupManager;
+
+ /** @var Folder */
+ protected $userFolder;
+
+ /** @var DefaultShareProvider */
+ protected $provider;
+
+ public function setUp() {
+ $this->dbConn = \OC::$server->getDatabaseConnection();
+ $this->userManager = $this->getMock('OCP\IUserManager');
+ $this->groupManager = $this->getMock('OCP\IGroupManager');
+ $this->userFolder = $this->getMock('OCP\Files\Folder');
+
+ //Empty share table
+ $this->dbConn->getQueryBuilder()->delete('share')->execute();
+
+ $this->provider = new DefaultShareProvider(
+ $this->dbConn,
+ $this->userManager,
+ $this->groupManager,
+ $this->userFolder
+ );
+ }
+
+ public function tearDown() {
+ $this->dbConn->getQueryBuilder()->delete('share')->execute();
+ }
+
+ /**
+ * @expectedException OC\Share20\Exception\ShareNotFound
+ */
+ public function testGetShareByIdNotExist() {
+ $this->provider->getShareById(1);
+ }
+
+ public function testGetShareByIdUserShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $qb->execute();
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id = $cursor->fetch();
+ $id = $id['id'];
+ $cursor->closeCursor();
+
+ $storage = $this->getMock('OC\Files\Storage\Storage');
+ $storage
+ ->expects($this->once())
+ ->method('getOwner')
+ ->willReturn('shareOwner');
+ $path = $this->getMock('OCP\Files\File');
+ $path
+ ->expects($this->once())
+ ->method('getStorage')
+ ->wilLReturn($storage);
+ $this->userFolder
+ ->expects($this->once())
+ ->method('getById')
+ ->with(42)
+ ->willReturn([$path]);
+
+ $sharedWith = $this->getMock('OCP\IUser');
+ $sharedBy = $this->getMock('OCP\IUser');
+ $shareOwner = $this->getMock('OCP\IUser');
+ $this->userManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['sharedWith', $sharedWith],
+ ['sharedBy', $sharedBy],
+ ['shareOwner', $shareOwner],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+ $this->assertEquals($sharedWith, $share->getSharedWith());
+ $this->assertEquals($sharedBy, $share->getSharedBy());
+ $this->assertEquals($shareOwner, $share->getShareOwner());
+ $this->assertEquals($path, $share->getPath());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetShareByIdGroupShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id = $cursor->fetch();
+ $id = $id['id'];
+ $cursor->closeCursor();
+
+ $storage = $this->getMock('OC\Files\Storage\Storage');
+ $storage
+ ->expects($this->once())
+ ->method('getOwner')
+ ->willReturn('shareOwner');
+ $path = $this->getMock('OCP\Files\Folder');
+ $path
+ ->expects($this->once())
+ ->method('getStorage')
+ ->wilLReturn($storage);
+ $this->userFolder
+ ->expects($this->once())
+ ->method('getById')
+ ->with(42)
+ ->willReturn([$path]);
+
+ $sharedWith = $this->getMock('OCP\IGroup');
+ $sharedBy = $this->getMock('OCP\IUser');
+ $shareOwner = $this->getMock('OCP\IUser');
+ $this->userManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['sharedBy', $sharedBy],
+ ['shareOwner', $shareOwner],
+ ]));
+ $this->groupManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('sharedWith')
+ ->willReturn($sharedWith);
+
+ $share = $this->provider->getShareById($id);
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
+ $this->assertEquals($sharedWith, $share->getSharedWith());
+ $this->assertEquals($sharedBy, $share->getSharedBy());
+ $this->assertEquals($shareOwner, $share->getShareOwner());
+ $this->assertEquals($path, $share->getPath());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetShareByIdLinkShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_LINK),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ 'token' => $qb->expr()->literal('token'),
+ 'expiration' => $qb->expr()->literal('2000-01-02 00:00:00'),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id = $cursor->fetch();
+ $id = $id['id'];
+ $cursor->closeCursor();
+
+ $storage = $this->getMock('OC\Files\Storage\Storage');
+ $storage
+ ->expects($this->once())
+ ->method('getOwner')
+ ->willReturn('shareOwner');
+ $path = $this->getMock('OCP\Files\Node');
+ $path
+ ->expects($this->once())
+ ->method('getStorage')
+ ->wilLReturn($storage);
+ $this->userFolder
+ ->expects($this->once())
+ ->method('getById')
+ ->with(42)
+ ->willReturn([$path]);
+
+ $sharedBy = $this->getMock('OCP\IUser');
+ $shareOwner = $this->getMock('OCP\IUser');
+ $this->userManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['sharedBy', $sharedBy],
+ ['shareOwner', $shareOwner],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals($sharedBy, $share->getSharedBy());
+ $this->assertEquals($shareOwner, $share->getShareOwner());
+ $this->assertEquals($path, $share->getPath());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals('token', $share->getToken());
+ $this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testGetShareByIdRemoteShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_REMOTE),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id = $cursor->fetch();
+ $id = $id['id'];
+ $cursor->closeCursor();
+
+
+ $storage = $this->getMock('OC\Files\Storage\Storage');
+ $storage
+ ->expects($this->once())
+ ->method('getOwner')
+ ->willReturn('shareOwner');
+ $path = $this->getMock('OCP\Files\Node');
+ $path
+ ->expects($this->once())
+ ->method('getStorage')
+ ->wilLReturn($storage);
+ $this->userFolder
+ ->expects($this->once())
+ ->method('getById')
+ ->with(42)
+ ->willReturn([$path]);
+
+ $sharedBy = $this->getMock('OCP\IUser');
+ $shareOwner = $this->getMock('OCP\IUser');
+ $this->userManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['sharedBy', $sharedBy],
+ ['shareOwner', $shareOwner],
+ ]));
+
+ $share = $this->provider->getShareById($id);
+
+ $this->assertEquals($id, $share->getId());
+ $this->assertEquals(\OCP\Share::SHARE_TYPE_REMOTE, $share->getShareType());
+ $this->assertEquals('sharedWith', $share->getSharedWith());
+ $this->assertEquals($sharedBy, $share->getSharedBy());
+ $this->assertEquals($shareOwner, $share->getShareOwner());
+ $this->assertEquals($path, $share->getPath());
+ $this->assertEquals(13, $share->getPermissions());
+ $this->assertEquals(null, $share->getToken());
+ $this->assertEquals(null, $share->getExpirationDate());
+ $this->assertEquals('myTarget', $share->getTarget());
+ }
+
+ public function testDeleteSingleShare() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id = $cursor->fetch();
+ $id = $id['id'];
+ $cursor->closeCursor();
+
+
+ $path = $this->getMock('OCP\Files\File');
+ $path
+ ->expects($this->exactly(2))
+ ->method('getId')
+ ->willReturn(42);
+
+ $sharedWith = $this->getMock('OCP\IUser');
+ $sharedWith
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('sharedWith');
+ $sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('sharedBy');
+
+ $share = $this->getMock('OC\Share20\IShare');
+ $share
+ ->method('getId')
+ ->willReturn($id);
+ $share
+ ->expects($this->once())
+ ->method('getShareType')
+ ->willReturn(\OCP\Share::SHARE_TYPE_USER);
+ $share
+ ->expects($this->exactly(3))
+ ->method('getPath')
+ ->willReturn($path);
+ $share
+ ->expects($this->once())
+ ->method('getSharedWith')
+ ->willReturn($sharedWith);
+ $share
+ ->expects($this->once())
+ ->method('getSharedBy')
+ ->willReturn($sharedBy);
+ $share
+ ->expects($this->once())
+ ->method('getTarget')
+ ->willReturn('myTarget');
+
+ $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
+ ->setConstructorArgs([
+ $this->dbConn,
+ $this->userManager,
+ $this->groupManager,
+ $this->userFolder,
+ ]
+ )
+ ->setMethods(['deleteChildren', 'getShareById'])
+ ->getMock();
+ $provider
+ ->expects($this->once())
+ ->method('deleteChildren');
+ $provider
+ ->expects($this->once())
+ ->method('getShareById')
+ ->willReturn($share);
+
+ $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listen'])->getMock();
+ \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'listen');
+ \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'listen');
+
+ $hookListnerExpects = [
+ 'id' => $id,
+ 'itemType' => 'file',
+ 'itemSource' => 42,
+ 'shareType' => \OCP\Share::SHARE_TYPE_USER,
+ 'shareWith' => 'sharedWith',
+ 'itemparent' => null,
+ 'uidOwner' => 'sharedBy',
+ 'fileSource' => 42,
+ 'fileTarget' => 'myTarget',
+ ];
+
+ $hookListner
+ ->expects($this->exactly(2))
+ ->method('listen')
+ ->with($hookListnerExpects);
+
+
+ $provider->delete($share);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $cursor = $qb->execute();
+ $result = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertEmpty($result);
+ }
+
+ public function testDeleteNestedShares() {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id1 = $cursor->fetch();
+ $id1 = $id1['id'];
+ $cursor->closeCursor();
+
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ 'parent' => $qb->expr()->literal($id1),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ // Get the id
+ $qb = $this->dbConn->getQueryBuilder();
+ $cursor = $qb->select('id')
+ ->from('share')
+ ->setMaxResults(1)
+ ->orderBy('id', 'DESC')
+ ->execute();
+ $id2 = $cursor->fetch();
+ $id2 = $id2['id'];
+ $cursor->closeCursor();
+
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->values([
+ 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+ 'share_with' => $qb->expr()->literal('sharedWith'),
+ 'uid_owner' => $qb->expr()->literal('sharedBy'),
+ 'item_type' => $qb->expr()->literal('file'),
+ 'file_source' => $qb->expr()->literal(42),
+ 'file_target' => $qb->expr()->literal('myTarget'),
+ 'permissions' => $qb->expr()->literal(13),
+ 'parent' => $qb->expr()->literal($id2),
+ ]);
+ $this->assertEquals(1, $qb->execute());
+
+ $storage = $this->getMock('OC\Files\Storage\Storage');
+ $storage
+ ->method('getOwner')
+ ->willReturn('shareOwner');
+ $path = $this->getMock('OCP\Files\Node');
+ $path
+ ->method('getStorage')
+ ->wilLReturn($storage);
+ $this->userFolder
+ ->method('getById')
+ ->with(42)
+ ->willReturn([$path]);
+
+ $sharedWith = $this->getMock('OCP\IUser');
+ $sharedWith
+ ->method('getUID')
+ ->willReturn('sharedWith');
+ $sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy
+ ->method('getUID')
+ ->willReturn('sharedBy');
+ $shareOwner = $this->getMock('OCP\IUser');
+ $this->userManager
+ ->method('get')
+ ->will($this->returnValueMap([
+ ['sharedWith', $sharedWith],
+ ['sharedBy', $sharedBy],
+ ['shareOwner', $shareOwner],
+ ]));
+
+ $share = $this->provider->getShareById($id1);
+ $this->provider->delete($share);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share');
+
+ $cursor = $qb->execute();
+ $result = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertEmpty($result);
+ }
+
+ /**
+ * @expectedException \OC\Share20\Exception\BackendError
+ */
+ public function testDeleteFails() {
+ $share = $this->getMock('OC\Share20\IShare');
+ $share
+ ->method('getId')
+ ->willReturn(42);
+ $share
+ ->expects($this->once())
+ ->method('getShareType')
+ ->willReturn(\OCP\Share::SHARE_TYPE_LINK);
+
+ $path = $this->getMock('OCP\Files\Folder');
+ $path
+ ->expects($this->exactly(2))
+ ->method('getId')
+ ->willReturn(100);
+ $share
+ ->expects($this->exactly(3))
+ ->method('getPath')
+ ->willReturn($path);
+
+ $sharedBy = $this->getMock('OCP\IUser');
+ $sharedBy
+ ->expects($this->once())
+ ->method('getUID');
+ $share
+ ->expects($this->once())
+ ->method('getSharedBy')
+ ->willReturn($sharedBy);
+
+ $expr = $this->getMock('OCP\DB\QueryBuilder\IExpressionBuilder');
+ $qb = $this->getMock('OCP\DB\QueryBuilder\IQueryBuilder');
+ $qb->expects($this->once())
+ ->method('delete')
+ ->will($this->returnSelf());
+ $qb->expects($this->once())
+ ->method('expr')
+ ->willReturn($expr);
+ $qb->expects($this->once())
+ ->method('where')
+ ->will($this->returnSelf());
+ $qb->expects($this->once())
+ ->method('setParameter')
+ ->will($this->returnSelf());
+ $qb->expects($this->once())
+ ->method('execute')
+ ->will($this->throwException(new \Exception));
+
+ $db = $this->getMock('OCP\IDBConnection');
+ $db->expects($this->once())
+ ->method('getQueryBuilder')
+ ->with()
+ ->willReturn($qb);
+
+ $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider')
+ ->setConstructorArgs([
+ $db,
+ $this->userManager,
+ $this->groupManager,
+ $this->userFolder,
+ ]
+ )
+ ->setMethods(['deleteChildren', 'getShareById'])
+ ->getMock();
+ $provider
+ ->expects($this->once())
+ ->method('deleteChildren')
+ ->with($share);
+ $provider
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->willReturn($share);
+
+ $provider->delete($share);
+ }
+}
diff --git a/tests/lib/share20/managertest.php b/tests/lib/share20/managertest.php
new file mode 100644
index 00000000000..fc6c30692f5
--- /dev/null
+++ b/tests/lib/share20/managertest.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace Test\Share20;
+
+use OC\Share20\Manager;
+use OC\Share20\Exception;
+
+
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\IGroupManager;
+use OCP\ILogger;
+use OCP\IAppConfig;
+use OCP\Files\Folder;
+use OCP\Share20\IShareProvider;
+
+class ManagerTest extends \Test\TestCase {
+
+ /** @var Manager */
+ protected $manager;
+
+ /** @var IUser */
+ protected $user;
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var IGroupManager */
+ protected $groupManager;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var IAppConfig */
+ protected $appConfig;
+
+ /** @var Folder */
+ protected $userFolder;
+
+ /** @var IShareProvider */
+ protected $defaultProvider;
+
+ public function setUp() {
+
+ $this->user = $this->getMock('\OCP\IUser');
+ $this->userManager = $this->getMock('\OCP\IUserManager');
+ $this->groupManager = $this->getMock('\OCP\IGroupManager');
+ $this->logger = $this->getMock('\OCP\ILogger');
+ $this->appConfig = $this->getMock('\OCP\IAppConfig');
+ $this->userFolder = $this->getMock('\OCP\Files\Folder');
+ $this->defaultProvider = $this->getMock('\OC\Share20\IShareProvider');
+
+ $this->manager = new Manager(
+ $this->user,
+ $this->userManager,
+ $this->groupManager,
+ $this->logger,
+ $this->appConfig,
+ $this->userFolder,
+ $this->defaultProvider
+ );
+ }
+
+ /**
+ * @expectedException OC\Share20\Exception\ShareNotFound
+ */
+ public function testDeleteNoShareId() {
+ $share = $this->getMock('\OC\Share20\IShare');
+
+ $share
+ ->expects($this->once())
+ ->method('getId')
+ ->with()
+ ->willReturn(null);
+
+ $this->manager->deleteShare($share);
+ }
+
+ public function testDelete() {
+ $share = $this->getMock('\OC\Share20\IShare');
+
+ $share
+ ->expects($this->once())
+ ->method('getId')
+ ->with()
+ ->willReturn(42);
+ $this->defaultProvider
+ ->expects($this->once())
+ ->method('delete')
+ ->with($share);
+
+ $this->manager->deleteShare($share);
+ }
+
+ /**
+ * @expectedException OC\Share20\Exception\ShareNotFound
+ */
+ public function testGetShareByIdNotFoundInBackend() {
+ $this->defaultProvider
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound()));
+
+ $this->manager->getShareById(42);
+ }
+
+ /**
+ * @expectedException OC\Share20\Exception\ShareNotFound
+ */
+ public function testGetShareByIdNotAuthorized() {
+ $otherUser1 = $this->getMock('\OCP\IUser');
+ $otherUser2 = $this->getMock('\OCP\IUser');
+ $otherUser3 = $this->getMock('\OCP\IUser');
+
+ $share = $this->getMock('\OC\Share20\IShare');
+ $share
+ ->expects($this->once())
+ ->method('getSharedWith')
+ ->with()
+ ->willReturn($otherUser1);
+ $share
+ ->expects($this->once())
+ ->method('getSharedBy')
+ ->with()
+ ->willReturn($otherUser2);
+ $share
+ ->expects($this->once())
+ ->method('getShareOwner')
+ ->with()
+ ->willReturn($otherUser3);
+
+ $this->defaultProvider
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->willReturn($share);
+
+ $this->manager->getShareById(42);
+ }
+
+ public function dataGetShareById() {
+ return [
+ ['getSharedWith'],
+ ['getSharedBy'],
+ ['getShareOwner'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataGetShareById
+ */
+ public function testGetShareById($currentUserIs) {
+ $otherUser1 = $this->getMock('\OCP\IUser');
+ $otherUser2 = $this->getMock('\OCP\IUser');
+ $otherUser3 = $this->getMock('\OCP\IUser');
+
+ $share = $this->getMock('\OC\Share20\IShare');
+ $share
+ ->method('getSharedWith')
+ ->with()
+ ->willReturn($currentUserIs === 'getSharedWith' ? $this->user : $otherUser1);
+ $share
+ ->method('getSharedBy')
+ ->with()
+ ->willReturn($currentUserIs === 'getSharedBy' ? $this->user : $otherUser2);
+ $share
+ ->method('getShareOwner')
+ ->with()
+ ->willReturn($currentUserIs === 'getShareOwner' ? $this->user : $otherUser3);
+
+ $this->defaultProvider
+ ->expects($this->once())
+ ->method('getShareById')
+ ->with(42)
+ ->willReturn($share);
+
+ $this->assertEquals($share, $this->manager->getShareById(42));
+ }
+}
diff --git a/tests/lib/subadmin.php b/tests/lib/subadmin.php
index 0855e514c7e..960943c22f5 100644
--- a/tests/lib/subadmin.php
+++ b/tests/lib/subadmin.php
@@ -55,6 +55,28 @@ class SubAdmin extends \Test\TestCase {
if (!$this->groupManager->groupExists('admin')) {
$this->groupManager->createGroup('admin');
}
+
+ // Create "orphaned" users and groups (scenario: temporarily disabled
+ // backend)
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('group_admin')
+ ->values([
+ 'gid' => $qb->createNamedParameter($this->groups[0]->getGID()),
+ 'uid' => $qb->createNamedParameter('orphanedUser')
+ ])
+ ->execute();
+ $qb->insert('group_admin')
+ ->values([
+ 'gid' => $qb->createNamedParameter('orphanedGroup'),
+ 'uid' => $qb->createNamedParameter('orphanedUser')
+ ])
+ ->execute();
+ $qb->insert('group_admin')
+ ->values([
+ 'gid' => $qb->createNamedParameter('orphanedGroup'),
+ 'uid' => $qb->createNamedParameter($this->users[0]->getUID())
+ ])
+ ->execute();
}
public function tearDown() {
@@ -65,6 +87,12 @@ class SubAdmin extends \Test\TestCase {
foreach($this->groups as $group) {
$group->delete();
}
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->delete('group_admin')
+ ->where($qb->expr()->eq('uid', $qb->createNamedParameter('orphanedUser')))
+ ->orWhere($qb->expr()->eq('gid', $qb->createNamedParameter('orphanedGroup')))
+ ->execute();
}
public function testCreateSubAdmin() {
@@ -118,6 +146,7 @@ class SubAdmin extends \Test\TestCase {
$this->assertContains($this->groups[0], $result);
$this->assertContains($this->groups[1], $result);
$this->assertNotContains($this->groups[2], $result);
+ $this->assertNotContains(null, $result);
$this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]));
$this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[1]));
@@ -133,6 +162,7 @@ class SubAdmin extends \Test\TestCase {
$this->assertContains($this->users[0], $result);
$this->assertContains($this->users[1], $result);
$this->assertNotContains($this->users[2], $result);
+ $this->assertNotContains(null, $result);
$this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]));
$this->assertTrue($subAdmin->deleteSubAdmin($this->users[1], $this->groups[0]));
@@ -150,6 +180,7 @@ class SubAdmin extends \Test\TestCase {
$this->assertContains(['user' => $this->users[0], 'group' => $this->groups[0]], $result);
$this->assertContains(['user' => $this->users[1], 'group' => $this->groups[1]], $result);
$this->assertContains(['user' => $this->users[2], 'group' => $this->groups[1]], $result);
+ $this->assertNotContains(['user' => null, 'group' => null], $result);
}
public function testIsSubAdminofGroup() {
diff --git a/themes/example/core/img/favicon.ico b/themes/example/core/img/favicon.ico
new file mode 100644
index 00000000000..70b59ad7669
--- /dev/null
+++ b/themes/example/core/img/favicon.ico
Binary files differ