diff --git a/apps/dav/lib/Avatars/AvatarHome.php b/apps/dav/lib/Avatars/AvatarHome.php
new file mode 100644
index 000000000000..9e00fe2e8f48
--- /dev/null
+++ b/apps/dav/lib/Avatars/AvatarHome.php
@@ -0,0 +1,119 @@
+
+ *
+ * @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
+ *
+ */
+
+
+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\HTTP\URLUtil;
+
+class AvatarHome implements ICollection {
+
+ /** @var array */
+ private $principalInfo;
+ /** @var IAvatarManager */
+ private $avatarManager;
+
+ /**
+ * AvatarHome constructor.
+ *
+ * @param array $principalInfo
+ */
+ public function __construct($principalInfo, IAvatarManager $avatarManager) {
+ $this->principalInfo = $principalInfo;
+ $this->avatarManager = $avatarManager;
+ }
+
+ function createFile($name, $data = null) {
+ throw new Forbidden('Permission denied to create a file');
+ }
+
+ function createDirectory($name) {
+ throw new Forbidden('Permission denied to create a folder');
+ }
+
+ function getChild($name) {
+ $elements = pathinfo($name);
+ $ext = isset($elements['extension']) ? $elements['extension'] : '';
+ $size = intval(isset($elements['filename']) ? $elements['filename'] : '64');
+ if (!in_array($ext, ['jpeg', 'png'])) {
+ 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);
+ }
+
+ function getChildren() {
+ try {
+ return [
+ $this->getChild('96.jpeg')
+ ];
+ } catch(NotFound $exception) {
+ return [];
+ }
+ }
+
+ function childExists($name) {
+ try {
+ $ret = $this->getChild($name);
+ return !is_null($ret);
+ } catch (NotFound $ex) {
+ return false;
+ } catch (MethodNotAllowed $ex) {
+ return false;
+ }
+ }
+
+ function delete() {
+ throw new Forbidden('Permission denied to delete this folder');
+ }
+
+ function getName() {
+ list(,$name) = URLUtil::splitPath($this->principalInfo['uri']);
+ return $name;
+ }
+
+ function setName($name) {
+ throw new Forbidden('Permission denied to rename this folder');
+ }
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ 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 000000000000..270f66d6dbe5
--- /dev/null
+++ b/apps/dav/lib/Avatars/AvatarNode.php
@@ -0,0 +1,97 @@
+
+ *
+ * @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
+ *
+ */
+
+
+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
+ */
+ function getName() {
+ return "$this->size.$this->ext";
+ }
+
+ function get() {
+ $image = $this->avatar->get($this->size);
+ $res = $image->resource();
+
+ ob_start();
+ if ($this->ext === 'png') {
+ imagepng($res);
+ }
+ 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
+ */
+ function getContentType() {
+ if ($this->ext === 'png') {
+ return 'image/png';
+ }
+ return 'image/jpeg';
+ }
+
+ function getETag() {
+ return $this->avatar->getFile($this->size)->getEtag();
+ }
+
+ 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 000000000000..8614d5d22b00
--- /dev/null
+++ b/apps/dav/lib/Avatars/RootCollection.php
@@ -0,0 +1,29 @@
+getAvatarManager();
+ return new AvatarHome($principalInfo, $avatarManager);
+ }
+
+ function getName() {
+ return 'avatars';
+ }
+
+}
diff --git a/apps/dav/lib/Connector/Sabre/Principal.php b/apps/dav/lib/Connector/Sabre/Principal.php
index 3ed730ed0f59..47e81c50797c 100644
--- a/apps/dav/lib/Connector/Sabre/Principal.php
+++ b/apps/dav/lib/Connector/Sabre/Principal.php
@@ -222,8 +222,8 @@ protected function userToPrincipal($user) {
$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 6cfe7a7d8ef8..8965c0c92550 100644
--- a/apps/dav/lib/RootCollection.php
+++ b/apps/dav/lib/RootCollection.php
@@ -89,6 +89,9 @@ public function __construct() {
$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,
@@ -103,6 +106,7 @@ public function __construct() {
$systemTagCollection,
$systemTagRelationsCollection,
$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 000000000000..ca8306e79a84
--- /dev/null
+++ b/apps/dav/tests/unit/Avatars/AvatarHomeTest.php
@@ -0,0 +1,125 @@
+
+ *
+ * @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
+ *
+ */
+
+
+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 000000000000..8e56ea6f6dfc
--- /dev/null
+++ b/apps/dav/tests/unit/Avatars/AvatarNodeTest.php
@@ -0,0 +1,48 @@
+
+ *
+ * @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
+ *
+ */
+
+
+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 e483515ca7a1..3f0a9107aaa3 100644
--- a/apps/dav/tests/unit/phpunit.xml
+++ b/apps/dav/tests/unit/phpunit.xml
@@ -11,9 +11,9 @@
- ../../dav
+ ../../../dav
- ../../dav/tests
+ ../../../dav/tests