Skip to content

Commit

Permalink
feat(share): Add basic backend implementation for page shares
Browse files Browse the repository at this point in the history
Signed-off-by: Jonas <[email protected]>
  • Loading branch information
mejo- committed Dec 6, 2023
1 parent 3dcf043 commit f60036f
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 31 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ In your Nextcloud instance, simply navigate to **»Apps«**, find the
**»Circles«** and **»Collectives«** apps and enable them.
]]></description>
<version>2.9.2</version>
<version>2.10.0</version>
<licence>agpl</licence>
<author>CollectiveCloud Team</author>
<namespace>Collectives</namespace>
Expand Down
6 changes: 3 additions & 3 deletions lib/Controller/CollectiveController.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public function createShare(int $id): DataResponse {
return $this->prepareResponse(function () use ($id): array {
$userId = $this->getUserId();
$collectiveInfo = $this->service->getCollectiveInfo($id, $userId);
$share = $this->shareService->createShare($userId, $collectiveInfo);
$share = $this->shareService->createShare($userId, $collectiveInfo, null);
$collectiveInfo->setShareToken($share->getToken());
return [
"data" => $collectiveInfo
Expand All @@ -239,7 +239,7 @@ public function updateShare(int $id, string $token, bool $editable = false): Dat
return $this->prepareResponse(function () use ($id, $token, $editable): array {
$userId = $this->getUserId();
$collectiveInfo = $this->service->getCollectiveInfo($id, $userId);
$this->shareService->updateShare($userId, $collectiveInfo, $token, $editable);
$this->shareService->updateShare($userId, $collectiveInfo, null, $token, $editable);
$collectiveInfo = $this->service->getCollectiveWithShare($id, $userId);
return [
"data" => $collectiveInfo
Expand All @@ -259,7 +259,7 @@ public function deleteShare(int $id, string $token): DataResponse {
return $this->prepareResponse(function () use ($id, $token): array {
$userId = $this->getUserId();
$collectiveInfo = $this->service->getCollectiveInfo($id, $userId);
$this->shareService->deleteShare($userId, $id, $token);
$this->shareService->deleteShare($userId, $id, 0, $token);
return [
"data" => $collectiveInfo
];
Expand Down
4 changes: 4 additions & 0 deletions lib/Db/CollectiveShare.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@
* @method void setId(int $value)
* @method int getCollectiveId()
* @method void setCollectiveId(int $value)
* @method int getPageId()
* @method void setPageId(?int $value)
* @method string getToken()
* @method void setToken(string $value)
* @method string getOwner()
* @method void setOwner(string $value)
*/
class CollectiveShare extends Entity implements JsonSerializable {
protected ?int $collectiveId = null;
protected ?int $pageId = null;
protected ?string $token = null;
protected ?string $owner = null;

public function jsonSerialize(): array {
return [
'id' => $this->id,
'collectiveId' => (int)$this->collectiveId,
'pageId' => (int)$this->pageId,
'token' => $this->token,
'owner' => $this->owner,
];
Expand Down
12 changes: 9 additions & 3 deletions lib/Db/CollectiveShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public function findByCollectiveId(int $collectiveId): array {

/**
* @param int $collectiveId
* @param int $pageId
* @param string $userId
*
* @return CollectiveShare
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws Exception
*/
public function findOneByCollectiveIdAndUser(int $collectiveId, string $userId): CollectiveShare {
public function findOneByCollectiveIdAndUser(int $collectiveId, int $pageId, string $userId): CollectiveShare {
$qb = $this->db->getQueryBuilder();
$where = $qb->expr()->andX();
$where->add($qb->expr()->eq('collective_id', $qb->createNamedParameter($collectiveId, IQueryBuilder::PARAM_INT)));
$where->add($qb->expr()->eq('page_id', $qb->createNamedParameter($pageId, IQueryBuilder::PARAM_INT)));
$where->add($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
$qb->select('*')
->from($this->tableName)
Expand Down Expand Up @@ -83,6 +85,7 @@ public function findOneByToken(string $token): CollectiveShare {

/**
* @param int $collectiveId
* @param int $pageId
* @param string $token
* @param string $userId
*
Expand All @@ -91,10 +94,11 @@ public function findOneByToken(string $token): CollectiveShare {
* @throws Exception
* @throws MultipleObjectsReturnedException
*/
public function findOneByCollectiveIdAndTokenAndUser(int $collectiveId, string $token, string $userId): CollectiveShare {
public function findOneByCollectiveIdAndTokenAndUser(int $collectiveId, int $pageId, string $token, string $userId): CollectiveShare {
$qb = $this->db->getQueryBuilder();
$where = $qb->expr()->andX();
$where->add($qb->expr()->eq('collective_id', $qb->createNamedParameter($collectiveId, IQueryBuilder::PARAM_INT)));
$where->add($qb->expr()->eq('page_id', $qb->createNamedParameter($pageId, IQueryBuilder::PARAM_INT)));
$where->add($qb->expr()->eq('token', $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
$where->add($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
$qb->select('*')
Expand All @@ -105,15 +109,17 @@ public function findOneByCollectiveIdAndTokenAndUser(int $collectiveId, string $

/**
* @param int $collectiveId
* @param int $pageId
* @param string $token
* @param string $owner
*
* @return CollectiveShare
* @throws Exception
*/
public function create(int $collectiveId, string $token, string $owner): CollectiveShare {
public function create(int $collectiveId, int $pageId, string $token, string $owner): CollectiveShare {
$share = new CollectiveShare();
$share->setCollectiveId($collectiveId);
$share->setPageId($pageId);
$share->setToken($token);
$share->setOwner($owner);

Expand Down
4 changes: 4 additions & 0 deletions lib/Migration/Version001600Date20211025000000.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
$table->addColumn('collective_id', Types::BIGINT, [
'notnull' => true,
]);
$table->addColumn('page_id', Types::BIGINT, [
'notnull' => true,
'default' => 0,
]);
$table->addColumn('token', Types::STRING, [
'notnull' => true,
'length' => 64,
Expand Down
37 changes: 37 additions & 0 deletions lib/Migration/Version021000Date20231206000000.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace OCA\Collectives\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version021000Date20231206000000 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$table = $schema->getTable('collectives_shares');
if (!$table->hasColumn('page_id')) {
$table->addColumn('page_id', Types::BIGINT, [
'notnull' => true,
'default' => 0,
]);

return $schema;
}

return null;
}
}
2 changes: 2 additions & 0 deletions lib/Model/CollectiveShareInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function __construct(CollectiveShare $collectiveShare,
bool $editable = false) {
$this->id = $collectiveShare->getId();
$this->collectiveId = $collectiveShare->getCollectiveId();
$this->pageId = $collectiveShare->getPageId();
$this->token = $collectiveShare->getToken();
$this->owner = $collectiveShare->getOwner();
$this->editable = $editable;
Expand All @@ -29,6 +30,7 @@ public function jsonSerialize(): array {
return [
'id' => $this->id,
'collectiveId' => $this->collectiveId,
'pageId' => $this->pageId,
'token' => $this->token,
'owner' => $this->owner,
'editable' => $this->editable,
Expand Down
4 changes: 2 additions & 2 deletions lib/Service/CollectiveService.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private function initPageVersionsBackend(): void {
*/
public function getCollectiveWithShare(int $id, string $userId): CollectiveInfo {
$collectiveInfo = $this->getCollectiveInfo($id, $userId);
if (null !== $share = $this->shareService->findShare($userId, $id)) {
if (null !== $share = $this->shareService->findShare($userId, $id, 0)) {
$collectiveInfo->setShareToken($share->getToken());
$collectiveInfo->setShareEditable($share->getEditable());
}
Expand Down Expand Up @@ -124,7 +124,7 @@ public function getCollectives(string $userId): array {
public function getCollectivesWithShares(string $userId): array {
$collectiveInfos = $this->collectiveHelper->getCollectivesForUser($userId);
foreach ($collectiveInfos as $c) {
if (null !== $share = $this->shareService->findShare($userId, $c->getId())) {
if (null !== $share = $this->shareService->findShare($userId, $c->getId(), 0)) {
$c->setShareToken($share->getToken());
$c->setShareEditable($share->getEditable());
}
Expand Down
48 changes: 37 additions & 11 deletions lib/Service/CollectiveShareService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
use OCA\Collectives\Fs\UserFolderHelper;
use OCA\Collectives\Model\CollectiveInfo;
use OCA\Collectives\Model\CollectiveShareInfo;
use OCA\Collectives\Model\PageInfo;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\Constants;
use OCP\DB\Exception;
use OCP\Files\Folder;
use OCP\Files\NotFoundException as FilesNotFoundException;
use OCP\IL10N;
use OCP\Lock\ILockingProvider;
Expand Down Expand Up @@ -43,12 +45,13 @@ public function __construct(IShareManager $shareManager,
*
* @param string $userId
* @param string $collectiveName
* @param int $pageId
*
* @return IShare
* @throws NotFoundException
* @throws NotPermittedException
*/
public function createFolderShare(string $userId, string $collectiveName): IShare {
public function createFolderShare(string $userId, string $collectiveName, int $pageId): IShare {
$share = $this->shareManager->newShare();

$permissions = Constants::PERMISSION_READ;
Expand All @@ -62,6 +65,13 @@ public function createFolderShare(string $userId, string $collectiveName): IShar
$userFolder = $this->userFolderHelper->get($userId);
try {
$path = $userFolder->get($collectiveName);
if (!($path instanceof Folder)) {
throw new FilesNotFoundException();
}
if ($pageId) {
// TODO: share the parent folder if it's an index page
$path = $path->getById($pageId);
}
} catch (FilesNotFoundException $e) {
throw new NotFoundException('Wrong path, collective folder doesn\'t exist', 0, $e);
}
Expand Down Expand Up @@ -99,12 +109,13 @@ public function createFolderShare(string $userId, string $collectiveName): IShar
/**
* @param string $userId
* @param int $collectiveId
* @param int $pageId
*
* @return CollectiveShareInfo|null
*/
public function findShare(string $userId, int $collectiveId): ?CollectiveShareInfo {
public function findShare(string $userId, int $collectiveId, int $pageId): ?CollectiveShareInfo {
try {
$collectiveShare = $this->collectiveShareMapper->findOneByCollectiveIdAndUser($collectiveId, $userId);
$collectiveShare = $this->collectiveShareMapper->findOneByCollectiveIdAndUser($collectiveId, $pageId, $userId);
} catch (DoesNotExistException | MultipleObjectsReturnedException | Exception $e) {
return null;
}
Expand Down Expand Up @@ -156,24 +167,31 @@ private function isShareEditable(IShare $folderShare): bool {
/**
* @param string $userId
* @param CollectiveInfo $collective
* @param PageInfo|null $pageInfo
*
* @return CollectiveShareInfo
* @throws NotFoundException
* @throws NotPermittedException
*/
public function createShare(string $userId, CollectiveInfo $collective): CollectiveShareInfo {
public function createShare(string $userId, CollectiveInfo $collective, ?PageInfo $pageInfo): CollectiveShareInfo {
if (!$collective->canShare()) {
throw new NotPermittedException($this->l10n->t('You are not allowed to share %s', $collective->getName()));
}

if (null !== $this->findShare($userId, $collective->getId())) {
$pageId = 0;
if ($pageInfo) {
// TODO: set folderId if index page
$pageId = $pageInfo->getId();
}

if (null !== $this->findShare($userId, $collective->getId(), $pageId)) {
throw new NotPermittedException($this->l10n->t('A share for collective %s exists already', $collective->getName()));
}

$folderShare = $this->createFolderShare($userId, $collective->getName());
$folderShare = $this->createFolderShare($userId, $collective->getName(), $pageId);

try {
return new CollectiveShareInfo($this->collectiveShareMapper->create($collective->getId(), $folderShare->getToken(), $userId));
return new CollectiveShareInfo($this->collectiveShareMapper->create($collective->getId(), $pageId, $folderShare->getToken(), $userId));
} catch (Exception $e) {
throw new NotPermittedException('Failed to create collective share for ' . $collective->getName(), 0, $e);
}
Expand All @@ -182,6 +200,7 @@ public function createShare(string $userId, CollectiveInfo $collective): Collect
/**
* @param string $userId
* @param CollectiveInfo $collective
* @param PageInfo|null $pageInfo
* @param string $token
* @param bool $editable
*
Expand All @@ -192,7 +211,7 @@ public function createShare(string $userId, CollectiveInfo $collective): Collect
* @throws NotFoundException
* @throws NotPermittedException
*/
public function updateShare(string $userId, CollectiveInfo $collective, string $token, bool $editable = false): CollectiveShareInfo {
public function updateShare(string $userId, CollectiveInfo $collective, ?PageInfo $pageInfo, string $token, bool $editable = false): CollectiveShareInfo {
if (!$collective->canShare()) {
throw new NotPermittedException($this->l10n->t('You are not allowed to share %s', $collective->getName()));
}
Expand All @@ -201,7 +220,13 @@ public function updateShare(string $userId, CollectiveInfo $collective, string $
throw new NotPermittedException($this->l10n->t('You are not allowed to edit %s', $collective->getName()));
}

if (null === $share = $this->collectiveShareMapper->findOneByCollectiveIdAndTokenAndUser($collective->getId(), $token, $userId)) {
$pageId = 0;
if ($pageInfo) {
// TODO: set folderId if index page
$pageId = $pageInfo->getId();
}

if (null === $share = $this->collectiveShareMapper->findOneByCollectiveIdAndTokenAndUser($collective->getId(), $pageId, $token, $userId)) {
throw new NotFoundException($this->l10n->t('Share not found for user'));
}

Expand Down Expand Up @@ -237,15 +262,16 @@ private function deleteFileShare(string $token): void {
/**
* @param string $userId
* @param int $collectiveId
* @param int $pageId
* @param string $token
*
* @return CollectiveShareInfo
* @throws NotFoundException
* @throws NotPermittedException
*/
public function deleteShare(string $userId, int $collectiveId, string $token): CollectiveShareInfo {
public function deleteShare(string $userId, int $collectiveId, int $pageId, string $token): CollectiveShareInfo {
try {
$collectiveShare = $this->collectiveShareMapper->findOneByCollectiveIdAndTokenAndUser($collectiveId, $token, $userId);
$collectiveShare = $this->collectiveShareMapper->findOneByCollectiveIdAndTokenAndUser($collectiveId, $pageId, $token, $userId);
$this->collectiveShareMapper->delete($collectiveShare);
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
throw new NotFoundException('Failed to find collective share ' . $token, 0, $e);
Expand Down
Loading

0 comments on commit f60036f

Please sign in to comment.