summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/caldav/caldavbackend.php4
-rw-r--r--apps/dav/lib/carddav/carddavbackend.php4
-rw-r--r--apps/dav/lib/connector/legacydavacl.php4
-rw-r--r--apps/dav/lib/connector/sabre/davaclplugin.php72
-rw-r--r--apps/dav/lib/connector/sabre/directory.php7
-rw-r--r--apps/dav/lib/server.php3
-rw-r--r--apps/dav/tests/unit/carddav/carddavbackendtest.php7
-rw-r--r--apps/dav/tests/unit/connector/sabre/directory.php39
-rw-r--r--apps/encryption/l10n/es.js2
-rw-r--r--apps/encryption/l10n/es.json2
-rw-r--r--apps/encryption/lib/crypto/decryptall.php57
-rw-r--r--apps/encryption/lib/keymanager.php2
-rw-r--r--apps/encryption/tests/lib/crypto/decryptalltest.php14
-rw-r--r--apps/federation/l10n/es.js11
-rw-r--r--apps/federation/l10n/es.json9
-rw-r--r--apps/files/l10n/nb_NO.js2
-rw-r--r--apps/files/l10n/nb_NO.json2
-rw-r--r--apps/files_external/service/dbconfigservice.php58
-rw-r--r--apps/files_sharing/api/share20ocs.php25
-rw-r--r--apps/files_sharing/l10n/es.js10
-rw-r--r--apps/files_sharing/l10n/es.json10
-rw-r--r--apps/files_sharing/lib/sharedstorage.php4
-rw-r--r--apps/files_sharing/tests/api/share20ocstest.php4
-rw-r--r--apps/systemtags/l10n/es.js14
-rw-r--r--apps/systemtags/l10n/es.json14
25 files changed, 308 insertions, 72 deletions
diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php
index 7f6810fb1e2..70dbccb8745 100644
--- a/apps/dav/lib/caldav/caldavbackend.php
+++ b/apps/dav/lib/caldav/caldavbackend.php
@@ -607,7 +607,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
->values([
'calendarid' => $query->createNamedParameter($calendarId),
'uri' => $query->createNamedParameter($objectUri),
- 'calendardata' => $query->createNamedParameter($calendarData, \PDO::PARAM_LOB),
+ 'calendardata' => $query->createNamedParameter($calendarData, IQueryBuilder::PARAM_LOB),
'lastmodified' => $query->createNamedParameter(time()),
'etag' => $query->createNamedParameter($extraData['etag']),
'size' => $query->createNamedParameter($extraData['size']),
@@ -646,7 +646,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$query = $this->db->getQueryBuilder();
$query->update('calendarobjects')
- ->set('calendardata', $query->createNamedParameter($calendarData, \PDO::PARAM_LOB))
+ ->set('calendardata', $query->createNamedParameter($calendarData, IQueryBuilder::PARAM_LOB))
->set('lastmodified', $query->createNamedParameter(time()))
->set('etag', $query->createNamedParameter($extraData['etag']))
->set('size', $query->createNamedParameter($extraData['size']))
diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php
index 61bdec52479..a109e8bde4a 100644
--- a/apps/dav/lib/carddav/carddavbackend.php
+++ b/apps/dav/lib/carddav/carddavbackend.php
@@ -489,7 +489,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$query = $this->db->getQueryBuilder();
$query->insert('cards')
->values([
- 'carddata' => $query->createNamedParameter($cardData, \PDO::PARAM_LOB),
+ 'carddata' => $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB),
'uri' => $query->createNamedParameter($cardUri),
'lastmodified' => $query->createNamedParameter(time()),
'addressbookid' => $query->createNamedParameter($addressBookId),
@@ -542,7 +542,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$etag = md5($cardData);
$query = $this->db->getQueryBuilder();
$query->update('cards')
- ->set('carddata', $query->createNamedParameter($cardData, \PDO::PARAM_LOB))
+ ->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
->set('lastmodified', $query->createNamedParameter(time()))
->set('size', $query->createNamedParameter(strlen($cardData)))
->set('etag', $query->createNamedParameter($etag))
diff --git a/apps/dav/lib/connector/legacydavacl.php b/apps/dav/lib/connector/legacydavacl.php
index 149bd85e4be..5a654606465 100644
--- a/apps/dav/lib/connector/legacydavacl.php
+++ b/apps/dav/lib/connector/legacydavacl.php
@@ -21,10 +21,10 @@
namespace OCA\DAV\Connector;
-
+use OCA\DAV\Connector\Sabre\DavAclPlugin;
use Sabre\HTTP\URLUtil;
-class LegacyDAVACL extends \Sabre\DAVACL\Plugin {
+class LegacyDAVACL extends DavAclPlugin {
/**
* Converts the v1 principal `principal/<username>` to the new v2
diff --git a/apps/dav/lib/connector/sabre/davaclplugin.php b/apps/dav/lib/connector/sabre/davaclplugin.php
new file mode 100644
index 00000000000..4a9dd66161d
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/davaclplugin.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, 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\Connector\Sabre;
+
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\IFile;
+use Sabre\DAV\INode;
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use Sabre\DAVACL\Exception\NeedPrivileges;
+use \Sabre\HTTP\RequestInterface;
+use \Sabre\HTTP\ResponseInterface;
+use Sabre\HTTP\URLUtil;
+
+/**
+ * Class DavAclPlugin is a wrapper around \Sabre\DAVACL\Plugin that returns 404
+ * responses in case the resource to a response has been forbidden instead of
+ * a 403. This is used to prevent enumeration of valid resources.
+ *
+ * @see https://github.com/owncloud/core/issues/22578
+ * @package OCA\DAV\Connector\Sabre
+ */
+class DavAclPlugin extends \Sabre\DAVACL\Plugin {
+ public function __construct() {
+ $this->hideNodesFromListings = true;
+ }
+
+ function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
+ $access = parent::checkPrivileges($uri, $privileges, $recursion, false);
+ if($access === false) {
+ /** @var INode $node */
+ $node = $this->server->tree->getNodeForPath($uri);
+
+ switch(get_class($node)) {
+ case 'OCA\DAV\CardDAV\AddressBook':
+ $type = 'Addressbook';
+ break;
+ default:
+ $type = 'Node';
+ break;
+ }
+ throw new NotFound(
+ sprintf(
+ "%s with name '%s' could not be found",
+ $type,
+ $node->getName()
+ )
+ );
+ }
+
+ return $access;
+ }
+}
diff --git a/apps/dav/lib/connector/sabre/directory.php b/apps/dav/lib/connector/sabre/directory.php
index 0119879a171..f31eff30b65 100644
--- a/apps/dav/lib/connector/sabre/directory.php
+++ b/apps/dav/lib/connector/sabre/directory.php
@@ -291,9 +291,14 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
}
try {
$storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
+ if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
+ $free = \OCP\Files\FileInfo::SPACE_UNLIMITED;
+ } else {
+ $free = $storageInfo['free'];
+ }
$this->quotaInfo = array(
$storageInfo['used'],
- $storageInfo['free']
+ $free
);
return $this->quotaInfo;
} catch (\OCP\Files\StorageNotAvailableException $e) {
diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php
index 55ae6c62d31..2aa720c9dc4 100644
--- a/apps/dav/lib/server.php
+++ b/apps/dav/lib/server.php
@@ -26,6 +26,7 @@ use OCA\DAV\CalDAV\Schedule\IMipPlugin;
use OCA\DAV\Connector\FedAuth;
use OCA\DAV\Connector\Sabre\Auth;
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
+use OCA\DAV\Connector\Sabre\DavAclPlugin;
use OCA\DAV\Connector\Sabre\FilesPlugin;
use OCA\DAV\Files\CustomPropertiesBackend;
use OCP\IRequest;
@@ -72,7 +73,7 @@ class Server {
$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
// acl
- $acl = new \Sabre\DAVACL\Plugin();
+ $acl = new DavAclPlugin();
$acl->defaultUsernamePath = 'principals/users';
$this->server->addPlugin($acl);
diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php
index 401041d6e39..2f96fc5da90 100644
--- a/apps/dav/tests/unit/carddav/carddavbackendtest.php
+++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php
@@ -26,6 +26,7 @@ use InvalidArgumentException;
use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Connector\Sabre\Principal;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use Sabre\DAV\PropPatch;
use Sabre\VObject\Component\VCard;
@@ -480,7 +481,7 @@ class CardDavBackendTest extends TestCase {
->values(
[
'addressbookid' => $query->createNamedParameter(0),
- 'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), \PDO::PARAM_LOB),
+ 'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
'uri' => $query->createNamedParameter('uri' . $i),
'lastmodified' => $query->createNamedParameter(time()),
'etag' => $query->createNamedParameter('etag' . $i),
@@ -558,7 +559,7 @@ class CardDavBackendTest extends TestCase {
->values(
[
'addressbookid' => $query->createNamedParameter(1),
- 'carddata' => $query->createNamedParameter('carddata', \PDO::PARAM_LOB),
+ 'carddata' => $query->createNamedParameter('carddata', IQueryBuilder::PARAM_LOB),
'uri' => $query->createNamedParameter('uri'),
'lastmodified' => $query->createNamedParameter(5489543),
'etag' => $query->createNamedParameter('etag'),
@@ -586,7 +587,7 @@ class CardDavBackendTest extends TestCase {
->values(
[
'addressbookid' => $query->createNamedParameter($i),
- 'carddata' => $query->createNamedParameter('carddata' . $i, \PDO::PARAM_LOB),
+ 'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
'uri' => $query->createNamedParameter('uri' . $i),
'lastmodified' => $query->createNamedParameter(5489543),
'etag' => $query->createNamedParameter('etag' . $i),
diff --git a/apps/dav/tests/unit/connector/sabre/directory.php b/apps/dav/tests/unit/connector/sabre/directory.php
index 317e089925b..c4ddc38b3e1 100644
--- a/apps/dav/tests/unit/connector/sabre/directory.php
+++ b/apps/dav/tests/unit/connector/sabre/directory.php
@@ -199,15 +199,48 @@ class Directory extends \Test\TestCase {
$dir->getChild('.');
}
- public function testGetQuotaInfo() {
+ public function testGetQuotaInfoUnlimited() {
$storage = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Quota')
->disableOriginalConstructor()
->getMock();
+ $storage->expects($this->any())
+ ->method('instanceOfStorage')
+ ->will($this->returnValueMap([
+ '\OC\Files\Storage\Shared' => false,
+ '\OC\Files\Storage\Wrapper\Quota' => false,
+ ]));
+
+ $storage->expects($this->never())
+ ->method('getQuota');
+
$storage->expects($this->once())
+ ->method('free_space')
+ ->will($this->returnValue(800));
+
+ $this->info->expects($this->once())
+ ->method('getSize')
+ ->will($this->returnValue(200));
+
+ $this->info->expects($this->once())
+ ->method('getStorage')
+ ->will($this->returnValue($storage));
+
+ $dir = new \OCA\DAV\Connector\Sabre\Directory($this->view, $this->info);
+ $this->assertEquals([200, -3], $dir->getQuotaInfo()); //200 used, unlimited
+ }
+
+ public function testGetQuotaInfoSpecific() {
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Quota')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $storage->expects($this->any())
->method('instanceOfStorage')
- ->with('\OC\Files\Storage\Wrapper\Quota')
- ->will($this->returnValue(true));
+ ->will($this->returnValueMap([
+ ['\OC\Files\Storage\Shared', false],
+ ['\OC\Files\Storage\Wrapper\Quota', true],
+ ]));
$storage->expects($this->once())
->method('getQuota')
diff --git a/apps/encryption/l10n/es.js b/apps/encryption/l10n/es.js
index bdaeabb68cb..ec15af8fc2f 100644
--- a/apps/encryption/l10n/es.js
+++ b/apps/encryption/l10n/es.js
@@ -25,6 +25,8 @@ OC.L10N.register(
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "La clave privada no es válida para la app de cifrado. Por favor, actualiza la contraseña de tu clave privada en tus ajustes personales para recuperar el acceso a tus archivos cifrados.",
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "La app de cifrado está habilitada pero sus claves no se han inicializado, por favor, cierre la sesión y vuelva a iniciarla de nuevo.",
"Encryption App is enabled and ready" : "Cifrado App está habilitada y lista",
+ "Bad Signature" : "Firma errónea",
+ "Missing Signature" : "No se encuentra la firma",
"one-time password for server-side-encryption" : "Contraseña de un solo uso para el cifrado en el lado servidor",
"Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "No fue posible descifrar este archivo, probablemente se trate de un archivo compartido. Solicite al propietario del mismo que vuelva a compartirlo con usted.",
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "No se puede leer este archivo, probablemente sea un archivo compartido. Consulte con el propietario del mismo y que lo vuelva a compartir con usted.",
diff --git a/apps/encryption/l10n/es.json b/apps/encryption/l10n/es.json
index 3eb7994eb9d..12d0c6188e7 100644
--- a/apps/encryption/l10n/es.json
+++ b/apps/encryption/l10n/es.json
@@ -23,6 +23,8 @@
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "La clave privada no es válida para la app de cifrado. Por favor, actualiza la contraseña de tu clave privada en tus ajustes personales para recuperar el acceso a tus archivos cifrados.",
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "La app de cifrado está habilitada pero sus claves no se han inicializado, por favor, cierre la sesión y vuelva a iniciarla de nuevo.",
"Encryption App is enabled and ready" : "Cifrado App está habilitada y lista",
+ "Bad Signature" : "Firma errónea",
+ "Missing Signature" : "No se encuentra la firma",
"one-time password for server-side-encryption" : "Contraseña de un solo uso para el cifrado en el lado servidor",
"Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "No fue posible descifrar este archivo, probablemente se trate de un archivo compartido. Solicite al propietario del mismo que vuelva a compartirlo con usted.",
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "No se puede leer este archivo, probablemente sea un archivo compartido. Consulte con el propietario del mismo y que lo vuelva a compartir con usted.",
diff --git a/apps/encryption/lib/crypto/decryptall.php b/apps/encryption/lib/crypto/decryptall.php
index fa9a3e0db95..694aba2fb89 100644
--- a/apps/encryption/lib/crypto/decryptall.php
+++ b/apps/encryption/lib/crypto/decryptall.php
@@ -81,35 +81,42 @@ class DecryptAll {
public function prepare(InputInterface $input, OutputInterface $output, $user) {
$question = new Question('Please enter the recovery key password: ');
- $recoveryKeyId = $this->keyManager->getRecoveryKeyId();
- if (!empty($user)) {
- $output->writeln('You can only decrypt the users files if you know');
- $output->writeln('the users password or if he activated the recovery key.');
- $output->writeln('');
- $questionUseLoginPassword = new ConfirmationQuestion(
- 'Do you want to use the users login password to decrypt all files? (y/n) ',
- false
- );
- $useLoginPassword = $this->questionHelper->ask($input, $output, $questionUseLoginPassword);
- if ($useLoginPassword) {
- $question = new Question('Please enter the user\'s login password: ');
- } else if ($this->util->isRecoveryEnabledForUser($user) === false) {
- $output->writeln('No recovery key available for user ' . $user);
- return false;
+ if($this->util->isMasterKeyEnabled()) {
+ $output->writeln('Use master key to decrypt all files');
+ $user = $this->keyManager->getMasterKeyId();
+ $password =$this->keyManager->getMasterKeyPassword();
+ } else {
+ $recoveryKeyId = $this->keyManager->getRecoveryKeyId();
+ if (!empty($user)) {
+ $output->writeln('You can only decrypt the users files if you know');
+ $output->writeln('the users password or if he activated the recovery key.');
+ $output->writeln('');
+ $questionUseLoginPassword = new ConfirmationQuestion(
+ 'Do you want to use the users login password to decrypt all files? (y/n) ',
+ false
+ );
+ $useLoginPassword = $this->questionHelper->ask($input, $output, $questionUseLoginPassword);
+ if ($useLoginPassword) {
+ $question = new Question('Please enter the user\'s login password: ');
+ } else if ($this->util->isRecoveryEnabledForUser($user) === false) {
+ $output->writeln('No recovery key available for user ' . $user);
+ return false;
+ } else {
+ $user = $recoveryKeyId;
+ }
} else {
+ $output->writeln('You can only decrypt the files of all users if the');
+ $output->writeln('recovery key is enabled by the admin and activated by the users.');
+ $output->writeln('');
$user = $recoveryKeyId;
}
- } else {
- $output->writeln('You can only decrypt the files of all users if the');
- $output->writeln('recovery key is enabled by the admin and activated by the users.');
- $output->writeln('');
- $user = $recoveryKeyId;
+
+ $question->setHidden(true);
+ $question->setHiddenFallback(false);
+ $password = $this->questionHelper->ask($input, $output, $question);
}
- $question->setHidden(true);
- $question->setHiddenFallback(false);
- $password = $this->questionHelper->ask($input, $output, $question);
$privateKey = $this->getPrivateKey($user, $password);
if ($privateKey !== false) {
$this->updateSession($user, $privateKey);
@@ -132,9 +139,13 @@ class DecryptAll {
*/
protected function getPrivateKey($user, $password) {
$recoveryKeyId = $this->keyManager->getRecoveryKeyId();
+ $masterKeyId = $this->keyManager->getMasterKeyId();
if ($user === $recoveryKeyId) {
$recoveryKey = $this->keyManager->getSystemPrivateKey($recoveryKeyId);
$privateKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
+ } elseif ($user === $masterKeyId) {
+ $masterKey = $this->keyManager->getSystemPrivateKey($masterKeyId);
+ $privateKey = $this->crypt->decryptPrivateKey($masterKey, $password, $masterKeyId);
} else {
$userKey = $this->keyManager->getPrivateKey($user);
$privateKey = $this->crypt->decryptPrivateKey($userKey, $password, $user);
diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php
index 0c957e12012..4169569d8b2 100644
--- a/apps/encryption/lib/keymanager.php
+++ b/apps/encryption/lib/keymanager.php
@@ -658,7 +658,7 @@ class KeyManager {
* @return string
* @throws \Exception
*/
- protected function getMasterKeyPassword() {
+ public function getMasterKeyPassword() {
$password = $this->config->getSystemValue('secret');
if (empty($password)){
throw new \Exception('Can not get secret from ownCloud instance');
diff --git a/apps/encryption/tests/lib/crypto/decryptalltest.php b/apps/encryption/tests/lib/crypto/decryptalltest.php
index 84819aa73bd..0945692e427 100644
--- a/apps/encryption/tests/lib/crypto/decryptalltest.php
+++ b/apps/encryption/tests/lib/crypto/decryptalltest.php
@@ -87,7 +87,7 @@ class DecryptAllTest extends TestCase {
* @param string $user
* @param string $recoveryKeyId
*/
- public function testGetPrivateKey($user, $recoveryKeyId) {
+ public function testGetPrivateKey($user, $recoveryKeyId, $masterKeyId) {
$password = 'passwd';
$recoveryKey = 'recoveryKey';
$userKey = 'userKey';
@@ -102,6 +102,13 @@ class DecryptAllTest extends TestCase {
$this->keyManager->expects($this->never())->method('getPrivateKey');
$this->crypt->expects($this->once())->method('decryptPrivateKey')
->with($recoveryKey, $password)->willReturn($unencryptedKey);
+ } elseif ($user === $masterKeyId) {
+ $this->keyManager->expects($this->once())->method('getSystemPrivateKey')
+ ->with($masterKeyId)->willReturn($masterKey);
+ $this->keyManager->expects($this->never())->method('getPrivateKey');
+ $this->crypt->expects($this->once())->method('decryptPrivateKey')
+ ->with($masterKey, $password, $masterKeyId)->willReturn($unencryptedKey);
+
} else {
$this->keyManager->expects($this->never())->method('getSystemPrivateKey');
$this->keyManager->expects($this->once())->method('getPrivateKey')
@@ -117,8 +124,9 @@ class DecryptAllTest extends TestCase {
public function dataTestGetPrivateKey() {
return [
- ['user1', 'recoveryKey'],
- ['recoveryKeyId', 'recoveryKeyId']
+ ['user1', 'recoveryKey', 'masterKeyId'],
+ ['recoveryKeyId', 'recoveryKeyId', 'masterKeyId'],
+ ['masterKeyId', 'masterKeyId', 'masterKeyId']
];
}
diff --git a/apps/federation/l10n/es.js b/apps/federation/l10n/es.js
new file mode 100644
index 00000000000..fb899bb0fc2
--- /dev/null
+++ b/apps/federation/l10n/es.js
@@ -0,0 +1,11 @@
+OC.L10N.register(
+ "federation",
+ {
+ "Server added to the list of trusted ownClouds" : "Servidor agregado a la lista de ownClouds en los que se confía",
+ "Server is already in the list of trusted servers." : "El servidor ya está en la lista de servidores en los que se confía.",
+ "No ownCloud server found" : "No se ha encontrado el servidor ownCloud",
+ "Could not add server" : "No se pudo agregar el servidor",
+ "Federation" : "Federación",
+ "ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing." : "La Federación de ownCloud permite conectar con otros ownClouds en los que se confíe para intercambiar el directorio de usuario. Por ejemplo esto se usará para autocompletar usuarios externos para compartición federada."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/federation/l10n/es.json b/apps/federation/l10n/es.json
new file mode 100644
index 00000000000..f4797b10ee4
--- /dev/null
+++ b/apps/federation/l10n/es.json
@@ -0,0 +1,9 @@
+{ "translations": {
+ "Server added to the list of trusted ownClouds" : "Servidor agregado a la lista de ownClouds en los que se confía",
+ "Server is already in the list of trusted servers." : "El servidor ya está en la lista de servidores en los que se confía.",
+ "No ownCloud server found" : "No se ha encontrado el servidor ownCloud",
+ "Could not add server" : "No se pudo agregar el servidor",
+ "Federation" : "Federación",
+ "ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing." : "La Federación de ownCloud permite conectar con otros ownClouds en los que se confíe para intercambiar el directorio de usuario. Por ejemplo esto se usará para autocompletar usuarios externos para compartición federada."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files/l10n/nb_NO.js b/apps/files/l10n/nb_NO.js
index 5227bf0b9ac..4b4a9e19273 100644
--- a/apps/files/l10n/nb_NO.js
+++ b/apps/files/l10n/nb_NO.js
@@ -79,7 +79,7 @@ OC.L10N.register(
"New folder" : "Ny mappe",
"{newname} already exists" : "{newname} finnes allerede",
"Upload" : "Last opp",
- "An error occurred while trying to update the tags" : "En feil oppstod under oppdatering av taggene",
+ "An error occurred while trying to update the tags" : "En feil oppstod under oppdatering av merkelappene",
"A new file or folder has been <strong>created</strong>" : "En ny fil eller mappe ble <strong>opprettet</strong>",
"A file or folder has been <strong>changed</strong>" : "En fil eller mappe ble <strong>endret</strong>",
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Begrens varsling om oppretting og endringer til <strong>favorittfilene</strong> dine <em>(Kun strøm)</em>",
diff --git a/apps/files/l10n/nb_NO.json b/apps/files/l10n/nb_NO.json
index 586850a9e8a..f3b0021dbbf 100644
--- a/apps/files/l10n/nb_NO.json
+++ b/apps/files/l10n/nb_NO.json
@@ -77,7 +77,7 @@
"New folder" : "Ny mappe",
"{newname} already exists" : "{newname} finnes allerede",
"Upload" : "Last opp",
- "An error occurred while trying to update the tags" : "En feil oppstod under oppdatering av taggene",
+ "An error occurred while trying to update the tags" : "En feil oppstod under oppdatering av merkelappene",
"A new file or folder has been <strong>created</strong>" : "En ny fil eller mappe ble <strong>opprettet</strong>",
"A file or folder has been <strong>changed</strong>" : "En fil eller mappe ble <strong>endret</strong>",
"Limit notifications about creation and changes to your <strong>favorite files</strong> <em>(Stream only)</em>" : "Begrens varsling om oppretting og endringer til <strong>favorittfilene</strong> dine <em>(Kun strøm)</em>",
diff --git a/apps/files_external/service/dbconfigservice.php b/apps/files_external/service/dbconfigservice.php
index 07f9942e05c..16d5de2665f 100644
--- a/apps/files_external/service/dbconfigservice.php
+++ b/apps/files_external/service/dbconfigservice.php
@@ -65,7 +65,7 @@ class DBConfigService {
$builder = $this->connection->getQueryBuilder();
$query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type'])
->from('external_mounts', 'm')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$mounts = $this->getMountsFromQuery($query);
if (count($mounts) > 0) {
return $mounts[0];
@@ -83,7 +83,7 @@ class DBConfigService {
$builder = $this->connection->getQueryBuilder();
$query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type'])
->from('external_mounts')
- ->where($builder->expr()->eq('type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT)));
return $this->getMountsFromQuery($query);
}
@@ -91,7 +91,7 @@ class DBConfigService {
$query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type'])
->from('external_mounts', 'm')
->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id')
- ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT)));
if (is_null($value)) {
$query = $query->andWhere($builder->expr()->isNull('a.value'));
@@ -126,7 +126,7 @@ class DBConfigService {
public function getAdminMountsFor($type, $value) {
$builder = $this->connection->getQueryBuilder();
$query = $this->getForQuery($builder, $type, $value);
- $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT)));
return $this->getMountsFromQuery($query);
}
@@ -141,15 +141,15 @@ class DBConfigService {
public function getAdminMountsForMultiple($type, array $values) {
$builder = $this->connection->getQueryBuilder();
$params = array_map(function ($value) use ($builder) {
- return $builder->createNamedParameter($value, \PDO::PARAM_STR);
+ return $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR);
}, $values);
$query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type'])
->from('external_mounts', 'm')
->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id')
- ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT)))
+ ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
->andWhere($builder->expr()->in('a.value', $params));
- $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT)));
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT)));
return $this->getMountsFromQuery($query);
}
@@ -164,7 +164,7 @@ class DBConfigService {
public function getUserMountsFor($type, $value) {
$builder = $this->connection->getQueryBuilder();
$query = $this->getForQuery($builder, $type, $value);
- $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_PERSONAl, \PDO::PARAM_INT)));
+ $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_PERSONAl, IQueryBuilder::PARAM_INT)));
return $this->getMountsFromQuery($query);
}
@@ -186,11 +186,11 @@ class DBConfigService {
$builder = $this->connection->getQueryBuilder();
$query = $builder->insert('external_mounts')
->values([
- 'mount_point' => $builder->createNamedParameter($mountPoint, \PDO::PARAM_STR),
- 'storage_backend' => $builder->createNamedParameter($storageBackend, \PDO::PARAM_STR),
- 'auth_backend' => $builder->createNamedParameter($authBackend, \PDO::PARAM_STR),
- 'priority' => $builder->createNamedParameter($priority, \PDO::PARAM_INT),
- 'type' => $builder->createNamedParameter($type, \PDO::PARAM_INT)
+ 'mount_point' => $builder->createNamedParameter($mountPoint, IQueryBuilder::PARAM_STR),
+ 'storage_backend' => $builder->createNamedParameter($storageBackend, IQueryBuilder::PARAM_STR),
+ 'auth_backend' => $builder->createNamedParameter($authBackend, IQueryBuilder::PARAM_STR),
+ 'priority' => $builder->createNamedParameter($priority, IQueryBuilder::PARAM_INT),
+ 'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT)
]);
$query->execute();
return (int)$this->connection->lastInsertId('external_mounts');
@@ -204,19 +204,19 @@ class DBConfigService {
public function removeMount($mountId) {
$builder = $this->connection->getQueryBuilder();
$query = $builder->delete('external_mounts')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
$query = $builder->delete('external_applicable')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
$query = $builder->delete('external_config')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
$query = $builder->delete('external_options')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
}
@@ -229,7 +229,7 @@ class DBConfigService {
$query = $builder->update('external_mounts')
->set('mount_point', $builder->createNamedParameter($newMountPoint))
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
}
@@ -243,7 +243,7 @@ class DBConfigService {
$query = $builder->update('external_mounts')
->set('auth_backend', $builder->createNamedParameter($newAuthBackend))
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$query->execute();
}
@@ -265,9 +265,9 @@ class DBConfigService {
if ($count === 0) {
$builder = $this->connection->getQueryBuilder();
$query = $builder->update('external_config')
- ->set('value', $builder->createNamedParameter($value, \PDO::PARAM_STR))
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
- ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR)));
+ ->set('value', $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, IQueryBuilder::PARAM_STR)));
$query->execute();
}
}
@@ -287,9 +287,9 @@ class DBConfigService {
if ($count === 0) {
$builder = $this->connection->getQueryBuilder();
$query = $builder->update('external_options')
- ->set('value', $builder->createNamedParameter(json_encode($value), \PDO::PARAM_STR))
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
- ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR)));
+ ->set('value', $builder->createNamedParameter(json_encode($value), IQueryBuilder::PARAM_STR))
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, IQueryBuilder::PARAM_STR)));
$query->execute();
}
}
@@ -305,13 +305,13 @@ class DBConfigService {
public function removeApplicable($mountId, $type, $value) {
$builder = $this->connection->getQueryBuilder();
$query = $builder->delete('external_applicable')
- ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT)))
- ->andWhere($builder->expr()->eq('type', $builder->createNamedParameter($type, \PDO::PARAM_INT)));
+ ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($builder->expr()->eq('type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT)));
if (is_null($value)) {
$query = $query->andWhere($builder->expr()->isNull('value'));
} else {
- $query = $query->andWhere($builder->expr()->eq('value', $builder->createNamedParameter($value, \PDO::PARAM_STR)));
+ $query = $query->andWhere($builder->expr()->eq('value', $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR)));
}
$query->execute();
@@ -354,7 +354,7 @@ class DBConfigService {
$builder = $this->connection->getQueryBuilder();
$fields[] = 'mount_id';
$placeHolders = array_map(function ($id) use ($builder) {
- return $builder->createPositionalParameter($id, \PDO::PARAM_INT);
+ return $builder->createPositionalParameter($id, IQueryBuilder::PARAM_INT);
}, $mountIds);
$query = $builder->select($fields)
->from($table)
diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php
index 588538fbb6c..4abd821f2ae 100644
--- a/apps/files_sharing/api/share20ocs.php
+++ b/apps/files_sharing/api/share20ocs.php
@@ -303,6 +303,15 @@ class Share20OCS {
return new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator');
}
+ /*
+ * For now we only allow 1 link share.
+ * Return the existing link share if this is a duplicate
+ */
+ $existingShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
+ if (!empty($existingShares)) {
+ return new \OC_OCS_Result($this->formatShare($existingShares[0]));
+ }
+
$publicUpload = $this->request->getParam('publicUpload', null);
if ($publicUpload === 'true') {
// Check if public upload is allowed
@@ -594,6 +603,22 @@ class Share20OCS {
}
}
+ if ($permissions !== null) {
+ /* Check if this is an incomming share */
+ $incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
+ $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
+
+ if (!empty($incomingShares)) {
+ $maxPermissions = 0;
+ foreach ($incomingShares as $incomingShare) {
+ $maxPermissions |= $incomingShare->getPermissions();
+ }
+
+ if ($share->getPermissions() & ~$maxPermissions) {
+ return new \OC_OCS_Result(null, 404, 'Cannot increase permissions');
+ }
+ }
+ }
try {
diff --git a/apps/files_sharing/l10n/es.js b/apps/files_sharing/l10n/es.js
index e2110f2b6a3..01f65761abb 100644
--- a/apps/files_sharing/l10n/es.js
+++ b/apps/files_sharing/l10n/es.js
@@ -40,10 +40,18 @@ OC.L10N.register(
"Public shared file %1$s was downloaded" : "Se descargó el archivo público compartido %1$s",
"You shared %1$s with %2$s" : "Usted compartió %1$s con %2$s",
"%2$s shared %1$s with %3$s" : "%2$s compartó %1$s con %3$s",
+ "You removed the share of %2$s for %1$s" : "Ha cambiado el compartido %2$s por %1$s",
+ "%2$s removed the share of %3$s for %1$s" : "%2$s eliminó la compartición de %3$s con %1$s",
"You shared %1$s with group %2$s" : "Usted ha compartido %1$s con el grupo %2$s",
"%2$s shared %1$s with group %3$s" : "%2$s compartió %1$s con el grupo %3$s",
+ "You removed the share of group %2$s for %1$s" : "Ha cambiado el compartido del grupo %2$s por %1$s",
+ "%2$s removed the share of group %3$s for %1$s" : "%2$s ha cambiado el compartido del grupo %3$s por %1$s",
"%2$s shared %1$s via link" : "%2$s compartió %1$s vía enlace",
"You shared %1$s via link" : "Ha compartido %1$s vía enlace",
+ "You removed the public link for %1$s" : "Ha borrado el enlace público de %1$s",
+ "%2$s removed the public link for %1$s" : "%2$s ha eliminado el enlace público de %1$s",
+ "Your public link for %1$s expired" : "Su enlace público %1$s ha expirado",
+ "The public link of %2$s for %1$s expired" : "El enlace público de %2$s para %1$s ha expirado",
"%2$s shared %1$s with you" : "%2$s ha compartido %1$s con usted",
"Downloaded via public link" : "Descargado vía enlace público",
"Shared with %2$s" : "Compartido con %2$s",
@@ -52,6 +60,8 @@ OC.L10N.register(
"Shared with group %3$s by %2$s" : "Compartido con el grupo %3$s por %2$s",
"Shared via link by %2$s" : "Compartido vía enlace por %2$s",
"Shared via public link" : "Compartido vía enlace público",
+ "Removed public link" : "Eliminado enlace público",
+ "Public link expired" : "El enlace público ha expirado",
"Shared by %2$s" : "Compartido por %2$s",
"Shares" : "Compartidos",
"Accept" : "Aceptar",
diff --git a/apps/files_sharing/l10n/es.json b/apps/files_sharing/l10n/es.json
index 4372f6c661d..bd5d497829b 100644
--- a/apps/files_sharing/l10n/es.json
+++ b/apps/files_sharing/l10n/es.json
@@ -38,10 +38,18 @@
"Public shared file %1$s was downloaded" : "Se descargó el archivo público compartido %1$s",
"You shared %1$s with %2$s" : "Usted compartió %1$s con %2$s",
"%2$s shared %1$s with %3$s" : "%2$s compartó %1$s con %3$s",
+ "You removed the share of %2$s for %1$s" : "Ha cambiado el compartido %2$s por %1$s",
+ "%2$s removed the share of %3$s for %1$s" : "%2$s eliminó la compartición de %3$s con %1$s",
"You shared %1$s with group %2$s" : "Usted ha compartido %1$s con el grupo %2$s",
"%2$s shared %1$s with group %3$s" : "%2$s compartió %1$s con el grupo %3$s",
+ "You removed the share of group %2$s for %1$s" : "Ha cambiado el compartido del grupo %2$s por %1$s",
+ "%2$s removed the share of group %3$s for %1$s" : "%2$s ha cambiado el compartido del grupo %3$s por %1$s",
"%2$s shared %1$s via link" : "%2$s compartió %1$s vía enlace",
"You shared %1$s via link" : "Ha compartido %1$s vía enlace",
+ "You removed the public link for %1$s" : "Ha borrado el enlace público de %1$s",
+ "%2$s removed the public link for %1$s" : "%2$s ha eliminado el enlace público de %1$s",
+ "Your public link for %1$s expired" : "Su enlace público %1$s ha expirado",
+ "The public link of %2$s for %1$s expired" : "El enlace público de %2$s para %1$s ha expirado",
"%2$s shared %1$s with you" : "%2$s ha compartido %1$s con usted",
"Downloaded via public link" : "Descargado vía enlace público",
"Shared with %2$s" : "Compartido con %2$s",
@@ -50,6 +58,8 @@
"Shared with group %3$s by %2$s" : "Compartido con el grupo %3$s por %2$s",
"Shared via link by %2$s" : "Compartido vía enlace por %2$s",
"Shared via public link" : "Compartido vía enlace público",
+ "Removed public link" : "Eliminado enlace público",
+ "Public link expired" : "El enlace público ha expirado",
"Shared by %2$s" : "Compartido por %2$s",
"Shares" : "Compartidos",
"Accept" : "Aceptar",
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 101503a03fb..600599d7175 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -725,4 +725,8 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
list($targetStorage) = $this->ownerView->resolvePath($ownerPath);
return $targetStorage->isLocal();
}
+
+ public function getSourceStorage() {
+ return $this->sourceStorage;
+ }
}
diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php
index 057df20a5a4..81db3b96333 100644
--- a/apps/files_sharing/tests/api/share20ocstest.php
+++ b/apps/files_sharing/tests/api/share20ocstest.php
@@ -1433,6 +1433,8 @@ class Share20OCSTest extends \Test\TestCase {
})
)->will($this->returnArgument(0));
+ $this->shareManager->method('getSharedWith')->willReturn([]);
+
$expected = new \OC_OCS_Result(null);
$result = $ocs->updateShare(42);
@@ -1498,6 +1500,8 @@ class Share20OCSTest extends \Test\TestCase {
})
)->will($this->returnArgument(0));
+ $this->shareManager->method('getSharedWith')->willReturn([]);
+
$expected = new \OC_OCS_Result(null);
$result = $ocs->updateShare(42);
diff --git a/apps/systemtags/l10n/es.js b/apps/systemtags/l10n/es.js
index 7ed27b6c085..56941f3f5da 100644
--- a/apps/systemtags/l10n/es.js
+++ b/apps/systemtags/l10n/es.js
@@ -1,7 +1,21 @@
OC.L10N.register(
"systemtags",
{
+ "<strong>System tags</strong> for a file have been modified" : "Se han modificado las <strong>etiquetas de sistema</strong> de un archivo",
+ "%1$s assigned system tag %3$s" : "%1$s asignó la etiqueta de sistema %3$s",
+ "%1$s unassigned system tag %3$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s",
+ "%1$s created system tag %2$s" : "%1$s creó la etiqueta de sistema %2$s",
+ "%1$s deleted system tag %2$s" : "%1$s eliminó la etiqueta de sistema %2$s",
+ "%1$s updated system tag %3$s to %2$s" : "%1$s actualizó la etiqueta de sistema %3$s a %2$s",
+ "%1$s assigned system tag %3$s to %2$s" : "%1$s asignó la etiqueta de sistema %3$s a %2$s",
+ "%1$s unassigned system tag %3$s from %2$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s de %2$s",
+ "%s (not-assignable)" : "%s (no asignable)",
+ "%s (invisible)" : "%s (invisible)",
"Tags" : "Etiquetas",
+ "Tagged files" : "Archivos etiquetados",
+ "Select tags to filter by" : "Seleccionar etiquetas por las que filtrar",
+ "Please select tags to filter by" : "Por favor, seleccione las etiquetas por las que desea filtrar",
+ "No files found for the selected tags" : "No se han encontrado archivos para las etiquetas seleccionadas",
"No files in here" : "Aquí no hay archivos",
"No entries found in this folder" : "No hay entradas en esta carpeta",
"Name" : "Nombre",
diff --git a/apps/systemtags/l10n/es.json b/apps/systemtags/l10n/es.json
index 038cf956fb3..e5ad1d78fef 100644
--- a/apps/systemtags/l10n/es.json
+++ b/apps/systemtags/l10n/es.json
@@ -1,5 +1,19 @@
{ "translations": {
+ "<strong>System tags</strong> for a file have been modified" : "Se han modificado las <strong>etiquetas de sistema</strong> de un archivo",
+ "%1$s assigned system tag %3$s" : "%1$s asignó la etiqueta de sistema %3$s",
+ "%1$s unassigned system tag %3$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s",
+ "%1$s created system tag %2$s" : "%1$s creó la etiqueta de sistema %2$s",
+ "%1$s deleted system tag %2$s" : "%1$s eliminó la etiqueta de sistema %2$s",
+ "%1$s updated system tag %3$s to %2$s" : "%1$s actualizó la etiqueta de sistema %3$s a %2$s",
+ "%1$s assigned system tag %3$s to %2$s" : "%1$s asignó la etiqueta de sistema %3$s a %2$s",
+ "%1$s unassigned system tag %3$s from %2$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s de %2$s",
+ "%s (not-assignable)" : "%s (no asignable)",
+ "%s (invisible)" : "%s (invisible)",
"Tags" : "Etiquetas",
+ "Tagged files" : "Archivos etiquetados",
+ "Select tags to filter by" : "Seleccionar etiquetas por las que filtrar",
+ "Please select tags to filter by" : "Por favor, seleccione las etiquetas por las que desea filtrar",
+ "No files found for the selected tags" : "No se han encontrado archivos para las etiquetas seleccionadas",
"No files in here" : "Aquí no hay archivos",
"No entries found in this folder" : "No hay entradas en esta carpeta",
"Name" : "Nombre",