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/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/lib/config.php2
-rw-r--r--apps/user_ldap/l10n/hu_HU.js2
-rw-r--r--apps/user_ldap/l10n/hu_HU.json2
-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--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--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/ja.js2
-rw-r--r--settings/l10n/ja.json2
-rw-r--r--settings/personal.php8
-rw-r--r--tests/lib/autoloader.php53
-rw-r--r--themes/example/core/img/favicon.icobin0 -> 5686 bytes
69 files changed, 1292 insertions, 151 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/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/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/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/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/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/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/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/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..fa10c0b6216 100644
--- a/tests/lib/autoloader.php
+++ b/tests/lib/autoloader.php
@@ -20,41 +20,78 @@ 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() {
$result = $this->loader->findClass('OCA\Files\Foobar');
+ print_r($result);
$this->assertEquals(2, count($result));
$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/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