Skip to content

Commit 2e32e0c

Browse files
committed
wip: test dav collection
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent 4d27629 commit 2e32e0c

4 files changed

Lines changed: 208 additions & 1 deletion

File tree

appinfo/info.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<name>Recommendations</name>
1010
<summary>Shows recommended files</summary>
1111
<description>Shows recommended files for quick access of files and folders with recent activity</description>
12-
<version>5.0.0-dev.0</version>
12+
<version>5.0.0-dev.1</version>
1313
<licence>agpl</licence>
1414
<author>Christoph Wurst</author>
1515
<author>Jan-Christoph Borchardt</author>
@@ -19,7 +19,16 @@
1919
<dependencies>
2020
<nextcloud min-version="32" max-version="32" />
2121
</dependencies>
22+
<types>
23+
<filesystem/>
24+
<dav/>
25+
</types>
2226
<commands>
2327
<command>OCA\Recommendations\Command\GetRecommendations</command>
2428
</commands>
29+
<sabre>
30+
<collections>
31+
<collection>OCA\Recommendations\Sabre\RootCollection</collection>
32+
</collections>
33+
</sabre>
2534
</info>

lib/AppInfo/Application.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace OCA\Recommendations\AppInfo;
1111

12+
use OCA\DAV\Connector\Sabre\Principal;
1213
use OCA\Files\Event\LoadAdditionalScriptsEvent;
1314
use OCA\Recommendations\Capabilities;
1415
use OCA\Recommendations\Dashboard\RecommendationWidget;
@@ -29,6 +30,7 @@ public function register(IRegistrationContext $context): void {
2930
$context->registerEventListener(LoadAdditionalScriptsEvent::class, FilesLoadAdditionalScriptsListener::class);
3031
$context->registerDashboardWidget(RecommendationWidget::class);
3132
$context->registerCapability(Capabilities::class);
33+
$context->registerServiceAlias('principalBackend', Principal::class);
3234
}
3335

