Skip to content

Commit

Permalink
Merge pull request #241 from nextcloud/feat/dav
Browse files Browse the repository at this point in the history
feat: Provide limit via dav property
  • Loading branch information
Pytal authored Mar 22, 2024
2 parents e655a79 + 2962467 commit 1b72bef
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 2 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,41 @@ jsonpath "$.ocs.data.limit" exists
jsonpath "$.ocs.data.count" exists
```

#### PropFind

```sh
hurl propfind.hurl --variable owner=admin --variable path=/welcome.txt
```

> propfind.hurl
````hurl
PROPFIND https://nextcloud.local/remote.php/dav/files/{{owner}}/{{path}}
[BasicAuth]
{{owner}}: {{owner}}
```xml
<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
<d:prop>
<oc:fileid />
<d:displayname />
<d:getlastmodified />
<d:getcontenttype />
<oc:size />
<oc:owner-id />
<oc:share-types />
<nc:sharees />
<nc:share-download-limits />
</d:prop>
</d:propfind>
```
HTTP 207
[Asserts]
xpath "//nc:share-download-limits" isCollection
````

#### Set

```sh
Expand Down
4 changes: 4 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@

namespace OCA\Files_DownloadLimit\AppInfo;

use OCA\DAV\Events\SabrePluginAddEvent;
use OCA\Files\Event\LoadSidebar;
use OCA\Files_DownloadLimit\Capabilities;
use OCA\Files_DownloadLimit\Listener\BeforeTemplateRenderedListener;
use OCA\Files_DownloadLimit\Listener\LoadSidebarListener;
use OCA\Files_DownloadLimit\Listener\SabrePluginAddListener;
use OCA\Files_DownloadLimit\Listener\ShareLinkAccessedListener;
use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
Expand All @@ -47,6 +49,8 @@ public function __construct(array $urlParams = []) {
}

public function register(IRegistrationContext $context): void {
$context->registerEventListener(SabrePluginAddEvent::class, SabrePluginAddListener::class);

$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
$context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class);
$context->registerEventListener(ShareLinkAccessedEvent::class, ShareLinkAccessedListener::class);
Expand Down
113 changes: 113 additions & 0 deletions lib/Dav/PropFindPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

declare(strict_types=1);

/**
* @copyright 2024 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Files_DownloadLimit\Dav;

use OCA\DAV\Connector\Sabre\File as SabreFile;
use OCA\Files_DownloadLimit\Db\Limit;
use OCA\Files_DownloadLimit\Db\LimitMapper;
use OCA\Files_DownloadLimit\LimitList;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\Files\File;
use OCP\IUser;
use OCP\IUserSession;
use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare;
use Psr\Log\LoggerInterface;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;

class PropFindPlugin extends ServerPlugin {
public const DOWNLOAD_LIMITS_PROPERTY = '{http://nextcloud.org/ns}share-download-limits';

public function __construct(
private IShareManager $shareManager,
private IUserSession $userSession,
private LimitMapper $limitMapper,
private LoggerInterface $logger,
) {
}

public function initialize(Server $server): void {
$server->on('propFind', [$this, 'propFind']);
}

public function propFind(PropFind $propFind, INode $node) {
if (!in_array(static::DOWNLOAD_LIMITS_PROPERTY, $propFind->getRequestedProperties(), true)) {
return;
}

if (!($node instanceof SabreFile)) { // Only allowed on files
return;
}

$propFind->handle(
static::DOWNLOAD_LIMITS_PROPERTY,
function () use ($node) {
$user = $this->userSession->getUser();
if (!($user instanceof IUser)) {
return new LimitList([]);
}

$externalShares = $this->getSharesForTypes(
$user,
$node->getNode(),
[
IShare::TYPE_LINK,
IShare::TYPE_EMAIL,
],
);

/** @var Limit[] $limits */
$limits = array_values(array_filter(array_map(function (IShare $share) {
try {
return $this->limitMapper->get($share->getToken());
} catch (DoesNotExistException $e) {
// Allow as no limit has been set
return null;
}
}, $externalShares)));

