Merge branch 'master' into master
This commit is contained in:
commit
63974992f9
|
@ -1,4 +1,3 @@
|
|||
# Version: 9.0.0
|
||||
<IfModule mod_headers.c>
|
||||
<IfModule mod_fcgid.c>
|
||||
<IfModule mod_setenvif.c>
|
||||
|
@ -51,9 +50,6 @@
|
|||
|
||||
# Rewrite rules for `front_controller_active`
|
||||
Options -MultiViews
|
||||
<IfModule mod_dir.c>
|
||||
DirectorySlash off
|
||||
</IfModule>
|
||||
RewriteRule ^core/js/oc.js$ index.php/core/js/oc.js [PT,E=PATH_INFO:$1]
|
||||
RewriteRule ^core/preview.png$ index.php/core/preview.png [PT,E=PATH_INFO:$1]
|
||||
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff)$
|
||||
|
|
3
.mailmap
3
.mailmap
|
@ -305,7 +305,8 @@ Robin Appelman <icewind@owncloud.com> Robin <robin@Amaya.(none)>
|
|||
Robin Appelman <icewind@owncloud.com> Robin Appelman <icewind1991@gmail.com>
|
||||
Robin Appelman <icewind@owncloud.com> Robin Appelman <icewind1991@gmail>
|
||||
Robin Appelman <icewind@owncloud.com> Robin Appelman <robin@icewind.nl>
|
||||
Robin McCorkell <rmccorkell@karoshi.org.uk> Robin McCorkell <rmccorkell@owncloud.com>
|
||||
Robin McCorkell <robin@mccorkell.me.uk> Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
Robin McCorkell <robin@mccorkell.me.uk> Robin McCorkell <rmccorkell@owncloud.com>
|
||||
Rodrigo Hjort <rodrigo.hjort@gmail.com>
|
||||
Roeland Jago Douma <rullzer@owncloud.com> Roeland Jago Douma <roeland@famdouma.nl>
|
||||
rok <brejktru@gmail.com>
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
{
|
||||
"name": "DeepDiver1975",
|
||||
"files": ["apps/dav/**"]
|
||||
},
|
||||
{
|
||||
"name": "Xenopathic",
|
||||
"files": ["apps/files_external/**"]
|
||||
}
|
||||
],
|
||||
"userBlacklist": ["owncloud-bot"]
|
||||
"userBlacklist": ["owncloud-bot", "scrutinizer-auto-fixer"]
|
||||
}
|
||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -25,22 +25,22 @@ before_install:
|
|||
|
||||
install:
|
||||
- sh -c "if [ '$TEST_DAV' = '1' ]; then bash tests/travis/install.sh $DB; fi"
|
||||
- sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC/install.sh; fi"
|
||||
|
||||
|
||||
script:
|
||||
- sh -c "if [ '$TEST_DAV' != '1' ]; then echo \"Not testing DAV\"; fi"
|
||||
- sh -c "if [ '$TEST_DAV' = '1' ]; then echo \"Testing DAV\"; fi"
|
||||
|
||||
- sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC.sh; fi"
|
||||
- sh -c "if [ '$TEST_DAV' = '1' ]; then bash apps/dav/tests/travis/$TC/script.sh; fi"
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.4
|
||||
env: DB=pgsql;TC=litmus-v1
|
||||
- php: 5.4
|
||||
env: DB=sqlite;TC=carddavtester
|
||||
# - php: 5.4
|
||||
# env: DB=pgsql;TC=carddavtester
|
||||
# - php: 5.4
|
||||
# env: DB=mysql;TC=caldavtester
|
||||
env: DB=sqlite;TC=carddav
|
||||
- php: 5.4
|
||||
env: DB=sqlite;TC=caldav
|
||||
|
||||
fast_finish: true
|
||||
|
|
2
3rdparty
2
3rdparty
|
@ -1 +1 @@
|
|||
Subproject commit a7b34d6f831c8fa363f389d27acd0150128fc0b9
|
||||
Subproject commit a5b2a3cdb03cbf5a7246c6185cd4d473f697803e
|
|
@ -18,20 +18,8 @@ If you have questions about how to install or use ownCloud, please direct these
|
|||
- [iOS client](https://github.com/owncloud/ios/issues)
|
||||
- [Desktop client](https://github.com/owncloud/client/issues)
|
||||
- [Documentation](https://github.com/owncloud/documentation/issues)
|
||||
- Apps:
|
||||
- [Activity](https://github.com/owncloud/activity/issues)
|
||||
- [Bookmarks](https://github.com/owncloud/bookmarks/issues)
|
||||
- [Calendar](https://github.com/owncloud/calendar/issues)
|
||||
- [Contacts](https://github.com/owncloud/contacts/issues)
|
||||
- [Documents](https://github.com/owncloud/documents/issues)
|
||||
- [Gallery](https://github.com/owncloud/gallery/issues)
|
||||
- [Mail](https://github.com/owncloud/mail/issues)
|
||||
- [Music](https://github.com/owncloud/music/issues)
|
||||
- [News](https://github.com/owncloud/news/issues)
|
||||
- [Notes](https://github.com/owncloud/notes/issues)
|
||||
- [Shorty](https://github.com/owncloud/shorty/issues)
|
||||
- [Tasks](https://github.com/owncloud/tasks/issues)
|
||||
- [All other apps](https://github.com/owncloud/apps/issues)
|
||||
- [ownCloud apps](https://github.com/owncloud/core/wiki/Maintainers#apps-repo)
|
||||
|
||||
* Report the issue using our [template][template], it includes all the information we need to track down the issue.
|
||||
|
||||
Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.
|
||||
|
|
|
@ -27,10 +27,14 @@ https://doc.owncloud.org/server/9.0/developer_manual/app/index.html
|
|||
## Contribution Guidelines
|
||||
https://owncloud.org/contribute/
|
||||
|
||||
## Support
|
||||
Learn about the diffrent ways you can get support for ownCloud: https://owncloud.org/support/
|
||||
|
||||
## Get in touch
|
||||
* :clipboard: [Forum](https://forum.owncloud.org)
|
||||
* :envelope: [Mailing list](https://mailman.owncloud.org/mailman/listinfo)
|
||||
* :busts_in_silhouette: [IRC channel](https://webchat.freenode.net/?channels=owncloud)
|
||||
* :hash: [IRC channel](https://webchat.freenode.net/?channels=owncloud)
|
||||
* :busts_in_silhouette: [Facebook] (https://facebook.com/ownclouders)
|
||||
* :hatching_chick: [Twitter](https://twitter.com/ownClouders)
|
||||
|
||||
## Important notice on translations
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?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/>
|
||||
*
|
||||
*/
|
||||
|
||||
$cm = \OC::$server->getContactsManager();
|
||||
$cm->register(function() use ($cm) {
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$userId = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$principal = new \OCA\DAV\Connector\Sabre\Principal(
|
||||
\OC::$server->getConfig(),
|
||||
\OC::$server->getUserManager()
|
||||
);
|
||||
$cardDav = new \OCA\DAV\CardDAV\CardDavBackend($db, $principal, \OC::$server->getLogger());
|
||||
$addressBooks = $cardDav->getAddressBooksForUser("principals/$userId");
|
||||
foreach ($addressBooks as $addressBookInfo) {
|
||||
$addressBook = new \OCA\DAV\CardDAV\AddressBook($cardDav, $addressBookInfo);
|
||||
$cm->registerAddressBook(
|
||||
new OCA\DAV\CardDAV\AddressBookImpl(
|
||||
$addressBook,
|
||||
$addressBookInfo,
|
||||
$cardDav
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
|
@ -571,6 +571,78 @@ CREATE TABLE calendarobjects (
|
|||
</declaration>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<name>*dbprefix*cards_properties</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></default>
|
||||
<notnull>true</notnull>
|
||||
<length>11</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>cardid</name>
|
||||
<type>integer</type>
|
||||
<default></default>
|
||||
<notnull>true</notnull>
|
||||
<unsigned>true</unsigned>
|
||||
<length>11</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>name</name>
|
||||
<type>text</type>
|
||||
<default></default>
|
||||
<notnull>false</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>value</name>
|
||||
<type>text</type>
|
||||
<default></default>
|
||||
<notnull>false</notnull>
|
||||
<length>255</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>preferred</name>
|
||||
<type>integer</type>
|
||||
<default>1</default>
|
||||
<notnull>true</notnull>
|
||||
<length>4</length>
|
||||
</field>
|
||||
<index>
|
||||
<name>card_contactid_index</name>
|
||||
<field>
|
||||
<name>cardid</name>
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>card_name_index</name>
|
||||
<field>
|
||||
<name>name</name>
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>card_value_index</name>
|
||||
<field>
|
||||
<name>value</name>
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<name>*dbprefix*dav_shares</name>
|
||||
<declaration>
|
||||
|
|
|
@ -8,8 +8,9 @@ $config = \OC::$server->getConfig();
|
|||
$dbConnection = \OC::$server->getDatabaseConnection();
|
||||
$userManager = OC::$server->getUserManager();
|
||||
$config = \OC::$server->getConfig();
|
||||
$logger = \OC::$server->getLogger();
|
||||
|
||||
/** @var Symfony\Component\Console\Application $application */
|
||||
$application->add(new CreateAddressBook($userManager, $dbConnection, $config));
|
||||
$application->add(new CreateAddressBook($userManager, $dbConnection, $config, $logger));
|
||||
$application->add(new CreateCalendar($userManager, $dbConnection));
|
||||
$application->add(new SyncSystemAddressBook($userManager, $dbConnection, $config));
|
||||
|
|
|
@ -6,6 +6,7 @@ use OCA\DAV\CardDAV\CardDavBackend;
|
|||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUserManager;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
@ -23,15 +24,25 @@ class CreateAddressBook extends Command {
|
|||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @param IUserManager $userManager
|
||||
* @param IDBConnection $dbConnection
|
||||
* @param IConfig $config
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
function __construct(IUserManager $userManager, IDBConnection $dbConnection, IConfig $config) {
|
||||
function __construct(IUserManager $userManager,
|
||||
IDBConnection $dbConnection,
|
||||
IConfig $config,
|
||||
ILogger $logger
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->userManager = $userManager;
|
||||
$this->dbConnection = $dbConnection;
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Björn Schießle <schiessle@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\CardDAV;
|
||||
|
||||
use OCP\Constants;
|
||||
use OCP\IAddressBook;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
use Sabre\VObject\Reader;
|
||||
use Sabre\VObject\UUIDUtil;
|
||||
|
||||
class AddressBookImpl implements IAddressBook {
|
||||
|
||||
/** @var CardDavBackend */
|
||||
private $backend;
|
||||
|
||||
/** @var array */
|
||||
private $addressBookInfo;
|
||||
|
||||
/** @var AddressBook */
|
||||
private $addressBook;
|
||||
|
||||
/**
|
||||
* AddressBookImpl constructor.
|
||||
*
|
||||
* @param AddressBook $addressBook
|
||||
* @param array $addressBookInfo
|
||||
* @param CardDavBackend $backend
|
||||
*/
|
||||
public function __construct(
|
||||
AddressBook $addressBook,
|
||||
array $addressBookInfo,
|
||||
CardDavBackend $backend) {
|
||||
|
||||
$this->addressBook = $addressBook;
|
||||
$this->addressBookInfo = $addressBookInfo;
|
||||
$this->backend = $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string defining the technical unique key
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function getKey() {
|
||||
return $this->addressBookInfo['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* In comparison to getKey() this function returns a human readable (maybe translated) name
|
||||
*
|
||||
* @return mixed
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function getDisplayName() {
|
||||
return $this->addressBookInfo['{DAV:}displayname'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pattern which should match within the $searchProperties
|
||||
* @param array $searchProperties defines the properties within the query pattern should match
|
||||
* @param array $options - for future use. One should always have options!
|
||||
* @return array an array of contacts which are arrays of key-value-pairs
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function search($pattern, $searchProperties, $options) {
|
||||
$result = $this->backend->search($this->getKey(), $pattern, $searchProperties);
|
||||
|
||||
$vCards = [];
|
||||
foreach ($result as $cardData) {
|
||||
$vCards[] = $this->vCard2Array($this->readCard($cardData));
|
||||
}
|
||||
|
||||
return $vCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $properties this array if key-value-pairs defines a contact
|
||||
* @return array an array representing the contact just created or updated
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function createOrUpdate($properties) {
|
||||
$update = false;
|
||||
if (!isset($properties['UID'])) { // create a new contact
|
||||
$uid = $this->createUid();
|
||||
$uri = $uid . '.vcf';
|
||||
$vCard = $this->createEmptyVCard($uid);
|
||||
} else { // update existing contact
|
||||
$uid = $properties['UID'];
|
||||
$uri = $uid . '.vcf';
|
||||
$vCardData = $this->backend->getCard($this->getKey(), $uri);
|
||||
$vCard = $this->readCard($vCardData['carddata']);
|
||||
$update = true;
|
||||
}
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
$vCard->$key = $vCard->createProperty($key, $value);
|
||||
}
|
||||
|
||||
if ($update) {
|
||||
$this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
|
||||
} else {
|
||||
$this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
|
||||
}
|
||||
|
||||
return $this->vCard2Array($vCard);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function getPermissions() {
|
||||
$permissions = $this->addressBook->getACL();
|
||||
$result = 0;
|
||||
foreach ($permissions as $permission) {
|
||||
switch($permission['privilege']) {
|
||||
case '{DAV:}read':
|
||||
$result |= Constants::PERMISSION_READ;
|
||||
break;
|
||||
case '{DAV:}write':
|
||||
$result |= Constants::PERMISSION_CREATE;
|
||||
$result |= Constants::PERMISSION_UPDATE;
|
||||
break;
|
||||
case '{DAV:}all':
|
||||
$result |= Constants::PERMISSION_ALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $id the unique identifier to a contact
|
||||
* @return bool successful or not
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function delete($id) {
|
||||
$uri = $this->backend->getCardUri($id);
|
||||
return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* read vCard data into a vCard object
|
||||
*
|
||||
* @param string $cardData
|
||||
* @return VCard
|
||||
*/
|
||||
protected function readCard($cardData) {
|
||||
return Reader::read($cardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* create UID for contact
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function createUid() {
|
||||
do {
|
||||
$uid = $this->getUid();
|
||||
} while (!empty($this->backend->getContact($uid . '.vcf')));
|
||||
|
||||
return $uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* getUid is only there for testing, use createUid instead
|
||||
*/
|
||||
protected function getUid() {
|
||||
return UUIDUtil::getUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* create empty vcard
|
||||
*
|
||||
* @param string $uid
|
||||
* @return VCard
|
||||
*/
|
||||
protected function createEmptyVCard($uid) {
|
||||
$vCard = new VCard();
|
||||
$vCard->add(new Text($vCard, 'UID', $uid));
|
||||
return $vCard;
|
||||
}
|
||||
|
||||
/**
|
||||
* create array with all vCard properties
|
||||
*
|
||||
* @param VCard $vCard
|
||||
* @return array
|
||||
*/
|
||||
protected function vCard2Array(VCard $vCard) {
|
||||
$result = [];
|
||||
foreach ($vCard->children as $property) {
|
||||
$result[$property->name] = $property->getValue();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -23,19 +23,48 @@
|
|||
namespace OCA\DAV\CardDAV;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use Sabre\CardDAV\Backend\BackendInterface;
|
||||
use Sabre\CardDAV\Backend\SyncSupport;
|
||||
use Sabre\CardDAV\Plugin;
|
||||
use Sabre\DAV\Exception\BadRequest;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Reader;
|
||||
|
||||
class CardDavBackend implements BackendInterface, SyncSupport {
|
||||
|
||||
/** @var Principal */
|
||||
private $principalBackend;
|
||||
|
||||
public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) {
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var string */
|
||||
private $dbCardsTable = 'cards';
|
||||
|
||||
/** @var string */
|
||||
private $dbCardsPropertiesTable = 'cards_properties';
|
||||
|
||||
/** @var IDBConnection */
|
||||
private $db;
|
||||
|
||||
/** @var array properties to index */
|
||||
public static $indexProperties = array(
|
||||
'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
|
||||
'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD');
|
||||
|
||||
/**
|
||||
* CardDavBackend constructor.
|
||||
*
|
||||
* @param IDBConnection $db
|
||||
* @param Principal $principalBackend
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function __construct(IDBConnection $db, Principal $principalBackend, ILogger $logger) {
|
||||
$this->db = $db;
|
||||
$this->principalBackend = $principalBackend;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,6 +292,11 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressBookId)))
|
||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
||||
->execute();
|
||||
|
||||
$query->delete($this->dbCardsPropertiesTable)
|
||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||
->execute();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,7 +432,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('cards')
|
||||
->values([
|
||||
'carddata' => $query->createNamedParameter($cardData),
|
||||
'carddata' => $query->createNamedParameter($cardData, \PDO::PARAM_LOB),
|
||||
'uri' => $query->createNamedParameter($cardUri),
|
||||
'lastmodified' => $query->createNamedParameter(time()),
|
||||
'addressbookid' => $query->createNamedParameter($addressBookId),
|
||||
|
@ -408,6 +442,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
->execute();
|
||||
|
||||
$this->addChange($addressBookId, $cardUri, 1);
|
||||
$this->updateProperties($addressBookId, $cardUri, $cardData);
|
||||
|
||||
return '"' . $etag . '"';
|
||||
}
|
||||
|
@ -451,6 +486,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
->execute();
|
||||
|
||||
$this->addChange($addressBookId, $cardUri, 2);
|
||||
$this->updateProperties($addressBookId, $cardUri, $cardData);
|
||||
|
||||
return '"' . $etag . '"';
|
||||
}
|
||||
|
@ -463,6 +499,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
* @return bool
|
||||
*/
|
||||
function deleteCard($addressBookId, $cardUri) {
|
||||
$cardId = $this->getCardId($cardUri);
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$ret = $query->delete('cards')
|
||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||
|
@ -471,7 +508,12 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
|
||||
$this->addChange($addressBookId, $cardUri, 3);
|
||||
|
||||
return $ret === 1;
|
||||
if ($ret === 1) {
|
||||
$this->purgeProperties($addressBookId, $cardId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -637,6 +679,87 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* search contact
|
||||
*
|
||||
* @param int $addressBookId
|
||||
* @param string $pattern which should match within the $searchProperties
|
||||
* @param array $searchProperties defines the properties within the query pattern should match
|
||||
* @return array an array of contacts which are arrays of key-value-pairs
|
||||
*/
|
||||
public function search($addressBookId, $pattern, $searchProperties) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query2 = $this->db->getQueryBuilder();
|
||||
$query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
|
||||
foreach ($searchProperties as $property) {
|
||||
$query2->orWhere(
|
||||
$query2->expr()->andX(
|
||||
$query2->expr()->eq('cp.name', $query->createNamedParameter($property)),
|
||||
$query2->expr()->like('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%'))
|
||||
)
|
||||
);
|
||||
}
|
||||
$query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
|
||||
|
||||
$query->select('c.carddata')->from($this->dbCardsTable, 'c')
|
||||
->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
|
||||
|
||||
$result = $query->execute();
|
||||
$cards = $result->fetchAll();
|
||||
|
||||
$result->closeCursor();
|
||||
|
||||
return array_map(function($array) {return $this->readBlob($array['carddata']);}, $cards);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get URI from a given contact
|
||||
*
|
||||
* @param int $id
|
||||
* @return string
|
||||
*/
|
||||
public function getCardUri($id) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('uri')->from($this->dbCardsTable)
|
||||
->where($query->expr()->eq('id', $query->createParameter('id')))
|
||||
->setParameter('id', $id);
|
||||
|
||||
$result = $query->execute();
|
||||
$uri = $result->fetch();
|
||||
$result->closeCursor();
|
||||
|
||||
if (!isset($uri['uri'])) {
|
||||
throw new \InvalidArgumentException('Card does not exists: ' . $id);
|
||||
}
|
||||
|
||||
return $uri['uri'];
|
||||
}
|
||||
|
||||
/**
|
||||
* return contact with the given URI
|
||||
*
|
||||
* @param string $uri
|
||||
* @returns array
|
||||
*/
|
||||
public function getContact($uri) {
|
||||
$result = [];
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('*')->from($this->dbCardsTable)
|
||||
->where($query->expr()->eq('uri', $query->createParameter('uri')))
|
||||
->setParameter('uri', $uri);
|
||||
$queryResult = $query->execute();
|
||||
$contact = $queryResult->fetch();
|
||||
$queryResult->closeCursor();
|
||||
|
||||
if (is_array($contact)) {
|
||||
$result = $contact;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $addressBookUri
|
||||
* @param string $element
|
||||
|
@ -658,7 +781,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
}
|
||||
|
||||
// remove the share if it already exists
|
||||
$this->unshare($addressBookUri, $element);
|
||||
$this->unshare($addressBookUri, $element['href']);
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('dav_shares')
|
||||
|
@ -677,8 +800,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
* @param string $element
|
||||
*/
|
||||
private function unshare($addressBookUri, $element) {
|
||||
$user = $element['href'];
|
||||
$parts = explode(':', $user, 2);
|
||||
$parts = explode(':', $element, 2);
|
||||
if ($parts[0] !== 'principal') {
|
||||
return;
|
||||
}
|
||||
|
@ -734,4 +856,93 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
|||
|
||||
return $shares;
|
||||
}
|
||||
|
||||
/**
|
||||
* update properties table
|
||||
*
|
||||
* @param int $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $vCardSerialized
|
||||
*/
|
||||
protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
|
||||
$cardId = $this->getCardId($cardUri);
|
||||
$vCard = $this->readCard($vCardSerialized);
|
||||
|
||||
$this->purgeProperties($addressBookId, $cardId);
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert($this->dbCardsPropertiesTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter($addressBookId),
|
||||
'cardid' => $query->createNamedParameter($cardId),
|
||||
'name' => $query->createParameter('name'),
|
||||
'value' => $query->createParameter('value'),
|
||||
'preferred' => $query->createParameter('preferred')
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($vCard->children as $property) {
|
||||
if(!in_array($property->name, self::$indexProperties)) {
|
||||
continue;
|
||||
}
|
||||
$preferred = 0;
|
||||
foreach($property->parameters as $parameter) {
|
||||
if ($parameter->name == 'TYPE' && strtoupper($parameter->getValue()) == 'PREF') {
|
||||
$preferred = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$query->setParameter('name', $property->name);
|
||||
$query->setParameter('value', substr($property->getValue(), 0, 254));
|
||||
$query->setParameter('preferred', $preferred);
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read vCard data into a vCard object
|
||||
*
|
||||
* @param string $cardData
|
||||
* @return VCard
|
||||
*/
|
||||
protected function readCard($cardData) {
|
||||
return Reader::read($cardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete all properties from a given card
|
||||
*
|
||||
* @param int $addressBookId
|
||||
* @param int $cardId
|
||||
*/
|
||||
protected function purgeProperties($addressBookId, $cardId) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete($this->dbCardsPropertiesTable)
|
||||
->where($query->expr()->eq('cardid', $query->createNamedParameter($cardId)))
|
||||
->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* get ID from a given contact
|
||||
*
|
||||
* @param string $uri
|
||||
* @return int
|
||||
*/
|
||||
protected function getCardId($uri) {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->select('id')->from($this->dbCardsTable)
|
||||
->where($query->expr()->eq('uri', $query->createNamedParameter($uri)));
|
||||
|
||||
$result = $query->execute();
|
||||
$cardIds = $result->fetch();
|
||||
$result->closeCursor();
|
||||
|
||||
if (!isset($cardIds['id'])) {
|
||||
throw new \InvalidArgumentException('Card does not exists: ' . $uri);
|
||||
}
|
||||
|
||||
return (int)$cardIds['id'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,24 @@ use Sabre\DAV\Exception\NotFound;
|
|||
use Sabre\DAV\Server;
|
||||
use Sabre\DAV\ServerPlugin;
|
||||
use Sabre\DAV\XMLUtil;
|
||||
use Sabre\DAVACL\IACL;
|
||||
use Sabre\HTTP\RequestInterface;
|
||||
use Sabre\HTTP\ResponseInterface;
|
||||
|
||||
class Plugin extends ServerPlugin {
|
||||
|
||||
/** @var Auth */
|
||||
private $auth;
|
||||
|
||||
/** @var IRequest */
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* Plugin constructor.
|
||||
*
|
||||
* @param Auth $authBackEnd
|
||||
* @param IRequest $request
|
||||
*/
|
||||
public function __construct(Auth $authBackEnd, IRequest $request) {
|
||||
$this->auth = $authBackEnd;
|
||||
$this->request = $request;
|
||||
|
@ -68,6 +81,7 @@ class Plugin extends ServerPlugin {
|
|||
function initialize(Server $server) {
|
||||
$this->server = $server;
|
||||
$server->resourceTypeMapping['OCA\\DAV\CardDAV\\ISharedAddressbook'] = '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}shared';
|
||||
$this->server->xml->elementMap['{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}share'] = 'OCA\\DAV\\CardDAV\\Sharing\\Xml\\ShareRequest';
|
||||
|
||||
$this->server->on('method:POST', [$this, 'httpPost']);
|
||||
}
|
||||
|
@ -109,9 +123,7 @@ class Plugin extends ServerPlugin {
|
|||
// re-populated the request body with the existing data.
|
||||
$request->setBody($requestBody);
|
||||
|
||||
$dom = XMLUtil::loadDOMDocument($requestBody);
|
||||
|
||||
$documentType = XMLUtil::toClarkNotation($dom->firstChild);
|
||||
$message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType);
|
||||
|
||||
switch ($documentType) {
|
||||
|
||||
|
@ -124,19 +136,18 @@ class Plugin extends ServerPlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
$this->server->transactionType = 'post-calendar-share';
|
||||
$this->server->transactionType = 'post-oc-addressbook-share';
|
||||
|
||||
// Getting ACL info
|
||||
$acl = $this->server->getPlugin('acl');
|
||||
|
||||
// If there's no ACL support, we allow everything
|
||||
if ($acl) {
|
||||
/** @var \Sabre\DAVACL\Plugin $acl */
|
||||
$acl->checkPrivileges($path, '{DAV:}write');
|
||||
}
|
||||
|
||||
$mutations = $this->parseShareRequest($dom);
|
||||
|
||||
$node->updateShares($mutations[0], $mutations[1]);
|
||||
$node->updateShares($message->set, $message->remove);
|
||||
|
||||
$response->setStatus(200);
|
||||
// Adding this because sending a response body may cause issues,
|
||||
|
@ -148,59 +159,6 @@ class Plugin extends ServerPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the 'share' POST request.
|
||||
*
|
||||
* This method returns an array, containing two arrays.
|
||||
* The first array is a list of new sharees. Every element is a struct
|
||||
* containing a:
|
||||
* * href element. (usually a mailto: address)
|
||||
* * commonName element (often a first and lastname, but can also be
|
||||
* false)
|
||||
* * readOnly (true or false)
|
||||
* * summary (A description of the share, can also be false)
|
||||
*
|
||||
* The second array is a list of sharees that are to be removed. This is
|
||||
* just a simple array with 'hrefs'.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
* @return array
|
||||
*/
|
||||
function parseShareRequest(\DOMDocument $dom) {
|
||||
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$xpath->registerNamespace('cs', \Sabre\CardDAV\Plugin::NS_CARDDAV);
|
||||
$xpath->registerNamespace('d', 'urn:DAV');
|
||||
|
||||
$set = [];
|
||||
$elems = $xpath->query('cs:set');
|
||||
|
||||
for ($i = 0; $i < $elems->length; $i++) {
|
||||
|
||||
$xset = $elems->item($i);
|
||||
$set[] = [
|
||||
'href' => $xpath->evaluate('string(d:href)', $xset),
|
||||
'commonName' => $xpath->evaluate('string(cs:common-name)', $xset),
|
||||
'summary' => $xpath->evaluate('string(cs:summary)', $xset),
|
||||
'readOnly' => $xpath->evaluate('boolean(cs:read)', $xset) !== false
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
$remove = [];
|
||||
$elems = $xpath->query('cs:remove');
|
||||
|
||||
for ($i = 0; $i < $elems->length; $i++) {
|
||||
|
||||
$xremove = $elems->item($i);
|
||||
$remove[] = $xpath->evaluate('string(d:href)', $xremove);
|
||||
|
||||
}
|
||||
|
||||
return [$set, $remove];
|
||||
|
||||
}
|
||||
|
||||
private function protectAgainstCSRF() {
|
||||
$user = $this->auth->getCurrentUser();
|
||||
if ($this->auth->isDavAuthenticated($user)) {
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\DAV\CardDAV\Sharing\Xml;
|
||||
|
||||
use Sabre\Xml\Reader;
|
||||
use Sabre\Xml\XmlDeserializable;
|
||||
|
||||
class ShareRequest implements XmlDeserializable {
|
||||
|
||||
public $set = [];
|
||||
|
||||
public $remove = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $set
|
||||
* @param array $remove
|
||||
*/
|
||||
function __construct(array $set, array $remove) {
|
||||
|
||||
$this->set = $set;
|
||||
$this->remove = $remove;
|
||||
|
||||
}
|
||||
|
||||
static function xmlDeserialize(Reader $reader) {
|
||||
|
||||
$elems = $reader->parseInnerTree([
|
||||
'{' . \Sabre\CardDAV\Plugin::NS_CARDDAV. '}set' => 'Sabre\\Xml\\Element\\KeyValue',
|
||||
'{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}remove' => 'Sabre\\Xml\\Element\\KeyValue',
|
||||
]);
|
||||
|
||||
$set = [];
|
||||
$remove = [];
|
||||
|
||||
foreach ($elems as $elem) {
|
||||
switch ($elem['name']) {
|
||||
|
||||
case '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}set' :
|
||||
$sharee = $elem['value'];
|
||||
|
||||
$sumElem = '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}summary';
|
||||
$commonName = '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}common-name';
|
||||
|
||||
$set[] = [
|
||||
'href' => $sharee['{DAV:}href'],
|
||||
'commonName' => isset($sharee[$commonName]) ? $sharee[$commonName] : null,
|
||||
'summary' => isset($sharee[$sumElem]) ? $sharee[$sumElem] : null,
|
||||
'readOnly' => !array_key_exists('{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}read-write', $sharee),
|
||||
];
|
||||
break;
|
||||
|
||||
case '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}remove' :
|
||||
$remove[] = $elem['value']['{DAV:}href'];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return new self($set, $remove);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -160,7 +160,7 @@ class Auth extends AbstractBasic {
|
|||
return [true, $this->principalPrefix . $user];
|
||||
}
|
||||
|
||||
if (!$this->userSession->isLoggedIn() && $request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
|
||||
if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
|
||||
// do not re-authenticate over ajax, use dummy auth name to prevent browser popup
|
||||
$response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
|
||||
$response->setStatus(401);
|
||||
|
|
|
@ -329,7 +329,7 @@ class File extends Node implements IFile {
|
|||
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
|
||||
return $mimeType;
|
||||
}
|
||||
return \OC_Helper::getSecureMimeType($mimeType);
|
||||
return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,7 @@ use \Sabre\DAV\PropFind;
|
|||
use \Sabre\DAV\PropPatch;
|
||||
use \Sabre\HTTP\RequestInterface;
|
||||
use \Sabre\HTTP\ResponseInterface;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
|
||||
class FilesPlugin extends \Sabre\DAV\ServerPlugin {
|
||||
|
||||
|
@ -225,9 +226,13 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
|
||||
$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
|
||||
/** @var $node \OCA\DAV\Connector\Sabre\File */
|
||||
$directDownloadUrl = $node->getDirectDownload();
|
||||
if (isset($directDownloadUrl['url'])) {
|
||||
return $directDownloadUrl['url'];
|
||||
try {
|
||||
$directDownloadUrl = $node->getDirectDownload();
|
||||
if (isset($directDownloadUrl['url'])) {
|
||||
return $directDownloadUrl['url'];
|
||||
}
|
||||
} catch (StorageNotAvailableException $e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
|
@ -190,7 +190,7 @@ class ObjectTree extends \Sabre\DAV\Tree {
|
|||
$targetNodeExists = $this->nodeExists($destinationPath);
|
||||
$sourceNode = $this->getNodeForPath($sourcePath);
|
||||
if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) {
|
||||
throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists');
|
||||
throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
|
||||
}
|
||||
list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourcePath);
|
||||
list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destinationPath);
|
||||
|
|
|
@ -41,11 +41,11 @@ class RootCollection extends SimpleCollection {
|
|||
\OC::$server->getSystemTagObjectMapper()
|
||||
);
|
||||
|
||||
$usersCardDavBackend = new CardDavBackend($db, $principalBackend);
|
||||
$usersCardDavBackend = new CardDavBackend($db, $principalBackend, \OC::$server->getLogger());
|
||||
$usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users');
|
||||
$usersAddressBookRoot->disableListing = $disableListing;
|
||||
|
||||
$systemCardDavBackend = new CardDavBackend($db, $principalBackend);
|
||||
$systemCardDavBackend = new CardDavBackend($db, $principalBackend, \OC::$server->getLogger());
|
||||
$systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system');
|
||||
$systemAddressBookRoot->disableListing = $disableListing;
|
||||
|
||||
|
|
|
@ -46,14 +46,25 @@ class SystemTagsByIdCollection implements ICollection {
|
|||
$this->tagManager = $tagManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param resource|string $data Initial payload
|
||||
* @throws Forbidden
|
||||
*/
|
||||
function createFile($name, $data = null) {
|
||||
throw new Forbidden('Cannot create tags by id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function createDirectory($name) {
|
||||
throw new Forbidden('Permission denied to create collections');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function getChild($name) {
|
||||
try {
|
||||
$tags = $this->tagManager->getTagsByIds([$name]);
|
||||
|
@ -72,6 +83,9 @@ class SystemTagsByIdCollection implements ICollection {
|
|||
}, $tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function childExists($name) {
|
||||
try {
|
||||
$this->tagManager->getTagsByIds([$name]);
|
||||
|
|
|
@ -61,14 +61,25 @@ class SystemTagsObjectTypeCollection implements ICollection {
|
|||
$this->objectType = $objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param resource|string $data Initial payload
|
||||
* @throws Forbidden
|
||||
*/
|
||||
function createFile($name, $data = null) {
|
||||
throw new Forbidden('Permission denied to create nodes');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function createDirectory($name) {
|
||||
throw new Forbidden('Permission denied to create collections');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $objectId
|
||||
*/
|
||||
function getChild($objectId) {
|
||||
return new SystemTagsObjectMappingCollection(
|
||||
$objectId,
|
||||
|
@ -83,6 +94,9 @@ class SystemTagsObjectTypeCollection implements ICollection {
|
|||
throw new MethodNotAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function childExists($name) {
|
||||
return true;
|
||||
}
|
||||
|
@ -95,6 +109,9 @@ class SystemTagsObjectTypeCollection implements ICollection {
|
|||
return $this->objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
function setName($name) {
|
||||
throw new Forbidden('Permission denied to rename this collection');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
if [ ! -f CalDAVTester/run.py ]; then
|
||||
cd "$SCRIPTPATH"
|
||||
git clone https://github.com/DeepDiver1975/CalDAVTester.git
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
python run.py -s
|
||||
cd "$SCRIPTPATH"
|
||||
fi
|
||||
|
||||
# create test user
|
||||
cd "$SCRIPTPATH/../../../../../"
|
||||
OC_PASS=user01 php occ user:add --password-from-env user01
|
||||
php occ dav:create-calendar user01 calendar
|
||||
OC_PASS=user02 php occ user:add --password-from-env user02
|
||||
php occ dav:create-calendar user02 calendar
|
||||
cd "$SCRIPTPATH/../../../../../"
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
|
||||
|
||||
sleep 30
|
||||
|
||||
# run the tests
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail -s "$SCRIPTPATH/../caldavtest/config/serverinfo.xml" -o cdt.txt \
|
||||
"$SCRIPTPATH/../caldavtest/tests/CalDAV/current-user-principal.xml"
|
||||
RESULT=$?
|
||||
|
||||
tail "$/../../../../../data-autotest/owncloud.log"
|
||||
|
||||
exit $RESULT
|
|
@ -0,0 +1,151 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
|
||||
<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
|
||||
|
||||
<!--
|
||||
Copyright (c) 2006-2015 Apple Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<caldavtest>
|
||||
<description>Test DAV:current-user-principal support</description>
|
||||
|
||||
<require-feature>
|
||||
<feature>caldav</feature>
|
||||
<feature>current-user-principal</feature>
|
||||
</require-feature>
|
||||
|
||||
<start/>
|
||||
|
||||
<test-suite name='Check for the property on /'>
|
||||
<require-feature>
|
||||
<feature>own-root</feature>
|
||||
</require-feature>
|
||||
<test name='1'>
|
||||
<description>Check for authenticated property on /</description>
|
||||
<request>
|
||||
<method>PROPFIND</method>
|
||||
<ruri>$root:</ruri>
|
||||
<header>
|
||||
<name>Depth</name>
|
||||
<value>0</value>
|
||||
</header>
|
||||
<data>
|
||||
<content-type>text/xml; charset=utf-8</content-type>
|
||||
<filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
|
||||
</data>
|
||||
<verify>
|
||||
<callback>propfindItems</callback>
|
||||
<arg>
|
||||
<name>okprops</name>
|
||||
<value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri1:</href>]]></value>
|
||||
</arg>
|
||||
</verify>
|
||||
</request>
|
||||
</test>
|
||||
<test name='3'>
|
||||
<description>Check for authenticated property on / (user02)</description>
|
||||
<request user="$userid2:" pswd="$pswd2:">
|
||||
<method>PROPFIND</method>
|
||||
<ruri>$root:</ruri>
|
||||
<header>
|
||||
<name>Depth</name>
|
||||
<value>0</value>
|
||||
</header>
|
||||
<data>
|
||||
<content-type>text/xml; charset=utf-8</content-type>
|
||||
<filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
|
||||
</data>
|
||||
<verify>
|
||||
<callback>propfindItems</callback>
|
||||
<arg>
|
||||
<name>okprops</name>
|
||||
<value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri2:</href>]]></value>
|
||||
</arg>
|
||||
</verify>
|
||||
</request>
|
||||
</test>
|
||||
</test-suite>
|
||||
|
||||
<test-suite name='Check for the property on /principals/'>
|
||||
<test name='1'>
|
||||
<description>Check for authenticated property on /</description>
|
||||
<request>
|
||||
<method>PROPFIND</method>
|
||||
<ruri>$principalcollection:</ruri>
|
||||
<header>
|
||||
<name>Depth</name>
|
||||
<value>0</value>
|
||||
</header>
|
||||
<data>
|
||||
<content-type>text/xml; charset=utf-8</content-type>
|
||||
<filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
|
||||
</data>
|
||||
<verify>
|
||||
<callback>propfindItems</callback>
|
||||
<arg>
|
||||
<name>okprops</name>
|
||||
<value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri1:</href>]]></value>
|
||||
</arg>
|
||||
</verify>
|
||||
</request>
|
||||
</test>
|
||||
<test name='2'>
|
||||
<description>Check for unauthenticated property on /</description>
|
||||
<request auth="no">
|
||||
<method>PROPFIND</method>
|
||||
<ruri>$principals_users:</ruri>
|
||||
<header>
|
||||
<name>Depth</name>
|
||||
<value>0</value>
|
||||
</header>
|
||||
<data>
|
||||
<content-type>text/xml; charset=utf-8</content-type>
|
||||
<filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
|
||||
</data>
|
||||
<verify>
|
||||
<callback>statusCode</callback>
|
||||
<arg>
|
||||
<name>status</name>
|
||||
<value>401</value>
|
||||
</arg>
|
||||
</verify>
|
||||
</request>
|
||||
</test>
|
||||
<test name='3'>
|
||||
<description>Check for authenticated property on / (user02)</description>
|
||||
<request user="$userid2:" pswd="$pswd2:">
|
||||
<method>PROPFIND</method>
|
||||
<ruri>$principalcollection:</ruri>
|
||||
<header>
|
||||
<name>Depth</name>
|
||||
<value>0</value>
|
||||
</header>
|
||||
<data>
|
||||
<content-type>text/xml; charset=utf-8</content-type>
|
||||
<filepath>Resource/CalDAV/current-user-principal/1.xml</filepath>
|
||||
</data>
|
||||
<verify>
|
||||
<callback>propfindItems</callback>
|
||||
<arg>
|
||||
<name>okprops</name>
|
||||
<value><![CDATA[{DAV:}current-user-principal$<href xmlns="DAV:">$principaluri2:</href>]]></value>
|
||||
</arg>
|
||||
</verify>
|
||||
</request>
|
||||
</test>
|
||||
</test-suite>
|
||||
|
||||
<end/>
|
||||
</caldavtest>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
if [ ! -f CalDAVTester/run.py ]; then
|
||||
cd "$SCRIPTPATH"
|
||||
git clone https://github.com/DeepDiver1975/CalDAVTester.git
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
python run.py -s
|
||||
cd "$SCRIPTPATH"
|
||||
fi
|
||||
|
||||
# create test user
|
||||
cd "$SCRIPTPATH/../../../../../"
|
||||
OC_PASS=user01 php occ user:add --password-from-env user01
|
||||
php occ dav:create-addressbook user01 addressbook
|
||||
OC_PASS=user02 php occ user:add --password-from-env user02
|
||||
php occ dav:create-addressbook user02 addressbook
|
||||
cd "$SCRIPTPATH/../../../../../"
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
|
||||
|
||||
sleep 30
|
||||
|
||||
# run the tests
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail -s "$SCRIPTPATH/../caldavtest/config/serverinfo.xml" -o cdt.txt \
|
||||
"$SCRIPTPATH/../caldavtest/tests/CardDAV/current-user-principal.xml" \
|
||||
"$SCRIPTPATH/../caldavtest/tests/CardDAV/sync-report.xml"
|
||||
RESULT=$?
|
||||
|
||||
tail "$/../../../../../data-autotest/owncloud.log"
|
||||
|
||||
exit $RESULT
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
|
||||
|
||||
|
||||
if [ ! -f CalDAVTester/run.py ]; then
|
||||
cd "$SCRIPTPATH"
|
||||
git clone https://github.com/DeepDiver1975/CalDAVTester.git
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
python run.py -s
|
||||
cd "$SCRIPTPATH"
|
||||
fi
|
||||
|
||||
# create test user
|
||||
cd "$SCRIPTPATH/../../../../"
|
||||
OC_PASS=user01 php occ user:add --password-from-env user01
|
||||
php occ dav:create-addressbook user01 addressbook
|
||||
OC_PASS=user02 php occ user:add --password-from-env user02
|
||||
php occ dav:create-addressbook user02 addressbook
|
||||
cd "$SCRIPTPATH/../../../../"
|
||||
|
||||
# run the tests
|
||||
cd "$SCRIPTPATH/CalDAVTester"
|
||||
PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail -s "$SCRIPTPATH/caldavtest/config/serverinfo.xml" -o cdt.txt \
|
||||
"$SCRIPTPATH/caldavtest/tests/CardDAV/current-user-principal.xml" \
|
||||
"$SCRIPTPATH/caldavtest/tests/CardDAV/sync-report.xml"
|
||||
RESULT=$?
|
||||
|
||||
tail "$SCRIPTPATH/../../../../data-autotest/owncloud.log"
|
||||
|
||||
exit $RESULT
|
|
@ -1,11 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
|
||||
|
||||
|
||||
# compile litmus
|
||||
if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
|
||||
|
@ -17,7 +10,3 @@ if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
|
|||
./configure
|
||||
make
|
||||
fi
|
||||
|
||||
# run the tests
|
||||
cd /tmp/litmus/litmus-0.13
|
||||
make URL=http://127.0.0.1:8888/remote.php/webdav CREDS="admin admin" TESTS="basic copymove props locks" check
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
|
||||
|
||||
sleep 30
|
||||
|
||||
# run the tests
|
||||
cd /tmp/litmus/litmus-0.13
|
||||
make URL=http://127.0.0.1:8888/remote.php/webdav CREDS="admin admin" TESTS="basic copymove props locks" check
|
|
@ -1,11 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../.." &
|
||||
|
||||
|
||||
# compile litmus
|
||||
if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
|
||||
|
@ -17,7 +10,3 @@ if [ ! -f /tmp/litmus/litmus-0.13.tar.gz ]; then
|
|||
./configure
|
||||
make
|
||||
fi
|
||||
|
||||
# run the tests
|
||||
cd /tmp/litmus/litmus-0.13
|
||||
make URL=http://127.0.0.1:8888/remote.php/dav/files/admin CREDS="admin admin" TESTS="basic copymove props locks" check
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
SCRIPT=`realpath $0`
|
||||
SCRIPTPATH=`dirname $SCRIPT`
|
||||
|
||||
|
||||
# start the server
|
||||
php -S 127.0.0.1:8888 -t "$SCRIPTPATH/../../../../.." &
|
||||
|
||||
sleep 30
|
||||
|
||||
# run the tests
|
||||
cd /tmp/litmus/litmus-0.13
|
||||
make URL=http://127.0.0.1:8888/remote.php/dav/files/admin CREDS="admin admin" TESTS="basic copymove props locks" check
|
|
@ -0,0 +1,287 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@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\AddressBook;
|
||||
use OCA\DAV\CardDAV\AddressBookImpl;
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
use Test\TestCase;
|
||||
|
||||
class AddressBookImplTest extends TestCase {
|
||||
|
||||
/** @var AddressBookImpl */
|
||||
private $addressBookImpl;
|
||||
|
||||
/** @var array */
|
||||
private $addressBookInfo;
|
||||
|
||||
/** @var AddressBook | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $addressBook;
|
||||
|
||||
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $backend;
|
||||
|
||||
/** @var VCard | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $vCard;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->addressBookInfo = [
|
||||
'id' => 42,
|
||||
'{DAV:}displayname' => 'display name'
|
||||
];
|
||||
$this->addressBook = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBook')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->backend = $this->getMockBuilder('\OCA\DAV\CardDAV\CardDavBackend')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->vCard = $this->getMock('Sabre\VObject\Component\VCard');
|
||||
|
||||
$this->addressBookImpl = new AddressBookImpl(
|
||||
$this->addressBook,
|
||||
$this->addressBookInfo,
|
||||
$this->backend
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetKey() {
|
||||
$this->assertSame($this->addressBookInfo['id'],
|
||||
$this->addressBookImpl->getKey());
|
||||
}
|
||||
|
||||
public function testGetDisplayName() {
|
||||
$this->assertSame($this->addressBookInfo['{DAV:}displayname'],
|
||||
$this->addressBookImpl->getDisplayName());
|
||||
}
|
||||
|
||||
public function testSearch() {
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->addressBook,
|
||||
$this->addressBookInfo,
|
||||
$this->backend
|
||||
]
|
||||
)
|
||||
->setMethods(['vCard2Array', 'readCard'])
|
||||
->getMock();
|
||||
|
||||
$pattern = 'pattern';
|
||||
$searchProperties = 'properties';
|
||||
|
||||
$this->backend->expects($this->once())->method('search')
|
||||
->with($this->addressBookInfo['id'], $pattern, $searchProperties)
|
||||
->willReturn(
|
||||
[
|
||||
'cardData1',
|
||||
'cardData2'
|
||||
]
|
||||
);
|
||||
|
||||
$addressBookImpl->expects($this->exactly(2))->method('readCard')
|
||||
->willReturn($this->vCard);
|
||||
$addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
|
||||
->with($this->vCard)->willReturn('vCard');
|
||||
|
||||
$result = $addressBookImpl->search($pattern, $searchProperties, []);
|
||||
$this->assertTrue((is_array($result)));
|
||||
$this->assertSame(2, count($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestCreate
|
||||
*
|
||||
* @param array $properties
|
||||
*/
|
||||
public function testCreate($properties) {
|
||||
|
||||
$uid = 'uid';
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->addressBook,
|
||||
$this->addressBookInfo,
|
||||
$this->backend
|
||||
]
|
||||
)
|
||||
->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
|
||||
->getMock();
|
||||
|
||||
$addressBookImpl->expects($this->once())->method('createUid')
|
||||
->willReturn($uid);
|
||||
$addressBookImpl->expects($this->once())->method('createEmptyVCard')
|
||||
->with($uid)->willReturn($this->vCard);
|
||||
$this->vCard->expects($this->exactly(count($properties)))
|
||||
->method('createProperty');
|
||||
$this->backend->expects($this->once())->method('createCard');
|
||||
$this->backend->expects($this->never())->method('updateCard');
|
||||
$this->backend->expects($this->never())->method('getCard');
|
||||
$addressBookImpl->expects($this->once())->method('vCard2Array')
|
||||
->with($this->vCard)->willReturn(true);
|
||||
|
||||
$this->assertTrue($addressBookImpl->createOrUpdate($properties));
|
||||
}
|
||||
|
||||
public function dataTestCreate() {
|
||||
return [
|
||||
[[]],
|
||||
[['FN' => 'John Doe']]
|
||||
];
|
||||
}
|
||||
|
||||
public function testUpdate() {
|
||||
|
||||
$uid = 'uid';
|
||||
$properties = ['UID' => $uid, 'FN' => 'John Doe'];
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->addressBook,
|
||||
$this->addressBookInfo,
|
||||
$this->backend
|
||||
]
|
||||
)
|
||||
->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
|
||||
->getMock();
|
||||
|
||||
$addressBookImpl->expects($this->never())->method('createUid');
|
||||
$addressBookImpl->expects($this->never())->method('createEmptyVCard');
|
||||
$this->backend->expects($this->once())->method('getCard')
|
||||
->with($this->addressBookInfo['id'], $uid . '.vcf')
|
||||
->willReturn(['carddata' => 'data']);
|
||||
$addressBookImpl->expects($this->once())->method('readCard')
|
||||
->with('data')->willReturn($this->vCard);
|
||||
$this->vCard->expects($this->exactly(count($properties)))
|
||||
->method('createProperty');
|
||||
$this->backend->expects($this->never())->method('createCard');
|
||||
$this->backend->expects($this->once())->method('updateCard');
|
||||
$addressBookImpl->expects($this->once())->method('vCard2Array')
|
||||
->with($this->vCard)->willReturn(true);
|
||||
|
||||
$this->assertTrue($addressBookImpl->createOrUpdate($properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestGetPermissions
|
||||
*
|
||||
* @param array $permissions
|
||||
* @param int $expected
|
||||
*/
|
||||
public function testGetPermissions($permissions, $expected) {
|
||||
$this->addressBook->expects($this->once())->method('getACL')
|
||||
->willReturn($permissions);
|
||||
|
||||
$this->assertSame($expected,
|
||||
$this->addressBookImpl->getPermissions()
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestGetPermissions() {
|
||||
return [
|
||||
[[], 0],
|
||||
[[['privilege' => '{DAV:}read']], 1],
|
||||
[[['privilege' => '{DAV:}write']], 6],
|
||||
[[['privilege' => '{DAV:}all']], 31],
|
||||
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
|
||||
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
|
||||
[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
|
||||
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
|
||||
[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
|
||||
];
|
||||
}
|
||||
|
||||
public function testDelete() {
|
||||
$cardId = 1;
|
||||
$cardUri = 'cardUri';
|
||||
$this->backend->expects($this->once())->method('getCardUri')
|
||||
->with($cardId)->willReturn($cardUri);
|
||||
$this->backend->expects($this->once())->method('deleteCard')
|
||||
->with($this->addressBookInfo['id'], $cardUri)
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue($this->addressBookImpl->delete($cardId));
|
||||
}
|
||||
|
||||
public function testReadCard() {
|
||||
$vCard = new VCard();
|
||||
$vCard->add(new Text($vCard, 'UID', 'uid'));
|
||||
$vCardSerialized = $vCard->serialize();
|
||||
|
||||
$result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
|
||||
$resultSerialized = $result->serialize();
|
||||
|
||||
$this->assertSame($vCardSerialized, $resultSerialized);
|
||||
}
|
||||
|
||||
public function testCreateUid() {
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->addressBook,
|
||||
$this->addressBookInfo,
|
||||
$this->backend
|
||||
]
|
||||
)
|
||||
->setMethods(['getUid'])
|
||||
->getMock();
|
||||
|
||||
$addressBookImpl->expects($this->at(0))->method('getUid')->willReturn('uid0');
|
||||
$addressBookImpl->expects($this->at(1))->method('getUid')->willReturn('uid1');
|
||||
|
||||
// simulate that 'uid0' already exists, so the second uid will be returned
|
||||
$this->backend->expects($this->exactly(2))->method('getContact')
|
||||
->willReturnCallback(
|
||||
function($uid) {
|
||||
return ($uid === 'uid0.vcf');
|
||||
}
|
||||
);
|
||||
|
||||
$this->assertSame('uid1',
|
||||
$this->invokePrivate($addressBookImpl, 'createUid', [])
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function testCreateEmptyVCard() {
|
||||
$uid = 'uid';
|
||||
$expectedVCard = new VCard();
|
||||
$expectedVCard->add(new Text($expectedVCard, 'UID', $uid));
|
||||
$expectedVCardSerialized = $expectedVCard->serialize();
|
||||
|
||||
$result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
|
||||
$resultSerialized = $result->serialize();
|
||||
|
||||
$this->assertSame($expectedVCardSerialized, $resultSerialized);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,8 +20,14 @@
|
|||
*/
|
||||
namespace OCA\DAV\Tests\Unit\CardDAV;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
|
@ -36,22 +42,46 @@ class CardDavBackendTest extends TestCase {
|
|||
/** @var CardDavBackend */
|
||||
private $backend;
|
||||
|
||||
/** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $principal;
|
||||
|
||||
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $logger;
|
||||
|
||||
/** @var IDBConnection */
|
||||
private $db;
|
||||
|
||||
/** @var string */
|
||||
private $dbCardsTable = 'cards';
|
||||
|
||||
/** @var string */
|
||||
private $dbCardsPropertiesTable = 'cards_properties';
|
||||
|
||||
const UNIT_TEST_USER = 'carddav-unit-test';
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||
$this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getPrincipalByPath'])
|
||||
->getMock();
|
||||
$principal->method('getPrincipalByPath')
|
||||
$this->principal->method('getPrincipalByPath')
|
||||
->willReturn([
|
||||
'uri' => 'principals/best-friend'
|
||||
]);
|
||||
$this->logger = $this->getMock('\OCP\ILogger');
|
||||
|
||||
$this->db = \OC::$server->getDatabaseConnection();
|
||||
|
||||
$this->backend = new CardDavBackend($this->db, $this->principal, $this->logger);
|
||||
|
||||
// start every test with a empty cards_properties and cards table
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete('cards_properties')->execute();
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete('cards')->execute();
|
||||
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$this->backend = new CardDavBackend($db, $principal);
|
||||
|
||||
$this->tearDown();
|
||||
}
|
||||
|
@ -96,23 +126,32 @@ class CardDavBackendTest extends TestCase {
|
|||
}
|
||||
|
||||
public function testCardOperations() {
|
||||
|
||||
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */
|
||||
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||
->setMethods(['updateProperties', 'purgeProperties'])->getMock();
|
||||
|
||||
// create a new address book
|
||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||
$backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||
$books = $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, '');
|
||||
// updateProperties is expected twice, once for createCard and once for updateCard
|
||||
$backend->expects($this->at(0))->method('updateProperties')->with($bookId, $uri, '');
|
||||
$backend->expects($this->at(1))->method('updateProperties')->with($bookId, $uri, '***');
|
||||
// create a card
|
||||
$backend->createCard($bookId, $uri, '');
|
||||
|
||||
// get all the cards
|
||||
$cards = $this->backend->getCards($bookId);
|
||||
$cards = $backend->getCards($bookId);
|
||||
$this->assertEquals(1, count($cards));
|
||||
$this->assertEquals('', $cards[0]['carddata']);
|
||||
|
||||
// get the cards
|
||||
$card = $this->backend->getCard($bookId, $uri);
|
||||
$card = $backend->getCard($bookId, $uri);
|
||||
$this->assertNotNull($card);
|
||||
$this->assertArrayHasKey('id', $card);
|
||||
$this->assertArrayHasKey('uri', $card);
|
||||
|
@ -122,17 +161,23 @@ class CardDavBackendTest extends TestCase {
|
|||
$this->assertEquals('', $card['carddata']);
|
||||
|
||||
// update the card
|
||||
$this->backend->updateCard($bookId, $uri, '***');
|
||||
$card = $this->backend->getCard($bookId, $uri);
|
||||
$backend->updateCard($bookId, $uri, '***');
|
||||
$card = $backend->getCard($bookId, $uri);
|
||||
$this->assertEquals('***', $card['carddata']);
|
||||
|
||||
// delete the card
|
||||
$this->backend->deleteCard($bookId, $uri);
|
||||
$cards = $this->backend->getCards($bookId);
|
||||
$backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
|
||||
$backend->deleteCard($bookId, $uri);
|
||||
$cards = $backend->getCards($bookId);
|
||||
$this->assertEquals(0, count($cards));
|
||||
}
|
||||
|
||||
public function testMultiCard() {
|
||||
|
||||
$this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||
->setMethods(['updateProperties'])->getMock();
|
||||
|
||||
// create a new address book
|
||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||
|
@ -175,6 +220,11 @@ class CardDavBackendTest extends TestCase {
|
|||
}
|
||||
|
||||
public function testSyncSupport() {
|
||||
|
||||
$this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||
->setMethods(['updateProperties'])->getMock();
|
||||
|
||||
// create a new address book
|
||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||
|
@ -213,7 +263,7 @@ class CardDavBackendTest extends TestCase {
|
|||
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
||||
$this->assertEquals(1, count($books));
|
||||
|
||||
$this->backend->updateShares('Example', [], [['href' => 'principal:principals/best-friend']]);
|
||||
$this->backend->updateShares('Example', [], ['principal:principals/best-friend']);
|
||||
|
||||
$shares = $this->backend->getShares('Example');
|
||||
$this->assertEquals(0, count($shares));
|
||||
|
@ -221,4 +271,273 @@ class CardDavBackendTest extends TestCase {
|
|||
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
||||
$this->assertEquals(0, count($books));
|
||||
}
|
||||
|
||||
public function testUpdateProperties() {
|
||||
|
||||
$bookId = 42;
|
||||
$cardUri = 'card-uri';
|
||||
$cardId = 2;
|
||||
|
||||
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||
->setMethods(['getCardId'])->getMock();
|
||||
|
||||
$backend->expects($this->any())->method('getCardId')->willReturn($cardId);
|
||||
|
||||
// add properties for new vCard
|
||||
$vCard = new VCard();
|
||||
$vCard->add(new Text($vCard, 'UID', $cardUri));
|
||||
$vCard->add(new Text($vCard, 'FN', 'John Doe'));
|
||||
$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||
|
||||
$this->assertSame(2, count($result));
|
||||
|
||||
$this->assertSame('UID', $result[0]['name']);
|
||||
$this->assertSame($cardUri, $result[0]['value']);
|
||||
$this->assertSame($bookId, (int)$result[0]['addressbookid']);
|
||||
$this->assertSame($cardId, (int)$result[0]['cardid']);
|
||||
|
||||
$this->assertSame('FN', $result[1]['name']);
|
||||
$this->assertSame('John Doe', $result[1]['value']);
|
||||
$this->assertSame($bookId, (int)$result[1]['addressbookid']);
|
||||
$this->assertSame($cardId, (int)$result[1]['cardid']);
|
||||
|
||||
// update properties for existing vCard
|
||||
$vCard = new VCard();
|
||||
$vCard->add(new Text($vCard, 'FN', 'John Doe'));
|
||||
$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||
|
||||
$this->assertSame(1, count($result));
|
||||
|
||||
$this->assertSame('FN', $result[0]['name']);
|
||||
$this->assertSame('John Doe', $result[0]['value']);
|
||||
$this->assertSame($bookId, (int)$result[0]['addressbookid']);
|
||||
$this->assertSame($cardId, (int)$result[0]['cardid']);
|
||||
}
|
||||
|
||||
public function testPurgeProperties() {
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('cards_properties')
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(1),
|
||||
'cardid' => $query->createNamedParameter(1),
|
||||
'name' => $query->createNamedParameter('name1'),
|
||||
'value' => $query->createNamedParameter('value1'),
|
||||
'preferred' => $query->createNamedParameter(0)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('cards_properties')
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(1),
|
||||
'cardid' => $query->createNamedParameter(2),
|
||||
'name' => $query->createNamedParameter('name2'),
|
||||
'value' => $query->createNamedParameter('value2'),
|
||||
'preferred' => $query->createNamedParameter(0)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
|
||||
$this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
|
||||
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||
$this->assertSame(1, count($result));
|
||||
$this->assertSame(1 ,(int)$result[0]['addressbookid']);
|
||||
$this->assertSame(2 ,(int)$result[0]['cardid']);
|
||||
|
||||
}
|
||||
|
||||
public function testGetCardId() {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
|
||||
$query->insert('cards')
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(1),
|
||||
'carddata' => $query->createNamedParameter(''),
|
||||
'uri' => $query->createNamedParameter('uri'),
|
||||
'lastmodified' => $query->createNamedParameter(4738743),
|
||||
'etag' => $query->createNamedParameter('etag'),
|
||||
'size' => $query->createNamedParameter(120)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
$id = $query->getLastInsertId();
|
||||
|
||||
$this->assertSame($id,
|
||||
$this->invokePrivate($this->backend, 'getCardId', ['uri']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testGetCardIdFailed() {
|
||||
$this->invokePrivate($this->backend, 'getCardId', ['uri']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestSearch
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param array $expected
|
||||
*/
|
||||
public function testSearch($pattern, $properties, $expected) {
|
||||
/** @var VCard $vCards */
|
||||
$vCards = [];
|
||||
$vCards[0] = new VCard();
|
||||
$vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
|
||||
$vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
|
||||
$vCards[0]->add(new Text($vCards[0], 'CLOUD', 'john@owncloud.org'));
|
||||
$vCards[1] = new VCard();
|
||||
$vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
|
||||
$vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
|
||||
|
||||
$vCardIds = [];
|
||||
$query = $this->db->getQueryBuilder();
|
||||
for($i=0; $i<2; $i++) {
|
||||
$query->insert($this->dbCardsTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(0),
|
||||
'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), \PDO::PARAM_LOB),
|
||||
'uri' => $query->createNamedParameter('uri' . $i),
|
||||
'lastmodified' => $query->createNamedParameter(time()),
|
||||
'etag' => $query->createNamedParameter('etag' . $i),
|
||||
'size' => $query->createNamedParameter(120),
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
$vCardIds[] = $query->getLastInsertId();
|
||||
}
|
||||
|
||||
$query->insert($this->dbCardsPropertiesTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(0),
|
||||
'cardid' => $query->createNamedParameter($vCardIds[0]),
|
||||
'name' => $query->createNamedParameter('FN'),
|
||||
'value' => $query->createNamedParameter('John Doe'),
|
||||
'preferred' => $query->createNamedParameter(0)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
$query->insert($this->dbCardsPropertiesTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(0),
|
||||
'cardid' => $query->createNamedParameter($vCardIds[0]),
|
||||
'name' => $query->createNamedParameter('CLOUD'),
|
||||
'value' => $query->createNamedParameter('John@owncloud.org'),
|
||||
'preferred' => $query->createNamedParameter(0)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
$query->insert($this->dbCardsPropertiesTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(0),
|
||||
'cardid' => $query->createNamedParameter($vCardIds[1]),
|
||||
'name' => $query->createNamedParameter('FN'),
|
||||
'value' => $query->createNamedParameter('John M. Doe'),
|
||||
'preferred' => $query->createNamedParameter(0)
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
|
||||
$result = $this->backend->search(0, $pattern, $properties);
|
||||
|
||||
// check result
|
||||
$this->assertSame(count($expected), count($result));
|
||||
$found = [];
|
||||
foreach ($result as $r) {
|
||||
foreach ($expected as $exp) {
|
||||
if (strpos($r, $exp) > 0) {
|
||||
$found[$exp] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame(count($expected), count($found));
|
||||
}
|
||||
|
||||
public function dataTestSearch() {
|
||||
return [
|
||||
['John', ['FN'], ['John Doe', 'John M. Doe']],
|
||||
['M. Doe', ['FN'], ['John M. Doe']],
|
||||
['Do', ['FN'], ['John Doe', 'John M. Doe']],
|
||||
// check if duplicates are handled correctly
|
||||
['John', ['FN', 'CLOUD'], ['John Doe', 'John M. Doe']],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetCardUri() {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert($this->dbCardsTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter(1),
|
||||
'carddata' => $query->createNamedParameter('carddata', \PDO::PARAM_LOB),
|
||||
'uri' => $query->createNamedParameter('uri'),
|
||||
'lastmodified' => $query->createNamedParameter(5489543),
|
||||
'etag' => $query->createNamedParameter('etag'),
|
||||
'size' => $query->createNamedParameter(120),
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
|
||||
$id = $query->getLastInsertId();
|
||||
|
||||
$this->assertSame('uri', $this->backend->getCardUri($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testGetCardUriFailed() {
|
||||
$this->backend->getCardUri(1);
|
||||
}
|
||||
|
||||
public function testGetContact() {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
for($i=0; $i<2; $i++) {
|
||||
$query->insert($this->dbCardsTable)
|
||||
->values(
|
||||
[
|
||||
'addressbookid' => $query->createNamedParameter($i),
|
||||
'carddata' => $query->createNamedParameter('carddata' . $i, \PDO::PARAM_LOB),
|
||||
'uri' => $query->createNamedParameter('uri' . $i),
|
||||
'lastmodified' => $query->createNamedParameter(5489543),
|
||||
'etag' => $query->createNamedParameter('etag' . $i),
|
||||
'size' => $query->createNamedParameter(120),
|
||||
]
|
||||
);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
$result = $this->backend->getContact('uri0');
|
||||
$this->assertSame(7, count($result));
|
||||
$this->assertSame(0, (int)$result['addressbookid']);
|
||||
$this->assertSame('uri0', $result['uri']);
|
||||
$this->assertSame(5489543, (int)$result['lastmodified']);
|
||||
$this->assertSame('etag0', $result['etag']);
|
||||
$this->assertSame(120, (int)$result['size']);
|
||||
}
|
||||
|
||||
public function testGetContactFail() {
|
||||
$this->assertEmpty($this->backend->getContact('uri'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?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\Tests\Unit\CardDAV;
|
||||
|
||||
|
||||
use OCA\DAV\CardDAV\Sharing\IShareableAddressBook;
|
||||
use OCA\DAV\CardDAV\Sharing\Plugin;
|
||||
use OCA\DAV\Connector\Sabre\Auth;
|
||||
use OCP\IRequest;
|
||||
use Sabre\DAV\Server;
|
||||
use Sabre\DAV\SimpleCollection;
|
||||
use Sabre\HTTP\Request;
|
||||
use Sabre\HTTP\Response;
|
||||
use Test\TestCase;
|
||||
|
||||
class PluginTest extends TestCase {
|
||||
|
||||
/** @var Plugin */
|
||||
private $plugin;
|
||||
/** @var Server */
|
||||
private $server;
|
||||
/** @var IShareableAddressBook | \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $book;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
/** @var Auth | \PHPUnit_Framework_MockObject_MockObject $authBackend */
|
||||
$authBackend = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Auth')->disableOriginalConstructor()->getMock();
|
||||
$authBackend->method('isDavAuthenticated')->willReturn(true);
|
||||
|
||||
/** @var IRequest $request */
|
||||
$request = $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock();
|
||||
$this->plugin = new Plugin($authBackend, $request);
|
||||
|
||||
$root = new SimpleCollection('root');
|
||||
$this->server = new \Sabre\DAV\Server($root);
|
||||
/** @var SimpleCollection $node */
|
||||
$this->book = $this->getMockBuilder('OCA\DAV\CardDAV\Sharing\IShareableAddressBook')->disableOriginalConstructor()->getMock();
|
||||
$this->book->method('getName')->willReturn('addressbook1.vcf');
|
||||
$root->addChild($this->book);
|
||||
$this->plugin->initialize($this->server);
|
||||
}
|
||||
|
||||
public function testSharing() {
|
||||
|
||||
$this->book->expects($this->once())->method('updateShares')->with([[
|
||||
'href' => 'principal:principals/admin',
|
||||
'commonName' => null,
|
||||
'summary' => null,
|
||||
'readOnly' => false
|
||||
]], ['mailto:wilfredo@example.com']);
|
||||
|
||||
// setup request
|
||||
$request = new Request();
|
||||
$request->addHeader('Content-Type', 'application/xml');
|
||||
$request->setUrl('addressbook1.vcf');
|
||||
$request->setBody('<?xml version="1.0" encoding="utf-8" ?><CS:share xmlns:D="DAV:" xmlns:CS="urn:ietf:params:xml:ns:carddav"><CS:set><D:href>principal:principals/admin</D:href><CS:read-write/></CS:set> <CS:remove><D:href>mailto:wilfredo@example.com</D:href></CS:remove></CS:share>');
|
||||
$response = new Response();
|
||||
$this->plugin->httpPost($request, $response);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,14 @@ class File extends \Test\TestCase {
|
|||
parent::tearDown();
|
||||
}
|
||||
|
||||
private function getMockStorage() {
|
||||
$storage = $this->getMock('\OCP\Files\Storage');
|
||||
$storage->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue('home::someuser'));
|
||||
return $storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*/
|
||||
|
@ -149,7 +157,7 @@ class File extends \Test\TestCase {
|
|||
->method('getRelativePath')
|
||||
->will($this->returnArgument(0));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -209,7 +217,7 @@ class File extends \Test\TestCase {
|
|||
|
||||
$_SERVER['HTTP_OC_CHUNKED'] = true;
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-0', null, null, [
|
||||
$info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-0', $this->getMockStorage(), null, [
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
], null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -219,7 +227,7 @@ class File extends \Test\TestCase {
|
|||
$this->assertNull($file->put('test data one'));
|
||||
$file->releaseLock(ILockingProvider::LOCK_SHARED);
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-1', null, null, [
|
||||
$info = new \OC\Files\FileInfo('/test.txt-chunking-12345-2-1', $this->getMockStorage(), null, [
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
], null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -261,7 +269,7 @@ class File extends \Test\TestCase {
|
|||
|
||||
$info = new \OC\Files\FileInfo(
|
||||
$viewRoot . '/' . ltrim($path, '/'),
|
||||
null,
|
||||
$this->getMockStorage(),
|
||||
null,
|
||||
['permissions' => \OCP\Constants::PERMISSION_ALL],
|
||||
null
|
||||
|
@ -450,7 +458,7 @@ class File extends \Test\TestCase {
|
|||
$_SERVER['CONTENT_LENGTH'] = 123456;
|
||||
$_SERVER['REQUEST_METHOD'] = 'PUT';
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -483,7 +491,7 @@ class File extends \Test\TestCase {
|
|||
// simulate situation where the target file is locked
|
||||
$view->lockFile('/test.txt', ILockingProvider::LOCK_EXCLUSIVE);
|
||||
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -518,7 +526,7 @@ class File extends \Test\TestCase {
|
|||
|
||||
$_SERVER['HTTP_OC_CHUNKED'] = true;
|
||||
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-0', null, null, [
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-0', $this->getMockStorage(), null, [
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
], null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -526,7 +534,7 @@ class File extends \Test\TestCase {
|
|||
$this->assertNull($file->put('test data one'));
|
||||
$file->releaseLock(ILockingProvider::LOCK_SHARED);
|
||||
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-1', null, null, [
|
||||
$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt-chunking-12345-2-1', $this->getMockStorage(), null, [
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
], null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -555,7 +563,7 @@ class File extends \Test\TestCase {
|
|||
->method('getRelativePath')
|
||||
->will($this->returnArgument(0));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/*', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/*', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -591,7 +599,7 @@ class File extends \Test\TestCase {
|
|||
->method('getRelativePath')
|
||||
->will($this->returnArgument(0));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/*', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/*', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
$file = new \OCA\DAV\Connector\Sabre\File($view, $info);
|
||||
|
@ -618,7 +626,7 @@ class File extends \Test\TestCase {
|
|||
$_SERVER['CONTENT_LENGTH'] = 12345;
|
||||
$_SERVER['REQUEST_METHOD'] = 'PUT';
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -654,7 +662,7 @@ class File extends \Test\TestCase {
|
|||
->method('unlink')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -672,7 +680,7 @@ class File extends \Test\TestCase {
|
|||
$view = $this->getMock('\OC\Files\View',
|
||||
array());
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => 0
|
||||
), null);
|
||||
|
||||
|
@ -695,7 +703,7 @@ class File extends \Test\TestCase {
|
|||
->method('unlink')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -718,7 +726,7 @@ class File extends \Test\TestCase {
|
|||
->method('unlink')
|
||||
->willThrowException(new ForbiddenException('', true));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -753,7 +761,7 @@ class File extends \Test\TestCase {
|
|||
$path = 'test-locking.txt';
|
||||
$info = new \OC\Files\FileInfo(
|
||||
'/' . $this->user . '/files/' . $path,
|
||||
null,
|
||||
$this->getMockStorage(),
|
||||
null,
|
||||
['permissions' => \OCP\Constants::PERMISSION_ALL],
|
||||
null
|
||||
|
@ -865,7 +873,7 @@ class File extends \Test\TestCase {
|
|||
->method('fopen')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
@ -883,7 +891,7 @@ class File extends \Test\TestCase {
|
|||
->method('fopen')
|
||||
->willThrowException(new ForbiddenException('', true));
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', null, null, array(
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace OCA\DAV\Tests\Unit\Connector\Sabre;
|
||||
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
|
@ -143,6 +145,29 @@ class FilesPlugin extends \Test\TestCase {
|
|||
$this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties());
|
||||
}
|
||||
|
||||
public function testGetPropertiesStorageNotAvailable() {
|
||||
$node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File');
|
||||
|
||||
$propFind = new \Sabre\DAV\PropFind(
|
||||
'/dummyPath',
|
||||
array(
|
||||
self::DOWNLOADURL_PROPERTYNAME,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('getDirectDownload')
|
||||
->will($this->throwException(new StorageNotAvailableException()));
|
||||
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind,
|
||||
$node
|
||||
);
|
||||
|
||||
$this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
|
||||
}
|
||||
|
||||
public function testGetPublicPermissions() {
|
||||
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view, true);
|
||||
$this->plugin->initialize($this->server);
|
||||
|
|
|
@ -294,4 +294,45 @@ class ObjectTree extends \Test\TestCase {
|
|||
|
||||
$this->assertInstanceOf('\Sabre\DAV\INode', $tree->getNodeForPath($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Sabre\DAV\Exception\Forbidden
|
||||
* @expectedExceptionMessage Could not copy directory nameOfSourceNode, target exists
|
||||
*/
|
||||
public function testFailingMove() {
|
||||
$source = 'a/b';
|
||||
$destination = 'b/b';
|
||||
$updatables = array('a' => true, 'a/b' => true, 'b' => true, 'b/b' => false);
|
||||
$deletables = array('a/b' => true);
|
||||
|
||||
$view = new TestDoubleFileView($updatables, $deletables);
|
||||
|
||||
$info = new FileInfo('', null, null, array(), null);
|
||||
|
||||
$rootDir = new \OCA\DAV\Connector\Sabre\Directory($view, $info);
|
||||
$objectTree = $this->getMock('\OCA\DAV\Connector\Sabre\ObjectTree',
|
||||
array('nodeExists', 'getNodeForPath'),
|
||||
array($rootDir, $view));
|
||||
|
||||
$sourceNode = $this->getMockBuilder('\Sabre\DAV\ICollection')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$sourceNode->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('nameOfSourceNode'));
|
||||
|
||||
$objectTree->expects($this->once())
|
||||
->method('nodeExists')
|
||||
->with($this->identicalTo($destination))
|
||||
->will($this->returnValue(true));
|
||||
$objectTree->expects($this->once())
|
||||
->method('getNodeForPath')
|
||||
->with($this->identicalTo($source))
|
||||
->will($this->returnValue($sourceNode));
|
||||
|
||||
/** @var $objectTree \OCA\DAV\Connector\Sabre\ObjectTree */
|
||||
$mountManager = \OC\Files\Filesystem::getMountManager();
|
||||
$objectTree->init($rootDir, $view, $mountManager);
|
||||
$objectTree->move($source, $destination);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,8 @@
|
|||
namespace OCA\DAV\Tests\Unit\SystemTag;
|
||||
|
||||
use Sabre\DAV\Exception\NotFound;
|
||||
use Sabre\DAV\Exception\MethodNotAllowed;
|
||||
use Sabre\DAV\Exception\Conflict;
|
||||
|
||||
use OC\SystemTag\SystemTag;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use OCP\SystemTag\TagAlreadyExistsException;
|
||||
|
||||
class SystemTagMappingNode extends SystemTagNode {
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace OCA\DAV\Tests\Unit\SystemTag;
|
|||
|
||||
use OC\SystemTag\SystemTag;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use OCP\SystemTag\TagAlreadyExistsException;
|
||||
|
||||
class SystemTagsByIdCollection extends \Test\TestCase {
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace OCA\DAV\Tests\Unit\SystemTag;
|
|||
|
||||
use OC\SystemTag\SystemTag;
|
||||
use OCP\SystemTag\TagNotFoundException;
|
||||
use OCP\SystemTag\TagAlreadyExistsException;
|
||||
|
||||
class SystemTagsObjectMappingCollection extends \Test\TestCase {
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ OC.L10N.register(
|
|||
"The share will expire on %s." : "El objeto dejará de ser compartido el %s.",
|
||||
"Cheers!" : "¡Saludos!",
|
||||
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hola,\n<br><br>\nEl administrador ha habilitado el cifrado del lado servidor. Sus archivos serán cifrados usando como contraseña: <strong>%s</strong>\n<br><br>\nPor favor, identifíquese en la interfaz web, vaya a la sección 'Modulo básico de cifrado' de sus opciones personales y actualice su contraseña tecleando esta contraseña en el campo 'contraseña antigua' e introduciendo la nueva en su correspondiente campo.<br><br>",
|
||||
"Encrypt the home storage" : "Encriptar el almacenamiento personal",
|
||||
"Enable recovery key" : "Activa la clave de recuperación",
|
||||
"Disable recovery key" : "Desactiva la clave de recuperación",
|
||||
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "La clave de recuperación es una clave de cifrado extra que se usa para cifrar ficheros. Permite la recuperación de los ficheros de un usuario si él o ella olvida su contraseña.",
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
"The share will expire on %s." : "El objeto dejará de ser compartido el %s.",
|
||||
"Cheers!" : "¡Saludos!",
|
||||
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Hola,\n<br><br>\nEl administrador ha habilitado el cifrado del lado servidor. Sus archivos serán cifrados usando como contraseña: <strong>%s</strong>\n<br><br>\nPor favor, identifíquese en la interfaz web, vaya a la sección 'Modulo básico de cifrado' de sus opciones personales y actualice su contraseña tecleando esta contraseña en el campo 'contraseña antigua' e introduciendo la nueva en su correspondiente campo.<br><br>",
|
||||
"Encrypt the home storage" : "Encriptar el almacenamiento personal",
|
||||
"Enable recovery key" : "Activa la clave de recuperación",
|
||||
"Disable recovery key" : "Desactiva la clave de recuperación",
|
||||
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "La clave de recuperación es una clave de cifrado extra que se usa para cifrar ficheros. Permite la recuperación de los ficheros de un usuario si él o ella olvida su contraseña.",
|
||||
|
|
|
@ -34,6 +34,7 @@ OC.L10N.register(
|
|||
"New recovery key password" : "Uus taastevõtme parool",
|
||||
"Repeat new recovery key password" : "Korda uut taastevõtme parooli",
|
||||
"Change Password" : "Muuda parooli",
|
||||
"ownCloud basic encryption module" : "ownCloud peamine küpteerimismoodul",
|
||||
"Your private key password no longer matches your log-in password." : "Sinu provaatvõtme parool ei kattu enam sinu sisselogimise parooliga.",
|
||||
"Set your old private key password to your current log-in password:" : "Pane oma vana privaatvõtme parooliks oma praegune sisselogimise parool.",
|
||||
" If you don't remember your old password you can ask your administrator to recover your files." : "Kui sa ei mäleta oma vana parooli, siis palu oma süsteemihalduril taastada ligipääs failidele.",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"New recovery key password" : "Uus taastevõtme parool",
|
||||
"Repeat new recovery key password" : "Korda uut taastevõtme parooli",
|
||||
"Change Password" : "Muuda parooli",
|
||||
"ownCloud basic encryption module" : "ownCloud peamine küpteerimismoodul",
|
||||
"Your private key password no longer matches your log-in password." : "Sinu provaatvõtme parool ei kattu enam sinu sisselogimise parooliga.",
|
||||
"Set your old private key password to your current log-in password:" : "Pane oma vana privaatvõtme parooliks oma praegune sisselogimise parool.",
|
||||
" If you don't remember your old password you can ask your administrator to recover your files." : "Kui sa ei mäleta oma vana parooli, siis palu oma süsteemihalduril taastada ligipääs failidele.",
|
||||
|
|
|
@ -30,7 +30,7 @@ OC.L10N.register(
|
|||
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este arquivo, provavelmente este é um arquivo compartilhado. Por favor, pergunte o dono do arquivo para recompartilhar o arquivo com você.",
|
||||
"Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\nO administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha '%s'.\n\nPor favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login.\n\n",
|
||||
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
|
||||
"Cheers!" : "Saúde!",
|
||||
"Cheers!" : "Saudações!",
|
||||
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha <strong>%s</strong>.<br><br>Por favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login..<br><br>",
|
||||
"Encrypt the home storage" : "Criptografar a pasta de armazenamento home",
|
||||
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativar essa opção de criptografia para todos os arquivos armazenados no armazenamento principal, caso contrário, apenas arquivos no armazenamento externo serão criptografados",
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Não é possível ler este arquivo, provavelmente este é um arquivo compartilhado. Por favor, pergunte o dono do arquivo para recompartilhar o arquivo com você.",
|
||||
"Hey there,\n\nthe admin enabled server-side-encryption. Your files were encrypted using the password '%s'.\n\nPlease login to the web interface, go to the section 'ownCloud basic encryption module' of your personal settings and update your encryption password by entering this password into the 'old log-in password' field and your current login-password.\n\n" : "Olá,\n\nO administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha '%s'.\n\nPor favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login.\n\n",
|
||||
"The share will expire on %s." : "O compartilhamento irá expirar em %s.",
|
||||
"Cheers!" : "Saúde!",
|
||||
"Cheers!" : "Saudações!",
|
||||
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Olá,<br><br>o administrador habilitou criptografia-lado-servidor. Os seus arquivos foram criptografados usando a senha <strong>%s</strong>.<br><br>Por favor faça o login para a interface da Web, vá para a seção 'ownCloud módulo de criptografia básico' das suas definições pessoais e atualize sua senha de criptografia, inserindo esta senha no campo 'senha antiga de log-in' e sua atual senha-de-login..<br><br>",
|
||||
"Encrypt the home storage" : "Criptografar a pasta de armazenamento home",
|
||||
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Ativar essa opção de criptografia para todos os arquivos armazenados no armazenamento principal, caso contrário, apenas arquivos no armazenamento externo serão criptografados",
|
||||
|
|
|
@ -30,7 +30,6 @@ use OC\Encryption\Exceptions\DecryptionFailedException;
|
|||
use OC\Encryption\Exceptions\EncryptionFailedException;
|
||||
use OCA\Encryption\Exceptions\MultiKeyDecryptException;
|
||||
use OCA\Encryption\Exceptions\MultiKeyEncryptException;
|
||||
use OCA\Encryption\Vendor\PBKDF2Fallback;
|
||||
use OCP\Encryption\Exceptions\GenericEncryptionException;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
|
@ -293,28 +292,14 @@ class Crypt {
|
|||
$salt = hash('sha256', $uid . $instanceId . $instanceSecret, true);
|
||||
$keySize = $this->getKeySize($cipher);
|
||||
|
||||
if (function_exists('hash_pbkdf2')) {
|
||||
$hash = hash_pbkdf2(
|
||||
'sha256',
|
||||
$password,
|
||||
$salt,
|
||||
100000,
|
||||
$keySize,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
// fallback to 3rdparty lib for PHP <= 5.4.
|
||||
// FIXME: Can be removed as soon as support for PHP 5.4 was dropped
|
||||
$fallback = new PBKDF2Fallback();
|
||||
$hash = $fallback->pbkdf2(
|
||||
'sha256',
|
||||
$password,
|
||||
$salt,
|
||||
100000,
|
||||
$keySize,
|
||||
true
|
||||
);
|
||||
}
|
||||
$hash = hash_pbkdf2(
|
||||
'sha256',
|
||||
$password,
|
||||
$salt,
|
||||
100000,
|
||||
$keySize,
|
||||
true
|
||||
);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
|
|
@ -43,15 +43,18 @@ class MigrationTest extends \Test\TestCase {
|
|||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER2, 'foo');
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER3, 'foo');
|
||||
\OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
|
||||
\OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER2, 'foo');
|
||||
\OC::$server->getUserManager()->createUser(self::TEST_ENCRYPTION_MIGRATION_USER3, 'foo');
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
$user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
if ($user !== null) { $user->delete(); }
|
||||
$user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
if ($user !== null) { $user->delete(); }
|
||||
$user = \OC::$server->getUserManager()->get(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
if ($user !== null) { $user->delete(); }
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
/* Note; This class can be removed as soon as we drop PHP 5.4 support.
|
||||
*
|
||||
*
|
||||
* Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
|
||||
* Copyright (c) 2013, Taylor Hornby
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption\Vendor;
|
||||
|
||||
class PBKDF2Fallback {
|
||||
|
||||
/*
|
||||
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
|
||||
* $algorithm - The hash algorithm to use. Recommended: SHA256
|
||||
* $password - The password.
|
||||
* $salt - A salt that is unique to the password.
|
||||
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
|
||||
* $key_length - The length of the derived key in bytes.
|
||||
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
|
||||
* Returns: A $key_length-byte key derived from the password and salt.
|
||||
*
|
||||
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
|
||||
*
|
||||
* This implementation of PBKDF2 was originally created by https://defuse.ca
|
||||
* With improvements by http://www.variations-of-shadow.com
|
||||
*/
|
||||
public function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) {
|
||||
$algorithm = strtolower($algorithm);
|
||||
if (!in_array($algorithm, hash_algos(), true))
|
||||
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
|
||||
if ($count <= 0 || $key_length <= 0)
|
||||
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
|
||||
|
||||
if (function_exists("hash_pbkdf2")) {
|
||||
// The output length is in NIBBLES (4-bits) if $raw_output is false!
|
||||
if (!$raw_output) {
|
||||
$key_length = $key_length * 2;
|
||||
}
|
||||
return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
|
||||
}
|
||||
|
||||
$hash_length = strlen(hash($algorithm, "", true));
|
||||
$block_count = ceil($key_length / $hash_length);
|
||||
|
||||
$output = "";
|
||||
for ($i = 1; $i <= $block_count; $i++) {
|
||||
// $i encoded as 4 bytes, big endian.
|
||||
$last = $salt . pack("N", $i);
|
||||
// first iteration
|
||||
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
|
||||
// perform the other $count - 1 iterations
|
||||
for ($j = 1; $j < $count; $j++) {
|
||||
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
|
||||
}
|
||||
$output .= $xorsum;
|
||||
}
|
||||
|
||||
if ($raw_output)
|
||||
return substr($output, 0, $key_length);
|
||||
else
|
||||
return bin2hex(substr($output, 0, $key_length));
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ use OCA\Federation\DbHandler;
|
|||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\BackgroundJob\IJobList;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use OCP\Security\StringUtils;
|
||||
|
@ -54,6 +55,9 @@ class OCSAuthAPI {
|
|||
/** @var DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* OCSAuthAPI constructor.
|
||||
*
|
||||
|
@ -62,19 +66,22 @@ class OCSAuthAPI {
|
|||
* @param IJobList $jobList
|
||||
* @param TrustedServers $trustedServers
|
||||
* @param DbHandler $dbHandler
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
ISecureRandom $secureRandom,
|
||||
IJobList $jobList,
|
||||
TrustedServers $trustedServers,
|
||||
DbHandler $dbHandler
|
||||
DbHandler $dbHandler,
|
||||
ILogger $logger
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->secureRandom = $secureRandom;
|
||||
$this->jobList = $jobList;
|
||||
$this->trustedServers = $trustedServers;
|
||||
$this->dbHandler = $dbHandler;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,6 +95,7 @@ class OCSAuthAPI {
|
|||
$token = $this->request->getParam('token');
|
||||
|
||||
if ($this->trustedServers->isTrustedServer($url) === false) {
|
||||
$this->logger->log(\OCP\Util::ERROR, 'remote server not trusted (' . $url . ') while requesting shared secret');
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
|
@ -95,6 +103,7 @@ class OCSAuthAPI {
|
|||
// token wins
|
||||
$localToken = $this->dbHandler->getToken($url);
|
||||
if (strcmp($localToken, $token) > 0) {
|
||||
$this->logger->log(\OCP\Util::ERROR, 'remote server (' . $url . ') presented lower token');
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
|
@ -120,10 +129,13 @@ class OCSAuthAPI {
|
|||
$url = $this->request->getParam('url');
|
||||
$token = $this->request->getParam('token');
|
||||
|
||||
if (
|
||||
$this->trustedServers->isTrustedServer($url) === false
|
||||
|| $this->isValidToken($url, $token) === false
|
||||
) {
|
||||
if ($this->trustedServers->isTrustedServer($url) === false) {
|
||||
$this->logger->log(\OCP\Util::ERROR, 'remote server not trusted (' . $url . ') while getting shared secret');
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
if ($this->isValidToken($url, $token) === false) {
|
||||
$this->logger->log(\OCP\Util::ERROR, 'remote server (' . $url . ') didn\'t send a valid token (got ' . $token . ') while getting shared secret');
|
||||
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
|
@ -139,7 +151,7 @@ class OCSAuthAPI {
|
|||
|
||||
protected function isValidToken($url, $token) {
|
||||
$storedToken = $this->dbHandler->getToken($url);
|
||||
return StringUtils::equals($storedToken, $token);
|
||||
return hash_equals($storedToken, $token);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,7 +108,8 @@ class Application extends \OCP\AppFramework\App {
|
|||
$server->getSecureRandom(),
|
||||
$server->getJobList(),
|
||||
$container->query('TrustedServers'),
|
||||
$container->query('DbHandler')
|
||||
$container->query('DbHandler'),
|
||||
$server->getLogger()
|
||||
|
||||
);
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ class GetSharedSecret extends QueuedJob{
|
|||
$this->trustedServers = new TrustedServers(
|
||||
$this->dbHandler,
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
$this->logger,
|
||||
$this->jobList,
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
|
@ -148,6 +148,7 @@ class GetSharedSecret extends QueuedJob{
|
|||
|
||||
} catch (ClientException $e) {
|
||||
$status = $e->getCode();
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
|
||||
// if we received a unexpected response we try again later
|
||||
|
|
|
@ -60,6 +60,9 @@ class RequestSharedSecret extends QueuedJob {
|
|||
|
||||
private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json';
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* RequestSharedSecret constructor.
|
||||
*
|
||||
|
@ -80,13 +83,14 @@ class RequestSharedSecret extends QueuedJob {
|
|||
$this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
|
||||
$this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
|
||||
$this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
|
||||
$this->logger = \OC::$server->getLogger();
|
||||
if ($trustedServers) {
|
||||
$this->trustedServers = $trustedServers;
|
||||
} else {
|
||||
$this->trustedServers = new TrustedServers(
|
||||
$this->dbHandler,
|
||||
\OC::$server->getHTTPClientService(),
|
||||
\OC::$server->getLogger(),
|
||||
$this->logger,
|
||||
$this->jobList,
|
||||
\OC::$server->getSecureRandom(),
|
||||
\OC::$server->getConfig()
|
||||
|
@ -142,6 +146,7 @@ class RequestSharedSecret extends QueuedJob {
|
|||
|
||||
} catch (ClientException $e) {
|
||||
$status = $e->getCode();
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
|
||||
// if we received a unexpected response we try again later
|
||||
|
|
|
@ -28,6 +28,7 @@ use OCA\Federation\API\OCSAuthAPI;
|
|||
use OCA\Federation\DbHandler;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use Test\TestCase;
|
||||
|
@ -49,6 +50,9 @@ class OCSAuthAPITest extends TestCase {
|
|||
/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
|
||||
private $dbHandler;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var OCSAuthApi */
|
||||
private $ocsAuthApi;
|
||||
|
||||
|
@ -63,13 +67,16 @@ class OCSAuthAPITest extends TestCase {
|
|||
->disableOriginalConstructor()->getMock();
|
||||
$this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->logger = $this->getMockBuilder('OCP\ILogger')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->ocsAuthApi = new OCSAuthAPI(
|
||||
$this->request,
|
||||
$this->secureRandom,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
$this->dbHandler,
|
||||
$this->logger
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -136,7 +143,8 @@ class OCSAuthAPITest extends TestCase {
|
|||
$this->secureRandom,
|
||||
$this->jobList,
|
||||
$this->trustedServers,
|
||||
$this->dbHandler
|
||||
$this->dbHandler,
|
||||
$this->logger
|
||||
]
|
||||
)->setMethods(['isValidToken'])->getMock();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ $htaccessWorking=(getenv('htaccessWorking')=='true');
|
|||
$upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize');
|
||||
$post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size');
|
||||
$maxUploadFilesize = OCP\Util::humanFileSize(min($upload_max_filesize, $post_max_size));
|
||||
if($_POST && OC_Util::isCallRegistered()) {
|
||||
if($_POST && \OC::$server->getRequest()->passesCSRFCheck()) {
|
||||
if(isset($_POST['maxUploadSize'])) {
|
||||
if(($setMaxSize = OC_Files::setUploadLimit(OCP\Util::computerFileSize($_POST['maxUploadSize']))) !== false) {
|
||||
$maxUploadFilesize = OCP\Util::humanFileSize($setMaxSize);
|
||||
|
|
|
@ -20,5 +20,5 @@
|
|||
*
|
||||
*/
|
||||
|
||||
$application->add(new OCA\Files\Command\Scan(OC_User::getManager()));
|
||||
$application->add(new OCA\Files\Command\Scan(\OC::$server->getUserManager()));
|
||||
$application->add(new OCA\Files\Command\DeleteOrphanedFiles(\OC::$server->getDatabaseConnection()));
|
||||
|
|
|
@ -32,6 +32,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class Scan extends Command {
|
||||
|
||||
|
@ -39,6 +40,15 @@ class Scan extends Command {
|
|||
* @var \OC\User\Manager $userManager
|
||||
*/
|
||||
private $userManager;
|
||||
/** @var float */
|
||||
protected $execTime = 0;
|
||||
/** @var int */
|
||||
protected $foldersCounter = 0;
|
||||
/** @var int */
|
||||
protected $filesCounter = 0;
|
||||
/** @var bool */
|
||||
protected $interrupted = false;
|
||||
|
||||
|
||||
public function __construct(\OC\User\Manager $userManager) {
|
||||
$this->userManager = $userManager;
|
||||
|
@ -64,7 +74,13 @@ class Scan extends Command {
|
|||
'quiet',
|
||||
'q',
|
||||
InputOption::VALUE_NONE,
|
||||
'suppress output'
|
||||
'suppress any output'
|
||||
)
|
||||
->addOption(
|
||||
'verbose',
|
||||
'-v|vv|vvv',
|
||||
InputOption::VALUE_NONE,
|
||||
'verbose the output'
|
||||
)
|
||||
->addOption(
|
||||
'all',
|
||||
|
@ -74,19 +90,31 @@ class Scan extends Command {
|
|||
);
|
||||
}
|
||||
|
||||
protected function scanFiles($user, $path, $quiet, OutputInterface $output) {
|
||||
protected function scanFiles($user, $path, $verbose, OutputInterface $output) {
|
||||
$scanner = new \OC\Files\Utils\Scanner($user, \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
|
||||
if (!$quiet) {
|
||||
# printout and count
|
||||
if ($verbose) {
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
|
||||
$output->writeln("Scanning file <info>$path</info>");
|
||||
$this->filesCounter += 1;
|
||||
});
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
|
||||
$output->writeln("Scanning folder <info>$path</info>");
|
||||
$this->foldersCounter += 1;
|
||||
});
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
|
||||
$output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
|
||||
});
|
||||
# count only
|
||||
} else {
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
|
||||
$this->filesCounter += 1;
|
||||
});
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
|
||||
$this->foldersCounter += 1;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
$scanner->scan($path);
|
||||
} catch (ForbiddenException $e) {
|
||||
|
@ -95,6 +123,7 @@ class Scan extends Command {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$inputPath = $input->getOption('path');
|
||||
if ($inputPath) {
|
||||
|
@ -106,24 +135,173 @@ class Scan extends Command {
|
|||
} else {
|
||||
$users = $input->getArgument('user_id');
|
||||
}
|
||||
$quiet = $input->getOption('quiet');
|
||||
|
||||
|
||||
if (count($users) === 0) {
|
||||
$output->writeln("<error>Please specify the user id to scan, \"--all\" to scan for all users or \"--path=...\"</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
# no messaging level option means: no full printout but statistics
|
||||
# $quiet means no print at all
|
||||
# $verbose means full printout including statistics
|
||||
# -q -v full stat
|
||||
# 0 0 no yes
|
||||
# 0 1 yes yes
|
||||
# 1 -- no no (quiet overrules verbose)
|
||||
$verbose = $input->getOption('verbose');
|
||||
$quiet = $input->getOption('quiet');
|
||||
# restrict the verbosity level to VERBOSITY_VERBOSE
|
||||
if ($output->getVerbosity()>OutputInterface::VERBOSITY_VERBOSE) {
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
|
||||
}
|
||||
if ($quiet) {
|
||||
$verbose = false;
|
||||
}
|
||||
|
||||
$this->initTools();
|
||||
|
||||
foreach ($users as $user) {
|
||||
if (is_object($user)) {
|
||||
$user = $user->getUID();
|
||||
}
|
||||
$path = $inputPath ? $inputPath : '/' . $user;
|
||||
if ($this->userManager->userExists($user)) {
|
||||
$this->scanFiles($user, $path, $quiet, $output);
|
||||
# full: printout data if $verbose was set
|
||||
$this->scanFiles($user, $path, $verbose, $output);
|
||||
} else {
|
||||
$output->writeln("<error>Unknown user $user</error>");
|
||||
}
|
||||
}
|
||||
|
||||
# stat: printout statistics if $quiet was not set
|
||||
if (!$quiet) {
|
||||
$this->presentStats($output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the command was interrupted by ctrl-c
|
||||
*/
|
||||
protected function checkForInterruption($output) {
|
||||
if ($this->hasBeenInterrupted()) {
|
||||
$this->presentResults($output);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialises some useful tools for the Command
|
||||
*/
|
||||
protected function initTools() {
|
||||
// Start the timer
|
||||
$this->execTime = -microtime(true);
|
||||
// Convert PHP errors to exceptions
|
||||
set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
|
||||
|
||||
// Collect interrupts and notify the running command
|
||||
pcntl_signal(SIGTERM, [$this, 'cancelOperation']);
|
||||
pcntl_signal(SIGINT, [$this, 'cancelOperation']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the status of the command to "interrupted"
|
||||
*
|
||||
* Gives a chance to the command to properly terminate what it's doing
|
||||
*/
|
||||
private function cancelOperation() {
|
||||
$this->interrupted = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes PHP errors as exceptions in order to be able to keep track of problems
|
||||
*
|
||||
* @see https://secure.php.net/manual/en/function.set-error-handler.php
|
||||
*
|
||||
* @param int $severity the level of the error raised
|
||||
* @param string $message
|
||||
* @param string $file the filename that the error was raised in
|
||||
* @param int $line the line number the error was raised
|
||||
*
|
||||
* @throws \ErrorException
|
||||
*/
|
||||
public function exceptionErrorHandler($severity, $message, $file, $line) {
|
||||
if (!(error_reporting() & $severity)) {
|
||||
// This error code is not included in error_reporting
|
||||
return;
|
||||
}
|
||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBeenInterrupted() {
|
||||
$cancelled = false;
|
||||
pcntl_signal_dispatch();
|
||||
if ($this->interrupted) {
|
||||
$cancelled = true;
|
||||
}
|
||||
|
||||
return $cancelled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
protected function presentStats(OutputInterface $output) {
|
||||
// Stop the timer
|
||||
$this->execTime += microtime(true);
|
||||
$output->writeln("");
|
||||
|
||||
$headers = [
|
||||
'Folders', 'Files', 'Elapsed time'
|
||||
];
|
||||
|
||||
$this->showSummary($headers, null, $output);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows a summary of operations
|
||||
*
|
||||
* @param string[] $headers
|
||||
* @param string[] $rows
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
protected function showSummary($headers, $rows, OutputInterface $output) {
|
||||
$niceDate = $this->formatExecTime();
|
||||
if (!$rows) {
|
||||
$rows = [
|
||||
$this->foldersCounter,
|
||||
$this->filesCounter,
|
||||
$niceDate,
|
||||
];
|
||||
}
|
||||
$table = new Table($output);
|
||||
$table
|
||||
->setHeaders($headers)
|
||||
->setRows([$rows]);
|
||||
$table->render();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats microtime into a human readable format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatExecTime() {
|
||||
list($secs, $tens) = explode('.', sprintf("%.1f", ($this->execTime)));
|
||||
$niceDate = date('H:i:s', $secs) . '.' . $tens;
|
||||
|
||||
return $niceDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
|
|||
exit;
|
||||
}
|
||||
|
||||
$ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filename ));
|
||||
$ftype=\OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filename ));
|
||||
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
|
|
|
@ -617,7 +617,16 @@
|
|||
|
||||
this.registerAction({
|
||||
name: 'Delete',
|
||||
displayName: t('files', 'Delete'),
|
||||
displayName: function(context) {
|
||||
var mountType = context.$file.attr('data-mounttype');
|
||||
var deleteTitle = t('files', 'Delete');
|
||||
if (mountType === 'external-root') {
|
||||
deleteTitle = t('files', 'Disconnect storage');
|
||||
} else if (mountType === 'shared-root') {
|
||||
deleteTitle = t('files', 'Unshare');
|
||||
}
|
||||
return deleteTitle;
|
||||
},
|
||||
mime: 'all',
|
||||
order: 1000,
|
||||
// permission is READ because we show a hint instead if there is no permission
|
||||
|
@ -668,8 +677,9 @@
|
|||
* @typedef {Object} OCA.Files.FileAction
|
||||
*
|
||||
* @property {String} name identifier of the action
|
||||
* @property {String} displayName display name of the action, defaults
|
||||
* to the name given in name property
|
||||
* @property {(String|OCA.Files.FileActions~displayNameFunction)} displayName
|
||||
* display name string for the action, or function that returns the display name.
|
||||
* Defaults to the name given in name property
|
||||
* @property {String} mime mime type
|
||||
* @property {int} permissions permissions
|
||||
* @property {(Function|String)} icon icon path to the icon or function
|
||||
|
@ -702,6 +712,16 @@
|
|||
* @return {Object} jQuery link object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display name function for actions.
|
||||
* The function returns the display name of the action using
|
||||
* the given context information..
|
||||
*
|
||||
* @callback OCA.Files.FileActions~displayNameFunction
|
||||
* @param {OCA.Files.FileActionContext} context action context
|
||||
* @return {String} display name
|
||||
*/
|
||||
|
||||
/**
|
||||
* Action handler function for file actions
|
||||
*
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
* Renders the menu with the currently set items
|
||||
*/
|
||||
render: function() {
|
||||
var self = this;
|
||||
var fileActions = this._context.fileActions;
|
||||
var actions = fileActions.getActions(
|
||||
fileActions.getCurrentMimeType(),
|
||||
|
@ -100,6 +101,13 @@
|
|||
(!defaultAction || actionSpec.name !== defaultAction.name)
|
||||
);
|
||||
});
|
||||
items = _.map(items, function(item) {
|
||||
if (_.isFunction(item.displayName)) {
|
||||
item = _.extend({}, item);
|
||||
item.displayName = item.displayName(self._context);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
items = items.sort(function(actionA, actionB) {
|
||||
var orderA = actionA.order || 0;
|
||||
var orderB = actionB.order || 0;
|
||||
|
|
|
@ -990,13 +990,16 @@
|
|||
}
|
||||
|
||||
if (fileData.mountType) {
|
||||
// FIXME: HACK: detect shared-root
|
||||
if (fileData.mountType === 'shared' && this.dirInfo.mountType !== 'shared') {
|
||||
// if parent folder isn't share, assume the displayed folder is a share root
|
||||
fileData.mountType = 'shared-root';
|
||||
} else if (fileData.mountType === 'external' && this.dirInfo.mountType !== 'external') {
|
||||
// if parent folder isn't external, assume the displayed folder is the external storage root
|
||||
fileData.mountType = 'external-root';
|
||||
// dirInfo (parent) only exist for the "real" file list
|
||||
if (this.dirInfo.id) {
|
||||
// FIXME: HACK: detect shared-root
|
||||
if (fileData.mountType === 'shared' && this.dirInfo.mountType !== 'shared' && this.dirInfo.mountType !== 'shared-root') {
|
||||
// if parent folder isn't share, assume the displayed folder is a share root
|
||||
fileData.mountType = 'shared-root';
|
||||
} else if (fileData.mountType === 'external' && this.dirInfo.mountType !== 'external' && this.dirInfo.mountType !== 'external-root') {
|
||||
// if parent folder isn't external, assume the displayed folder is the external storage root
|
||||
fileData.mountType = 'external-root';
|
||||
}
|
||||
}
|
||||
tr.attr('data-mounttype', fileData.mountType);
|
||||
}
|
||||
|
@ -1065,7 +1068,7 @@
|
|||
nameSpan.tooltip({placement: 'right'});
|
||||
}
|
||||
// dirs can show the number of uploaded files
|
||||
if (mime !== 'httpd/unix-directory') {
|
||||
if (mime === 'httpd/unix-directory') {
|
||||
linkElem.append($('<span></span>').attr({
|
||||
'class': 'uploadtext',
|
||||
'currentUploads': 0
|
||||
|
@ -1380,7 +1383,7 @@
|
|||
* Returns list of webdav properties to request
|
||||
*/
|
||||
_getWebdavProperties: function() {
|
||||
return this.filesClient.getPropfindProperties();
|
||||
return [].concat(this.filesClient.getPropfindProperties());
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2069,7 +2072,7 @@
|
|||
*/
|
||||
showFileBusyState: function(files, state) {
|
||||
var self = this;
|
||||
if (!_.isArray(files)) {
|
||||
if (!_.isArray(files) && !files.is) {
|
||||
files = [files];
|
||||
}
|
||||
|
||||
|
@ -2077,10 +2080,13 @@
|
|||
state = true;
|
||||
}
|
||||
|
||||
_.each(files, function($tr) {
|
||||
_.each(files, function(fileName) {
|
||||
// jquery element already ?
|
||||
if (!$tr.is) {
|
||||
$tr = self.findFileEl($tr);
|
||||
var $tr;
|
||||
if (_.isString(fileName)) {
|
||||
$tr = self.findFileEl(fileName);
|
||||
} else {
|
||||
$tr = $(fileName);
|
||||
}
|
||||
|
||||
var $thumbEl = $tr.find('.thumbnail');
|
||||
|
@ -2465,6 +2471,7 @@
|
|||
}
|
||||
});
|
||||
fileUploadStart.on('fileuploadadd', function(e, data) {
|
||||
console.log('XXXXXXX');
|
||||
OC.Upload.log('filelist handle fileuploadadd', e, data);
|
||||
|
||||
//finish delete if we are uploading a deleted file
|
||||
|
@ -2484,8 +2491,7 @@
|
|||
|
||||
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
|
||||
if (currentUploads === 1) {
|
||||
var img = OC.imagePath('core', 'loading.gif');
|
||||
data.context.find('.thumbnail').css('background-image', 'url(' + img + ')');
|
||||
self.showFileBusyState(uploadText.closest('tr'), true);
|
||||
uploadText.text(translatedText);
|
||||
uploadText.show();
|
||||
} else {
|
||||
|
@ -2523,8 +2529,7 @@
|
|||
uploadText.attr('currentUploads', currentUploads);
|
||||
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
|
||||
if (currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder');
|
||||
data.context.find('.thumbnail').css('background-image', 'url(' + img + ')');
|
||||
self.showFileBusyState(uploadText.closest('tr'), false);
|
||||
uploadText.text(translatedText);
|
||||
uploadText.hide();
|
||||
} else {
|
||||
|
@ -2601,18 +2606,15 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
fileUploadStart.on('fileuploadstop', function(e, data) {
|
||||
OC.Upload.log('filelist handle fileuploadstop', e, data);
|
||||
fileUploadStart.on('fileuploadstop', function() {
|
||||
OC.Upload.log('filelist handle fileuploadstop');
|
||||
|
||||
//cleanup uploading to a dir
|
||||
var uploadText = self.$fileList.find('tr .uploadtext');
|
||||
self.showFileBusyState(uploadText.closest('tr'), false);
|
||||
uploadText.fadeOut();
|
||||
uploadText.attr('currentUploads', 0);
|
||||
|
||||
//if user pressed cancel hide upload chrome
|
||||
if (data.errorThrown === 'abort') {
|
||||
//cleanup uploading to a dir
|
||||
var uploadText = $('tr .uploadtext');
|
||||
var img = OC.imagePath('core', 'filetypes/folder');
|
||||
uploadText.parents('td.filename').find('.thumbnail').css('background-image', 'url(' + img + ')');
|
||||
uploadText.fadeOut();
|
||||
uploadText.attr('currentUploads', 0);
|
||||
}
|
||||
self.updateStorageStatistics();
|
||||
});
|
||||
fileUploadStart.on('fileuploadfail', function(e, data) {
|
||||
|
@ -2621,9 +2623,8 @@
|
|||
//if user pressed cancel hide upload chrome
|
||||
if (data.errorThrown === 'abort') {
|
||||
//cleanup uploading to a dir
|
||||
var uploadText = $('tr .uploadtext');
|
||||
var img = OC.imagePath('core', 'filetypes/folder');
|
||||
uploadText.parents('td.filename').find('.thumbnail').css('background-image', 'url(' + img + ')');
|
||||
var uploadText = self.$fileList.find('tr .uploadtext');
|
||||
self.showFileBusyState(uploadText.closest('tr'), false);
|
||||
uploadText.fadeOut();
|
||||
uploadText.attr('currentUploads', 0);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ OC.L10N.register(
|
|||
"Download" : "تحميل",
|
||||
"Rename" : "إعادة التسمية",
|
||||
"Delete" : "حذف ",
|
||||
"Unshare" : "إلغاء المشاركة",
|
||||
"Details" : "تفاصيل",
|
||||
"Select" : "اختار",
|
||||
"Pending" : "قيد الانتظار",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"Download" : "تحميل",
|
||||
"Rename" : "إعادة التسمية",
|
||||
"Delete" : "حذف ",
|
||||
"Unshare" : "إلغاء المشاركة",
|
||||
"Details" : "تفاصيل",
|
||||
"Select" : "اختار",
|
||||
"Pending" : "قيد الانتظار",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renomar",
|
||||
"Delete" : "Desaniciar",
|
||||
"Disconnect storage" : "Desconeutar almacenamientu",
|
||||
"Unshare" : "Dexar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Select" : "Esbillar",
|
||||
"Pending" : "Pendiente",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renomar",
|
||||
"Delete" : "Desaniciar",
|
||||
"Disconnect storage" : "Desconeutar almacenamientu",
|
||||
"Unshare" : "Dexar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Select" : "Esbillar",
|
||||
"Pending" : "Pendiente",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Yüklə",
|
||||
"Rename" : "Adı dəyiş",
|
||||
"Delete" : "Sil",
|
||||
"Disconnect storage" : "Daşıyıcını ayır",
|
||||
"Unshare" : "Paylaşımı durdur",
|
||||
"Details" : "Detallar",
|
||||
"Select" : "Seç",
|
||||
"Pending" : "Gözləmə",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Yüklə",
|
||||
"Rename" : "Adı dəyiş",
|
||||
"Delete" : "Sil",
|
||||
"Disconnect storage" : "Daşıyıcını ayır",
|
||||
"Unshare" : "Paylaşımı durdur",
|
||||
"Details" : "Detallar",
|
||||
"Select" : "Seç",
|
||||
"Pending" : "Gözləmə",
|
||||
|
|
|
@ -26,6 +26,7 @@ OC.L10N.register(
|
|||
"Download" : "ডাউনলোড",
|
||||
"Rename" : "পূনঃনামকরণ",
|
||||
"Delete" : "মুছে",
|
||||
"Unshare" : "ভাগাভাগি বাতিল ",
|
||||
"Details" : "বিস্তারিত",
|
||||
"Pending" : "মুলতুবি",
|
||||
"Name" : "রাম",
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"Download" : "ডাউনলোড",
|
||||
"Rename" : "পূনঃনামকরণ",
|
||||
"Delete" : "মুছে",
|
||||
"Unshare" : "ভাগাভাগি বাতিল ",
|
||||
"Details" : "বিস্তারিত",
|
||||
"Pending" : "মুলতুবি",
|
||||
"Name" : "রাম",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Preuzmi",
|
||||
"Rename" : "Preimenuj",
|
||||
"Delete" : "Izbriši",
|
||||
"Disconnect storage" : "Diskonektuj pohranu",
|
||||
"Unshare" : "Prestani dijeliti",
|
||||
"Select" : "Izaberi",
|
||||
"Pending" : "Na čekanju",
|
||||
"Unable to determine date" : "Nemoguće odrediti datum",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Preuzmi",
|
||||
"Rename" : "Preimenuj",
|
||||
"Delete" : "Izbriši",
|
||||
"Disconnect storage" : "Diskonektuj pohranu",
|
||||
"Unshare" : "Prestani dijeliti",
|
||||
"Select" : "Izaberi",
|
||||
"Pending" : "Na čekanju",
|
||||
"Unable to determine date" : "Nemoguće odrediti datum",
|
||||
|
|
|
@ -5,6 +5,7 @@ OC.L10N.register(
|
|||
"Files" : "Dateien",
|
||||
"Download" : "Herunterladen",
|
||||
"Delete" : "Löschen",
|
||||
"Unshare" : "Teilung zurücknehmen",
|
||||
"Details" : "Details",
|
||||
"New folder" : "Neuer Ordner",
|
||||
"Upload" : "Hochladen",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"Files" : "Dateien",
|
||||
"Download" : "Herunterladen",
|
||||
"Delete" : "Löschen",
|
||||
"Unshare" : "Teilung zurücknehmen",
|
||||
"Details" : "Details",
|
||||
"New folder" : "Neuer Ordner",
|
||||
"Upload" : "Hochladen",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Herunterladen",
|
||||
"Rename" : "Umbenennen",
|
||||
"Delete" : "Löschen",
|
||||
"Disconnect storage" : "Speicher trennen",
|
||||
"Unshare" : "Freigabe aufheben",
|
||||
"Details" : "Details",
|
||||
"Select" : "Auswählen",
|
||||
"Pending" : "Ausstehend",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Herunterladen",
|
||||
"Rename" : "Umbenennen",
|
||||
"Delete" : "Löschen",
|
||||
"Disconnect storage" : "Speicher trennen",
|
||||
"Unshare" : "Freigabe aufheben",
|
||||
"Details" : "Details",
|
||||
"Select" : "Auswählen",
|
||||
"Pending" : "Ausstehend",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Λήψη",
|
||||
"Rename" : "Μετονομασία",
|
||||
"Delete" : "Διαγραφή",
|
||||
"Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
|
||||
"Unshare" : "Διακοπή διαμοιρασμού",
|
||||
"Details" : "Λεπτομέρειες",
|
||||
"Select" : "Επιλογή",
|
||||
"Pending" : "Εκκρεμεί",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Λήψη",
|
||||
"Rename" : "Μετονομασία",
|
||||
"Delete" : "Διαγραφή",
|
||||
"Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
|
||||
"Unshare" : "Διακοπή διαμοιρασμού",
|
||||
"Details" : "Λεπτομέρειες",
|
||||
"Select" : "Επιλογή",
|
||||
"Pending" : "Εκκρεμεί",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Download",
|
||||
"Rename" : "Rename",
|
||||
"Delete" : "Delete",
|
||||
"Disconnect storage" : "Disconnect storage",
|
||||
"Unshare" : "Unshare",
|
||||
"Details" : "Details",
|
||||
"Select" : "Select",
|
||||
"Pending" : "Pending",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Download",
|
||||
"Rename" : "Rename",
|
||||
"Delete" : "Delete",
|
||||
"Disconnect storage" : "Disconnect storage",
|
||||
"Unshare" : "Unshare",
|
||||
"Details" : "Details",
|
||||
"Select" : "Select",
|
||||
"Pending" : "Pending",
|
||||
|
|
|
@ -28,6 +28,7 @@ OC.L10N.register(
|
|||
"Download" : "Elŝuti",
|
||||
"Rename" : "Alinomigi",
|
||||
"Delete" : "Forigi",
|
||||
"Unshare" : "Malkunhavigi",
|
||||
"Details" : "Detaloj",
|
||||
"Select" : "Elekti",
|
||||
"Pending" : "Traktotaj",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"Download" : "Elŝuti",
|
||||
"Rename" : "Alinomigi",
|
||||
"Delete" : "Forigi",
|
||||
"Unshare" : "Malkunhavigi",
|
||||
"Details" : "Detaloj",
|
||||
"Select" : "Elekti",
|
||||
"Pending" : "Traktotaj",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renombrar",
|
||||
"Delete" : "Eliminar",
|
||||
"Disconnect storage" : "Desconectar almacenamiento",
|
||||
"Unshare" : "Dejar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Select" : "Seleccionar",
|
||||
"Pending" : "Pendiente",
|
||||
|
@ -97,6 +99,7 @@ OC.L10N.register(
|
|||
"Maximum upload size" : "Tamaño máximo de subida",
|
||||
"max. possible: " : "máx. posible:",
|
||||
"Save" : "Guardar",
|
||||
"Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.",
|
||||
"Settings" : "Ajustes",
|
||||
"WebDAV" : "WebDAV",
|
||||
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use esta URL <a href=\"%s\" target=\"_blank\">para acceder via WebDAV</a>",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renombrar",
|
||||
"Delete" : "Eliminar",
|
||||
"Disconnect storage" : "Desconectar almacenamiento",
|
||||
"Unshare" : "Dejar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Select" : "Seleccionar",
|
||||
"Pending" : "Pendiente",
|
||||
|
@ -95,6 +97,7 @@
|
|||
"Maximum upload size" : "Tamaño máximo de subida",
|
||||
"max. possible: " : "máx. posible:",
|
||||
"Save" : "Guardar",
|
||||
"Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.",
|
||||
"Settings" : "Ajustes",
|
||||
"WebDAV" : "WebDAV",
|
||||
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use esta URL <a href=\"%s\" target=\"_blank\">para acceder via WebDAV</a>",
|
||||
|
|
|
@ -28,6 +28,7 @@ OC.L10N.register(
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renombrar",
|
||||
"Delete" : "Eliminar",
|
||||
"Unshare" : "Dejar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Pending" : "Pendiente",
|
||||
"Name" : "Nombre",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"Download" : "Descargar",
|
||||
"Rename" : "Renombrar",
|
||||
"Delete" : "Eliminar",
|
||||
"Unshare" : "Dejar de compartir",
|
||||
"Details" : "Detalles",
|
||||
"Pending" : "Pendiente",
|
||||
"Name" : "Nombre",
|
||||
|
|
|
@ -34,12 +34,19 @@ OC.L10N.register(
|
|||
"Download" : "Lae alla",
|
||||
"Rename" : "Nimeta ümber",
|
||||
"Delete" : "Kustuta",
|
||||
"Disconnect storage" : "Ühenda andmehoidla lahti.",
|
||||
"Unshare" : "Lõpeta jagamine",
|
||||
"Details" : "Üksikasjad",
|
||||
"Select" : "Vali",
|
||||
"Pending" : "Ootel",
|
||||
"Unable to determine date" : "Kuupäeva tuvastamine ei õnnestunud",
|
||||
"This operation is forbidden" : "See toiming on keelatud",
|
||||
"This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
|
||||
"Could not move \"{file}\"" : "\"{file}\" liigutamine ebaõnnestus",
|
||||
"{newName} already exists" : "{newName} on juba olemas",
|
||||
"Could not rename \"{fileName}\"" : "\"{fileName}\" ümbernimetamine ebaõnnestus",
|
||||
"Could not create file \"{file}\"" : "Faili \"{file}\" loomine ebaõnnestus",
|
||||
"Error deleting file \"{fileName}\"." : "Tõrge faili \"{fileName}\" kustutamisel.",
|
||||
"No entries in this folder match '{filter}'" : "Ükski sissekanne ei kattu filtriga '{filter}'",
|
||||
"Name" : "Nimi",
|
||||
"Size" : "Suurus",
|
||||
|
@ -62,6 +69,7 @@ OC.L10N.register(
|
|||
"Favorite" : "Lemmik",
|
||||
"Folder" : "Kaust",
|
||||
"New folder" : "Uus kaust",
|
||||
"{newname} already exists" : "{newname} on juba olemas",
|
||||
"Upload" : "Lae üles",
|
||||
"An error occurred while trying to update the tags" : "Siltide uuendamisel tekkis tõrge",
|
||||
"A new file or folder has been <strong>created</strong>" : "Uus fail või kataloog on <strong>loodud</strong>",
|
||||
|
@ -96,6 +104,7 @@ OC.L10N.register(
|
|||
"Currently scanning" : "Praegu skännimisel",
|
||||
"No favorites" : "Lemmikuid pole",
|
||||
"Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks",
|
||||
"Text file" : "Tekstifail"
|
||||
"Text file" : "Tekstifail",
|
||||
"New text file.txt" : "Uus tekstifail.txt"
|
||||
},
|
||||
"nplurals=2; plural=(n != 1);");
|
||||
|
|
|
@ -32,12 +32,19 @@
|
|||
"Download" : "Lae alla",
|
||||
"Rename" : "Nimeta ümber",
|
||||
"Delete" : "Kustuta",
|
||||
"Disconnect storage" : "Ühenda andmehoidla lahti.",
|
||||
"Unshare" : "Lõpeta jagamine",
|
||||
"Details" : "Üksikasjad",
|
||||
"Select" : "Vali",
|
||||
"Pending" : "Ootel",
|
||||
"Unable to determine date" : "Kuupäeva tuvastamine ei õnnestunud",
|
||||
"This operation is forbidden" : "See toiming on keelatud",
|
||||
"This directory is unavailable, please check the logs or contact the administrator" : "See kaust pole saadaval. Palun kontrolli logifaile või võta ühendust administraatoriga",
|
||||
"Could not move \"{file}\"" : "\"{file}\" liigutamine ebaõnnestus",
|
||||
"{newName} already exists" : "{newName} on juba olemas",
|
||||
"Could not rename \"{fileName}\"" : "\"{fileName}\" ümbernimetamine ebaõnnestus",
|
||||
"Could not create file \"{file}\"" : "Faili \"{file}\" loomine ebaõnnestus",
|
||||
"Error deleting file \"{fileName}\"." : "Tõrge faili \"{fileName}\" kustutamisel.",
|
||||
"No entries in this folder match '{filter}'" : "Ükski sissekanne ei kattu filtriga '{filter}'",
|
||||
"Name" : "Nimi",
|
||||
"Size" : "Suurus",
|
||||
|
@ -60,6 +67,7 @@
|
|||
"Favorite" : "Lemmik",
|
||||
"Folder" : "Kaust",
|
||||
"New folder" : "Uus kaust",
|
||||
"{newname} already exists" : "{newname} on juba olemas",
|
||||
"Upload" : "Lae üles",
|
||||
"An error occurred while trying to update the tags" : "Siltide uuendamisel tekkis tõrge",
|
||||
"A new file or folder has been <strong>created</strong>" : "Uus fail või kataloog on <strong>loodud</strong>",
|
||||
|
@ -94,6 +102,7 @@
|
|||
"Currently scanning" : "Praegu skännimisel",
|
||||
"No favorites" : "Lemmikuid pole",
|
||||
"Files and folders you mark as favorite will show up here" : "Siin kuvatakse faile ja kaustasid, mille oled märkinud lemmikuteks",
|
||||
"Text file" : "Tekstifail"
|
||||
"Text file" : "Tekstifail",
|
||||
"New text file.txt" : "Uus tekstifail.txt"
|
||||
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
||||
}
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Deskargatu",
|
||||
"Rename" : "Berrizendatu",
|
||||
"Delete" : "Ezabatu",
|
||||
"Disconnect storage" : "Deskonektatu biltegia",
|
||||
"Unshare" : "Ez elkarbanatu",
|
||||
"Details" : "Xehetasunak",
|
||||
"Select" : "hautatu",
|
||||
"Pending" : "Zain",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Deskargatu",
|
||||
"Rename" : "Berrizendatu",
|
||||
"Delete" : "Ezabatu",
|
||||
"Disconnect storage" : "Deskonektatu biltegia",
|
||||
"Unshare" : "Ez elkarbanatu",
|
||||
"Details" : "Xehetasunak",
|
||||
"Select" : "hautatu",
|
||||
"Pending" : "Zain",
|
||||
|
|
|
@ -34,6 +34,7 @@ OC.L10N.register(
|
|||
"Download" : "دانلود",
|
||||
"Rename" : "تغییرنام",
|
||||
"Delete" : "حذف",
|
||||
"Unshare" : "لغو اشتراک",
|
||||
"Details" : "جزئیات",
|
||||
"Select" : "انتخاب",
|
||||
"Pending" : "در انتظار",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"Download" : "دانلود",
|
||||
"Rename" : "تغییرنام",
|
||||
"Delete" : "حذف",
|
||||
"Unshare" : "لغو اشتراک",
|
||||
"Details" : "جزئیات",
|
||||
"Select" : "انتخاب",
|
||||
"Pending" : "در انتظار",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Lataa",
|
||||
"Rename" : "Nimeä uudelleen",
|
||||
"Delete" : "Poista",
|
||||
"Disconnect storage" : "Katkaise yhteys tallennustilaan",
|
||||
"Unshare" : "Peru jakaminen",
|
||||
"Details" : "Tiedot",
|
||||
"Select" : "Valitse",
|
||||
"Pending" : "Odottaa",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Lataa",
|
||||
"Rename" : "Nimeä uudelleen",
|
||||
"Delete" : "Poista",
|
||||
"Disconnect storage" : "Katkaise yhteys tallennustilaan",
|
||||
"Unshare" : "Peru jakaminen",
|
||||
"Details" : "Tiedot",
|
||||
"Select" : "Valitse",
|
||||
"Pending" : "Odottaa",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Télécharger",
|
||||
"Rename" : "Renommer",
|
||||
"Delete" : "Supprimer",
|
||||
"Disconnect storage" : "Déconnecter ce support de stockage",
|
||||
"Unshare" : "Ne plus partager",
|
||||
"Details" : "Détails",
|
||||
"Select" : "Sélectionner",
|
||||
"Pending" : "En attente",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"Download" : "Télécharger",
|
||||
"Rename" : "Renommer",
|
||||
"Delete" : "Supprimer",
|
||||
"Disconnect storage" : "Déconnecter ce support de stockage",
|
||||
"Unshare" : "Ne plus partager",
|
||||
"Details" : "Détails",
|
||||
"Select" : "Sélectionner",
|
||||
"Pending" : "En attente",
|
||||
|
|
|
@ -10,6 +10,7 @@ OC.L10N.register(
|
|||
"Close" : "Clauder",
|
||||
"Download" : "Discargar",
|
||||
"Delete" : "Deler",
|
||||
"Unshare" : "Leva compartir",
|
||||
"Name" : "Nomine",
|
||||
"Size" : "Dimension",
|
||||
"Modified" : "Modificate",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"Close" : "Clauder",
|
||||
"Download" : "Discargar",
|
||||
"Delete" : "Deler",
|
||||
"Unshare" : "Leva compartir",
|
||||
"Name" : "Nomine",
|
||||
"Size" : "Dimension",
|
||||
"Modified" : "Modificate",
|
||||
|
|
|
@ -34,6 +34,8 @@ OC.L10N.register(
|
|||
"Download" : "Unduh",
|
||||
"Rename" : "Ubah nama",
|
||||
"Delete" : "Hapus",
|
||||
"Disconnect storage" : "Memutuskan penyimpaan",
|
||||
"Unshare" : "Batalkan berbagi",
|
||||
"Details" : "Rincian",
|
||||
"Select" : "Pilih",
|
||||
"Pending" : "Tertunda",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue