Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@
['name' => 'board_api#preflighted_cors', 'url' => '/api/v{apiVersion}/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']],
],
'ocs' => [

['name' => 'new_board#index', 'url' => '/api/v{apiVersion}/boards', 'verb' => 'GET'],
['name' => 'new_board#read', 'url' => '/api/v{apiVersion}/board/{boardId}', 'verb' => 'GET'],
['name' => 'new_board#stacks', 'url' => '/api/v{apiVersion}/stacks/{boardId}', 'verb' => 'GET'],

['name' => 'Config#get', 'url' => '/api/v{apiVersion}/config', 'verb' => 'GET'],
['name' => 'Config#setValue', 'url' => '/api/v{apiVersion}/config/{key}', 'verb' => 'POST'],

Expand Down
14 changes: 14 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use OCA\Deck\Event\CardUpdatedEvent;
use OCA\Deck\Event\SessionClosedEvent;
use OCA\Deck\Event\SessionCreatedEvent;
use OCA\Deck\Federation\DeckFederationProvider;
use OCA\Deck\Listeners\BeforeTemplateRenderedListener;
use OCA\Deck\Listeners\CommentEventListener;
use OCA\Deck\Listeners\FullTextSearchEventListener;
Expand Down Expand Up @@ -59,9 +60,11 @@
use OCP\Comments\CommentsEntityEvent;
use OCP\Comments\CommentsEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Group\Events\GroupDeletedEvent;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Server;
use OCP\Share\IManager;
use OCP\User\Events\UserDeletedEvent;
use OCP\Util;
Expand Down Expand Up @@ -101,6 +104,7 @@ public function boot(IBootContext $context): void {
$context->injectFn(function (Listener $listener, IEventDispatcher $eventDispatcher) {
$listener->register($eventDispatcher);
});
$context->injectFn($this->registerCloudFederationProvider(...));
}

public function register(IRegistrationContext $context): void {
Expand Down Expand Up @@ -189,4 +193,14 @@ protected function registerCollaborationResources(IProviderManager $resourceMana
$resourceManager->registerResourceProvider(ResourceProvider::class);
$resourceManager->registerResourceProvider(ResourceProviderCard::class);
}

public function registerCloudFederationProvider(
ICloudFederationProviderManager $manager,
): void {
$manager->addCloudFederationProvider(
DeckFederationProvider::PROVIDER_ID,
"Deck Federation",
static fn () => Server::get(DeckFederationProvider::class),
);
}
}
6 changes: 4 additions & 2 deletions lib/Controller/BoardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\ExternalBoardService;
use OCA\Deck\Service\Importer\BoardImportService;
use OCA\Deck\Service\PermissionService;
use OCP\AppFramework\ApiController;
Expand All @@ -24,6 +25,7 @@
$appName,
IRequest $request,
private BoardService $boardService,
private ExternalBoardService $externalBoardService,
private PermissionService $permissionService,
private BoardImportService $boardImportService,
private IL10N $l10n,
Expand Down Expand Up @@ -77,8 +79,8 @@
* @param $participant
*/
#[NoAdminRequired]
public function addAcl(int $boardId, int $type, $participant, bool $permissionEdit, bool $permissionShare, bool $permissionManage): Acl {
return $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage);
public function addAcl(int $boardId, int $type, $participant, bool $permissionEdit, bool $permissionShare, bool $permissionManage, ?string $remote = null): Acl {
return $this->boardService->addAcl($boardId, $type, $participant, $permissionEdit, $permissionShare, $permissionManage, $remote);

Check failure on line 83 in lib/Controller/BoardController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

TooManyArguments

lib/Controller/BoardController.php:83:31: TooManyArguments: Too many arguments for method OCA\Deck\Service\BoardService::addacl - saw 7 (see https://psalm.dev/026)
}

/**
Expand Down
61 changes: 61 additions & 0 deletions lib/Controller/NewBoardController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace OCA\Deck\Controller;

use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\StackService;
use OCA\Deck\Service\ExternalBoardService;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\Attribute\RequestHeader;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

class NewBoardController extends OCSController{
public function __construct(
string $appName,
IRequest $request,
private BoardService $boardService,
private ExternalBoardService $externalBoardService,
private LoggerInterface $logger,
private StackService $stackService,
) {
parent::__construct($appName, $request);
}

#[NoAdminRequired]
public function index(): DataResponse {
$internalBoards = $this->boardService->findAll();
return new DataResponse($internalBoards);
}

#[NoAdminRequired]
#[PublicPage]
#[NoCSRFRequired]

Check failure on line 36 in lib/Controller/NewBoardController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedAttributeClass

lib/Controller/NewBoardController.php:36:4: UndefinedAttributeClass: Attribute class OCA\Deck\Controller\NoCSRFRequired does not exist (see https://psalm.dev/241)
#[RequestHeader(name: 'x-nextcloud-federation', description: 'Set to 1 when the request is performed by another Nextcloud Server to indicate a federation request', indirect: true)]
public function read(int $boardId): DataResponse {
// Board on this instance -> get it from database
$localBoard = $this->boardService->find($boardId, true, true, $this->request->getParam('accessToken'));
if($localBoard->getExternalId() !== null) {
return $this->externalBoardService->getExternalBoardFromRemote($localBoard);
}
// Board on other instance -> get it from other instance
return new DataResponse($localBoard);
}

#[NoAdminRequired]
#[PublicPage]
#[NoCSRFRequired]

Check failure on line 50 in lib/Controller/NewBoardController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedAttributeClass

lib/Controller/NewBoardController.php:50:4: UndefinedAttributeClass: Attribute class OCA\Deck\Controller\NoCSRFRequired does not exist (see https://psalm.dev/241)
#[RequestHeader(name: 'x-nextcloud-federation', description: 'Set to 1 when the request is performed by another Nextcloud Server to indicate a federation request', indirect: true)]
public function stacks(int $boardId): DataResponse{
$localBoard = $this->boardService->find($boardId, true, true, $this->request->getParam('accessToken'));
// Board on other instance -> get it from other instance
if($localBoard->getExternalId() !== null) {
return $this->externalBoardService->getExternalStacksFromRemote($localBoard);
} else {
return new DataResponse($this->stackService->findAll($boardId));
}
}
}
6 changes: 5 additions & 1 deletion lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\ExternalBoardService;
use OCA\Deck\Service\CardService;
use OCA\Deck\Service\ConfigService;
use OCA\Deck\Service\PermissionService;
Expand All @@ -36,6 +37,7 @@ public function __construct(
private PermissionService $permissionService,
private IInitialState $initialState,
private BoardService $boardService,
private ExternalBoardService $externalBoardService,
private ConfigService $configService,
private IEventDispatcher $eventDispatcher,
private CardMapper $cardMapper,
Expand All @@ -53,7 +55,9 @@ public function index(): TemplateResponse {
$this->initialState->provideInitialState('canCreate', $this->permissionService->canCreate());
$this->initialState->provideInitialState('config', $this->configService->getAll());

$this->initialState->provideInitialState('initialBoards', $this->boardService->findAll());
$this->initialState->provideInitialState('initialBoards', [
$this->boardService->findAll(),
]);

$this->eventDispatcher->dispatchTyped(new LoadSidebar());
$this->eventDispatcher->dispatchTyped(new CollaborationResourcesEvent());
Expand Down
5 changes: 5 additions & 0 deletions lib/Db/Acl.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* @method void setType(int $type)
* @method bool isOwner()
* @method void setOwner(int $owner)
* @method void setToken(string $token)
* @method string getToken()
*
*/
class Acl extends RelationalEntity {
Expand All @@ -29,6 +31,7 @@ class Acl extends RelationalEntity {

public const PERMISSION_TYPE_USER = 0;
public const PERMISSION_TYPE_GROUP = 1;
public const PERMISSION_TYPE_REMOTE = 6;
public const PERMISSION_TYPE_CIRCLE = 7;

protected $participant;
Expand All @@ -38,6 +41,7 @@ class Acl extends RelationalEntity {
protected $permissionShare = false;
protected $permissionManage = false;
protected $owner = false;
protected $token = null;

public function __construct() {
$this->addType('id', 'integer');
Expand All @@ -47,6 +51,7 @@ public function __construct() {
$this->addType('permissionManage', 'boolean');
$this->addType('type', 'integer');
$this->addType('owner', 'boolean');
$this->addType('token', 'string');
$this->addRelation('owner');
$this->addResolvable('participant');
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Db/AclMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct(IDBConnection $db) {
*/
public function findAll(int $boardId, ?int $limit = null, ?int $offset = null) {
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage', 'token')
->from('deck_board_acl')
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->setMaxResults($limit)
Expand Down
8 changes: 8 additions & 0 deletions lib/Db/Board.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
* @method void setOwner(string $owner)
* @method string getColor()
* @method void setColor(string $color)
* @method void setShareToken(string $shareToken)
* @method string getShareToken()
* @method void setExternalId(int $externalId)
* @method int getExternalId()
*/
class Board extends RelationalEntity {
protected $title;
Expand All @@ -41,6 +45,8 @@ class Board extends RelationalEntity {
protected $activeSessions = [];
protected $deletedAt = 0;
protected $lastModified = 0;
protected $shareToken = null;
protected $externalId = null;

protected $settings = [];

Expand All @@ -50,6 +56,8 @@ public function __construct() {
$this->addType('archived', 'boolean');
$this->addType('deletedAt', 'integer');
$this->addType('lastModified', 'integer');
$this->addType('shareToken', 'string');
$this->addType('externalId', 'integer');
$this->addRelation('labels');
$this->addRelation('acl');
$this->addRelation('shared');
Expand Down
3 changes: 3 additions & 0 deletions lib/Db/BoardMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ public function mapAcl(Acl &$acl): void {
}
return null;
}
if ($acl->getType() === Acl::PERMISSION_TYPE_REMOTE) {
return null;
}
$this->logger->warning('Unknown permission type for mapping acl ' . $acl->getId());
return null;
});
Expand Down
68 changes: 68 additions & 0 deletions lib/Federation/DeckFederationProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace OCA\Deck\Federation;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\ChangeHelper;
use OCP\Federation\ICloudFederationProvider;
use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Notification\IManager as INotificationManager;
use Exception;

class DeckFederationProvider implements ICloudFederationProvider{
public const PROVIDER_ID = 'deck';

public function __construct(
private readonly ICloudIdmanager $cloudIdManager,
private INotificationManager $notificationManager,
private BoardMapper $boardMapper,
private AclMapper $aclMapper,
private ChangeHelper $changeHelper,
){
}

public function getShareType(): string {
return self::PROVIDER_ID;
}

public function shareReceived(ICloudFederationShare $share): string {
$notification = $this->notificationManager->createNotification();
$notification->setApp('deck');
$notification->setUser($share->getShareWith());
$notification->setDateTime(new \DateTime());
$notification->setObject('remote-board-shared', (string) rand(0,9999999));
$notification->setSubject('remote-board-shared',[$share->getResourceName(), $share->getSharedBy()]);

$this->notificationManager->notify($notification);

$externalBoard = new Board();
$externalBoard->setTitle($share->getResourceName());
$externalBoard->setExternalId($share->getProviderId());

Check failure on line 43 in lib/Federation/DeckFederationProvider.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidArgument

lib/Federation/DeckFederationProvider.php:43:33: InvalidArgument: Argument 1 of setExternalId expects int, but string provided (see https://psalm.dev/004)
$externalBoard->setOwner($share->getSharedBy());
$externalBoard->setShareToken($share->getShareSecret());
$insertedBoard = $this->boardMapper->insert($externalBoard);

$acl = new Acl();
$acl->setBoardId($insertedBoard->getId());
$acl->setType(Acl::PERMISSION_TYPE_USER);
$acl->setParticipant($share->getShareWith());
$acl->setPermissionEdit(false);
$acl->setPermissionShare(false);
$acl->setPermissionManage(false);
$this->aclMapper->insert($acl);

$this->changeHelper->boardChanged($insertedBoard->getId());
return 'PLACE_HOLDER_ID';
}

public function notificationReceived($notificationType, $providerId, $notification): array {
return [];
}

public function getSupportedShareTypes(): array {
return ['user'];
}
}
Loading
Loading