diff --git a/appinfo/routes.php b/appinfo/routes.php
index 4adb828b46..45d6555f3b 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -22,6 +22,7 @@
['name' => 'board#update', 'url' => '/boards/{boardId}', 'verb' => 'PUT'],
['name' => 'board#delete', 'url' => '/boards/{boardId}', 'verb' => 'DELETE'],
['name' => 'board#deleteUndo', 'url' => '/boards/{boardId}/deleteUndo', 'verb' => 'POST'],
+ ['name' => 'board#leave', 'url' => '/boards/{boardId}/leave', 'verb' => 'POST'],
['name' => 'board#getUserPermissions', 'url' => '/boards/{boardId}/permissions', 'verb' => 'GET'],
['name' => 'board#addAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'POST'],
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php
index d053d6bcc6..8376327a7d 100644
--- a/lib/Controller/BoardController.php
+++ b/lib/Controller/BoardController.php
@@ -87,6 +87,15 @@ public function deleteUndo($boardId) {
return $this->boardService->deleteUndo($boardId);
}
+ /**
+ * @NoAdminRequired
+ * @param $boardId
+ * @return \OCP\AppFramework\Db\Entity|null
+ */
+ public function leave(int $boardId) {
+ return $this->boardService->leave($boardId);
+ }
+
/**
* @NoAdminRequired
* @param $boardId
diff --git a/lib/Db/AclMapper.php b/lib/Db/AclMapper.php
index 656a231e8b..f2ea424b37 100644
--- a/lib/Db/AclMapper.php
+++ b/lib/Db/AclMapper.php
@@ -98,6 +98,16 @@ public function findByParticipant($type, $participant): array {
return $this->findEntities($qb);
}
+ public function findParticipantFromBoard(int $boardId, int $type, string $participant): ?Acl {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from('deck_board_acl')
+ ->where($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
+ ->where($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
+ ->andWhere($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)));
+ return $this->findEntity($qb);
+ }
+
/**
* @throws \OCP\DB\Exception
*/
diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php
index b88111adde..273c304ab5 100644
--- a/lib/Service/BoardService.php
+++ b/lib/Service/BoardService.php
@@ -466,6 +466,37 @@ public function deleteAcl(int $id): ?Acl {
return $deletedAcl;
}
+ public function leave(int $boardId): ?Acl {
+ if ($this->permissionService->userIsBoardOwner($boardId)) {
+ throw new BadRequestException('Board owner cannot leave board');
+ }
+
+ $acl = $this->aclMapper->findParticipantFromBoard($boardId, Acl::PERMISSION_TYPE_USER, $this->userId);
+
+ if (!$acl) {
+ throw new BadRequestException('Not a participant of this board');
+ }
+
+ $this->assignedUsersMapper->deleteByParticipantOnBoard($acl->getParticipant(), $acl->getBoardId());
+
+ $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $acl, ActivityManager::SUBJECT_BOARD_UNSHARE);
+ $this->changeHelper->boardChanged($acl->getBoardId());
+
+ $version = \OCP\Util::getVersion()[0];
+ if ($version >= 16) {
+ try {
+ $resourceProvider = Server::get(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
+ $resourceProvider->invalidateAccessCache($acl->getBoardId());
+ } catch (\Exception $e) {
+ }
+ }
+
+ $deletedAcl = $this->aclMapper->delete($acl);
+ $this->eventDispatcher->dispatchTyped(new AclDeletedEvent($acl));
+
+ return $deletedAcl;
+ }
+
/**
* @throws BadRequestException
* @throws DbException
diff --git a/src/components/navigation/AppNavigationBoard.vue b/src/components/navigation/AppNavigationBoard.vue
index 14562390c1..eda417bb6f 100644
--- a/src/components/navigation/AppNavigationBoard.vue
+++ b/src/components/navigation/AppNavigationBoard.vue
@@ -116,6 +116,16 @@
@click="actionDelete">
{{ t('deck', 'Delete board') }}
+
+