3436
public function boot(IBootContext $context): void {

lib/Sabre/RecommendationsHome.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OCA\Recommendations\Sabre;
10+
11+
use OC\Files\Filesystem;
12+
use OC\Files\View;
13+
use OCA\DAV\Connector\Sabre\Directory;
14+
use OCA\DAV\Connector\Sabre\File;
15+
use OCA\Recommendations\AppInfo\Application;
16+
use OCA\Recommendations\Service\IRecommendation;
17+
use OCA\Recommendations\Service\RecommendationService;
18+
use OCP\Files\FileInfo;
19+
use OCP\IConfig;
20+
use OCP\IL10N;
21+
use OCP\IRequest;
22+
use OCP\IUser;
23+
use OCP\Share\IManager;
24+
use Sabre\DAV\Exception\Forbidden;
25+
use Sabre\DAV\Exception\NotFound;
26+
use Sabre\DAV\ICollection;
27+
28+
class RecommendationsHome implements ICollection {
29+
30+
/** @var ?list<IRecommendation> */
31+
private ?array $cachedRecommendations = null;
32+
33+
private View $fileView;
34+
35+
public function __construct(
36+
private array $principalInfo,
37+
private IUser $user,
38+
private IConfig $config,
39+
private RecommendationService $recommendationService,
40+
private IManager $shareManager,
41+
private IRequest $request,
42+
private IL10N $l10n,
43+
) {
44+
$this->fileView = Filesystem::getView();
45+
}
46+
47+
public function delete() {
48+
throw new Forbidden();
49+
}
50+
51+
public function getName(): string {
52+
[, $name] = \Sabre\Uri\split($this->principalInfo['uri']);
53+
return $name;
54+
}
55+
56+
public function setName($name) {
57+
throw new Forbidden();
58+
}
59+
60+
public function createFile($name, $data = null) {
61+
throw new Forbidden();
62+
}
63+
64+
public function createDirectory($name) {
65+
throw new Forbidden();
66+
}
67+
68+
public function getChild($name) {
69+
if (!$this->isEnabled()) {
70+
throw new NotFound('Recommendations are disabled');
71+
}
72+
73+
$recommendations = $this->getChildren();
74+
foreach ($recommendations as $child) {
75+
if ($child->getName() === $name) {
76+
return $child;
77+
}
78+
}
79+
80+
throw new NotFound("Child '$name' not found in recommendations");
81+
}
82+
83+
public function getChildren(): array {
84+
if (!$this->isEnabled()) {
85+
return [];
86+
}
87+
88+
if ($this->cachedRecommendations === null) {
89+
$this->cachedRecommendations = $this->recommendationService->getRecommendations($this->user);
90+
}
91+
92+
return array_map(
93+
function (IRecommendation $recommendation) {
94+
if ($recommendation->getNode()->getType() === FileInfo::TYPE_FOLDER) {
95+
return new Directory(
96+
$this->fileView,
97+
$this->fileView->getFileInfo($recommendation->getNode()->getInternalPath()),
98+
null,
99+
$this->shareManager,
100+
);
101+
}
102+
return new File(
103+
$this->fileView,
104+
$this->fileView->getFileInfo($recommendation->getNode()->getInternalPath()),
105+
$this->shareManager,
106+
$this->request,
107+
$this->l10n
108+
);
109+
},
110+
$this->cachedRecommendations
111+
);
112+
}
113+
114+
public function childExists($name): bool {
115+
if (!$this->isEnabled()) {
116+
return false;
117+
}
118+
// TODO: map the recommendations to a Sabre node type
119+
return true;
120+
}
121+
122+
public function getLastModified(): int {
123+
return 0;
124+
}
125+
126+
private function isEnabled(): bool {
127+
return $this->config->getUserValue($this->user->getUID(), Application::APP_ID, 'enabled', 'true') === 'true';
128+
}
129+
}

lib/Sabre/RootCollection.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OCA\Recommendations\Sabre;
10+
11+
use OCA\Recommendations\AppInfo\Application;
12+
use OCA\Recommendations\Service\RecommendationService;
13+
use OCP\IConfig;
14+
use OCP\IL10N;
15+
use OCP\IRequest;
16+
use OCP\IUserSession;
17+
use OCP\Share\IManager;
18+
use Sabre\DAV\Exception\Forbidden;
19+
use Sabre\DAV\INode;
20+
use Sabre\DAVACL\AbstractPrincipalCollection;
21+
use Sabre\DAVACL\PrincipalBackend;
22+
23+
class RootCollection extends AbstractPrincipalCollection {
24+
public function __construct(
25+
PrincipalBackend\BackendInterface $principalBackend,
26+
private IConfig $config,
27+
private RecommendationService $recommendationService,
28+
private IUserSession $userSession,
29+
private IManager $shareManager,
30+
private IRequest $request,
31+
private IL10N $l10n,
32+
) {
33+
parent::__construct($principalBackend, 'principals/users');
34+
$this->disableListing = !$config->getSystemValue('debug', false);
35+
}
36+
37+
/**
38+
* This method returns a node for a principal.
39+
*
40+
* The passed array contains principal information, and is guaranteed to
41+
* at least contain a uri item. Other properties may or may not be
42+
* supplied by the authentication backend.
43+
*
44+
* @param array $principalInfo
45+
* @return INode
46+
*/
47+
public function getChildForPrincipal(array $principalInfo): RecommendationsHome {
48+
[, $name] = \Sabre\Uri\split($principalInfo['uri']);
49+
$user = $this->userSession->getUser();
50+
if (is_null($user) || $name !== $user->getUID()) {
51+
throw new Forbidden();
52+
}
53+
return new RecommendationsHome(
54+
$principalInfo,
55+
$user,
56+
$this->config,
57+
$this->recommendationService,
58+
$this->shareManager,
59+
$this->request,
60+
$this->l10n,
61+
);
62+
}
63+
64+
public function getName(): string {
65+
return Application::APP_ID;
66+
}
67+
}

0 commit comments

Comments
 (0)