summaryrefslogtreecommitdiffstats
path: root/apps/dav
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav')
-rw-r--r--apps/dav/lib/Avatars/AvatarHome.php120
-rw-r--r--apps/dav/lib/Avatars/AvatarNode.php98
-rw-r--r--apps/dav/lib/Avatars/RootCollection.php29
-rw-r--r--apps/dav/lib/Connector/Sabre/Principal.php2
-rw-r--r--apps/dav/lib/RootCollection.php4
-rw-r--r--apps/dav/tests/unit/Avatars/AvatarHomeTest.php125
-rw-r--r--apps/dav/tests/unit/Avatars/AvatarNodeTest.php48
-rw-r--r--apps/dav/tests/unit/phpunit.xml4
8 files changed, 427 insertions, 3 deletions
diff --git a/apps/dav/lib/Avatars/AvatarHome.php b/apps/dav/lib/Avatars/AvatarHome.php
new file mode 100644
index 00000000000..17ac37dc8af
--- /dev/null
+++ b/apps/dav/lib/Avatars/AvatarHome.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud GmbH
+ * @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\Avatars;
+
+
+use OCP\IAvatarManager;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ICollection;
+use Sabre\Uri;
+
+class AvatarHome implements ICollection {
+
+ /** @var array */
+ private $principalInfo;
+ /** @var IAvatarManager */
+ private $avatarManager;
+
+ /**
+ * AvatarHome constructor.
+ *
+ * @param array $principalInfo
+ * @param IAvatarManager $avatarManager
+ */
+ public function __construct($principalInfo, IAvatarManager $avatarManager) {
+ $this->principalInfo = $principalInfo;
+ $this->avatarManager = $avatarManager;
+ }
+
+ public function createFile($name, $data = null) {
+ throw new Forbidden('Permission denied to create a file');
+ }
+
+ public function createDirectory($name) {
+ throw new Forbidden('Permission denied to create a folder');
+ }
+
+ public function getChild($name) {
+ $elements = pathinfo($name);
+ $ext = isset($elements['extension']) ? $elements['extension'] : '';
+ $size = (int)(isset($elements['filename']) ? $elements['filename'] : '64');
+ if (!in_array($ext, ['jpeg', 'png'], true)) {
+ throw new MethodNotAllowed('File format not allowed');
+ }
+ if ($size <= 0 || $size > 1024) {
+ throw new MethodNotAllowed('Invalid image size');
+ }
+ $avatar = $this->avatarManager->getAvatar($this->getName());
+ if ($avatar === null || !$avatar->exists()) {
+ throw new NotFound();
+ }
+ return new AvatarNode($size, $ext, $avatar);
+ }
+
+ public function getChildren() {
+ try {
+ return [
+ $this->getChild('96.jpeg')
+ ];
+ } catch(NotFound $exception) {
+ return [];
+ }
+ }
+
+ public function childExists($name) {
+ try {
+ $ret = $this->getChild($name);
+ return $ret !== null;
+ } catch (NotFound $ex) {
+ return false;
+ } catch (MethodNotAllowed $ex) {
+ return false;
+ }
+ }
+
+ public function delete() {
+ throw new Forbidden('Permission denied to delete this folder');
+ }
+
+ public function getName() {
+ list(,$name) = Uri\split($this->principalInfo['uri']);
+ return $name;
+ }
+
+ public function setName($name) {
+ throw new Forbidden('Permission denied to rename this folder');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int|null
+ */
+ public function getLastModified() {
+ return null;
+ }
+
+
+}
diff --git a/apps/dav/lib/Avatars/AvatarNode.php b/apps/dav/lib/Avatars/AvatarNode.php
new file mode 100644
index 00000000000..4030f482510
--- /dev/null
+++ b/apps/dav/lib/Avatars/AvatarNode.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2016, ownCloud GmbH
+ * @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\Avatars;
+
+
+use OCP\IAvatar;
+use Sabre\DAV\File;
+
+class AvatarNode extends File {
+ private $ext;
+ private $size;
+ private $avatar;
+
+ /**
+ * AvatarNode constructor.
+ *
+ * @param integer $size
+ * @param string $ext
+ * @param IAvatar $avatar
+ */
+ public function __construct($size, $ext, $avatar) {
+ $this->size = $size;
+ $this->ext = $ext;
+ $this->avatar = $avatar;
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * This is used to generate the url.
+ *
+ * @return string
+ */
+ public function getName() {
+ return "$this->size.$this->ext";
+ }
+
+ public function get() {
+ $image = $this->avatar->get($this->size);
+ $res = $image->resource();
+
+ ob_start();
+ if ($this->ext === 'png') {
+ imagepng($res);
+ } else {
+ imagejpeg($res);
+ }
+
+ return ob_get_clean();
+ }
+
+ /**
+ * Returns the mime-type for a file
+ *
+ * If null is returned, we'll assume application/octet-stream
+ *
+ * @return string|null
+ */
+ public function getContentType() {
+ if ($this->ext === 'png') {
+ return 'image/png';
+ }
+ return 'image/jpeg';
+ }
+
+ public function getETag() {
+ return $this->avatar->getFile($this->size)->getEtag();
+ }
+
+ public function getLastModified() {
+ $timestamp = $this->avatar->getFile($this->size)->getMTime();
+ if (!empty($timestamp)) {
+ return (int)$timestamp;
+ }
+ return $timestamp;
+
+ }
+}
diff --git a/apps/dav/lib/Avatars/RootCollection.php b/apps/dav/lib/Avatars/RootCollection.php
new file mode 100644
index 00000000000..d7c7ff4e9fb
--- /dev/null
+++ b/apps/dav/lib/Avatars/RootCollection.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace OCA\DAV\Avatars;
+
+use Sabre\DAVACL\AbstractPrincipalCollection;
+
+
+class RootCollection extends AbstractPrincipalCollection {
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principalInfo
+ * @return AvatarHome
+ */
+ public function getChildForPrincipal(array $principalInfo) {
+ $avatarManager = \OC::$server->getAvatarManager();
+ return new AvatarHome($principalInfo, $avatarManager);
+ }
+
+ public function getName() {
+ return 'avatars';
+ }
+
+}
diff --git a/apps/dav/lib/Connector/Sabre/Principal.php b/apps/dav/lib/Connector/Sabre/Principal.php
index 9da416312d0..8713f61767b 100644
--- a/apps/dav/lib/Connector/Sabre/Principal.php
+++ b/apps/dav/lib/Connector/Sabre/Principal.php
@@ -223,8 +223,8 @@ class Principal implements BackendInterface {
$email = $user->getEMailAddress();
if (!empty($email)) {
$principal['{http://sabredav.org/ns}email-address'] = $email;
- return $principal;
}
+
return $principal;
}
diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php
index 478f0929c20..a243ec6d00a 100644
--- a/apps/dav/lib/RootCollection.php
+++ b/apps/dav/lib/RootCollection.php
@@ -99,6 +99,9 @@ class RootCollection extends SimpleCollection {
$uploadCollection = new Upload\RootCollection($userPrincipalBackend, 'principals/users');
$uploadCollection->disableListing = $disableListing;
+ $avatarCollection = new Avatars\RootCollection($userPrincipalBackend, 'principals/users');
+ $avatarCollection->disableListing = $disableListing;
+
$children = [
new SimpleCollection('principals', [
$userPrincipals,
@@ -114,6 +117,7 @@ class RootCollection extends SimpleCollection {
$systemTagRelationsCollection,
$commentsCollection,
$uploadCollection,
+ $avatarCollection
];
parent::__construct('root', $children);
diff --git a/apps/dav/tests/unit/Avatars/AvatarHomeTest.php b/apps/dav/tests/unit/Avatars/AvatarHomeTest.php
new file mode 100644
index 00000000000..ca8306e79a8
--- /dev/null
+++ b/apps/dav/tests/unit/Avatars/AvatarHomeTest.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2017, ownCloud GmbH
+ * @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\Avatars;
+
+
+use OCA\DAV\Avatars\AvatarHome;
+use OCA\DAV\Avatars\AvatarNode;
+use OCP\IAvatar;
+use OCP\IAvatarManager;
+use Sabre\DAV\Exception\MethodNotAllowed;
+use Sabre\DAV\Exception\NotFound;
+use Test\TestCase;
+
+class AvatarHomeTest extends TestCase {
+
+ /** @var AvatarHome */
+ private $home;
+
+ /** @var IAvatarManager | \PHPUnit_Framework_MockObject_MockObject */
+ private $avatarManager;
+
+ public function setUp() {
+ $this->avatarManager = $this->createMock(IAvatarManager::class);
+ $this->home = new AvatarHome(['uri' => 'principals/users/admin'], $this->avatarManager);
+ }
+
+ /**
+ * @expectedException \Sabre\DAV\Exception\Forbidden
+ * @dataProvider providesForbiddenMethods
+ */
+ public function testForbiddenMethods($method) {
+ $this->home->$method('');
+ }
+
+ public function providesForbiddenMethods() {
+ return [
+ ['createFile'],
+ ['createDirectory'],
+ ['delete'],
+ ['setName']
+ ];
+ }
+
+ public function testGetName() {
+ $n = $this->home->getName();
+ self::assertEquals('admin', $n);
+ }
+
+ public function providesTestGetChild() {
+ return [
+ [MethodNotAllowed::class, false, ''],
+ [MethodNotAllowed::class, false, 'bla.foo'],
+ [MethodNotAllowed::class, false, 'bla.png'],
+ [NotFound::class, false, '512.png'],
+ [null, true, '512.png'],
+ ];
+ }
+
+ /**
+ * @dataProvider providesTestGetChild
+ */
+ public function testGetChild($expectedException, $hasAvatar, $path) {
+ if ($expectedException !== null) {
+ $this->expectException($expectedException);
+ }
+ $avatar = null;
+ if ($hasAvatar) {
+ $avatar = $this->createMock(IAvatar::class);
+ $avatar->expects($this->once())->method('exists')->willReturn(true);
+ }
+ $this->avatarManager->expects($this->any())->method('getAvatar')->with('admin')->willReturn($avatar);
+ $avatarNode = $this->home->getChild($path);
+ $this->assertInstanceOf(AvatarNode::class, $avatarNode);
+ }
+
+ public function testGetChildren() {
+ $avatarNodes = $this->home->getChildren();
+ self::assertEquals(0, count($avatarNodes));
+
+ $avatar = $this->createMock(IAvatar::class);
+ $avatar->expects($this->once())->method('exists')->willReturn(true);
+ $this->avatarManager->expects($this->any())->method('getAvatar')->with('admin')->willReturn($avatar);
+ $avatarNodes = $this->home->getChildren();
+ self::assertEquals(1, count($avatarNodes));
+ }
+
+ /**
+ * @dataProvider providesTestGetChild
+ */
+ public function testChildExists($expectedException, $hasAvatar, $path) {
+ $avatar = null;
+ if ($hasAvatar) {
+ $avatar = $this->createMock(IAvatar::class);
+ $avatar->expects($this->once())->method('exists')->willReturn(true);
+ }
+ $this->avatarManager->expects($this->any())->method('getAvatar')->with('admin')->willReturn($avatar);
+ $childExists = $this->home->childExists($path);
+ $this->assertEquals($hasAvatar, $childExists);
+ }
+
+ public function testGetLastModified() {
+ self::assertNull($this->home->getLastModified());
+ }
+
+}
diff --git a/apps/dav/tests/unit/Avatars/AvatarNodeTest.php b/apps/dav/tests/unit/Avatars/AvatarNodeTest.php
new file mode 100644
index 00000000000..8e56ea6f6df
--- /dev/null
+++ b/apps/dav/tests/unit/Avatars/AvatarNodeTest.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2017, ownCloud GmbH
+ * @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\Avatars;
+
+
+use OCA\DAV\Avatars\AvatarNode;
+use OCP\IAvatar;
+use Test\TestCase;
+
+class AvatarNodeTest extends TestCase {
+
+ public function testGetName() {
+ /** @var IAvatar | \PHPUnit_Framework_MockObject_MockObject $a */
+ $a = $this->createMock(IAvatar::class);
+ $n = new AvatarNode(1024, 'png', $a);
+ $this->assertEquals('1024.png', $n->getName());
+ }
+
+ public function testGetContentType() {
+ /** @var IAvatar | \PHPUnit_Framework_MockObject_MockObject $a */
+ $a = $this->createMock(IAvatar::class);
+ $n = new AvatarNode(1024, 'png', $a);
+ $this->assertEquals('image/png', $n->getContentType());
+
+ $n = new AvatarNode(1024, 'jpeg', $a);
+ $this->assertEquals('image/jpeg', $n->getContentType());
+ }
+}
diff --git a/apps/dav/tests/unit/phpunit.xml b/apps/dav/tests/unit/phpunit.xml
index e483515ca7a..3f0a9107aaa 100644
--- a/apps/dav/tests/unit/phpunit.xml
+++ b/apps/dav/tests/unit/phpunit.xml
@@ -11,9 +11,9 @@
<!-- filters for code coverage -->
<filter>
<whitelist>
- <directory suffix=".php">../../dav</directory>
+ <directory suffix=".php">../../../dav</directory>
<exclude>
- <directory suffix=".php">../../dav/tests</directory>
+ <directory suffix=".php">../../../dav/tests</directory>
</exclude>
</whitelist>
</filter>