return new LimitList($limits);
},
);
}

/**
* @param int[] $types
* @return IShare[]
*/
private function getSharesForTypes(IUser $user, File $file, array $types) {
/** @var IShare[] $shares */
$shares = [];
foreach ($types as $type) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($user->getUID(), $type, $file, false, -1, 0));
}
return $shares;
}
}
57 changes: 57 additions & 0 deletions lib/LimitList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

/**
* @copyright 2024 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Files_DownloadLimit;

use OCA\Files_DownloadLimit\Db\Limit;
use Sabre\Xml\Writer;
use Sabre\Xml\XmlSerializable;

class LimitList implements XmlSerializable {
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';

/** @var Limit[] */
private $limits;

/**
* @param Limit[] $limits
*/
public function __construct(
array $limits,
) {
$this->limits = $limits;
}

public function xmlSerialize(Writer $writer): void {
foreach ($this->limits as $limit) {
$writer->startElement('{' . static::NS_NEXTCLOUD . '}share-download-limit');
$writer->writeElement('{' . static::NS_NEXTCLOUD . '}token', $limit->getId());
$writer->writeElement('{' . static::NS_NEXTCLOUD . '}limit', $limit->getLimit());
$writer->writeElement('{' . static::NS_NEXTCLOUD . '}count', $limit->getDownloads());
$writer->endElement();
}
}
}
51 changes: 51 additions & 0 deletions lib/Listener/SabrePluginAddListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

/**
* @copyright 2024 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Files_DownloadLimit\Listener;

use OCA\DAV\Events\SabrePluginAddEvent;
use OCA\Files_DownloadLimit\Dav\PropFindPlugin;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use Psr\Container\ContainerInterface;

/** @template-implements IEventListener<SabrePluginAddEvent> */
class SabrePluginAddListener implements IEventListener {
public function __construct(
private ContainerInterface $container,
) {
}

public function handle(Event $event): void {
if (!($event instanceof SabrePluginAddEvent)) {
return;
}

$server = $event->getServer();
$plugin = $this->container->get(PropFindPlugin::class);
$server->addPlugin($plugin);
}
}
8 changes: 6 additions & 2 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@
<issueHandlers>
<UndefinedClass>
<errorLevel type="suppress">
<referencedClass name="Doctrine\DBAL\Types\Types" />
<referencedClass name="OCA\DAV\Events\SabrePluginAddEvent" />
<referencedClass name="OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent" />
<referencedClass name="OCA\Files_Sharing\Event\ShareLinkAccessedEvent" />
<referencedClass name="Doctrine\DBAL\Types\Types" />
<referencedClass name="OCA\Files\Event\LoadSidebar" />
<referencedClass name="Sabre\DAV\ServerPlugin" />
<referencedClass name="Sabre\Xml\XmlSerializable" />
</errorLevel>
</UndefinedClass>
<UndefinedDocblockClass>
<errorLevel type="suppress">
<referencedClass name="Doctrine\DBAL\Schema\Table" />
<referencedClass name="OCA\DAV\Events\SabrePluginAddEvent" />
<referencedClass name="OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent" />
<referencedClass name="OCA\Files_Sharing\Event\ShareLinkAccessedEvent" />
<referencedClass name="Doctrine\DBAL\Schema\Table" />
<referencedClass name="OCA\Files\Event\LoadSidebar" />
</errorLevel>
</UndefinedDocblockClass>
Expand Down
11 changes: 11 additions & 0 deletions tests/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,15 @@
<code>$event</code>
</ImplementedParamTypeMismatch>
</file>
<file src="lib/Listener/SabrePluginAddListener.php">
<InvalidTemplateParam>
<code>IEventListener</code>
</InvalidTemplateParam>
<ImplementedParamTypeMismatch>
<code>$event</code>
</ImplementedParamTypeMismatch>
<MissingDependency>
<code>PropFindPlugin</code>
</MissingDependency>
</file>
</files>

0 comments on commit 1b72bef

Please sign in to comment.