Reduce duplicate queries when fetching user boards an permissions
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
|
use OC\Cache\CappedMemoryCache;
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\IUserManager;
|
use OCP\IUserManager;
|
||||||
@@ -39,6 +40,8 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
|
|
||||||
private $circlesEnabled;
|
private $circlesEnabled;
|
||||||
|
|
||||||
|
private $userBoardCache;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IDBConnection $db,
|
IDBConnection $db,
|
||||||
LabelMapper $labelMapper,
|
LabelMapper $labelMapper,
|
||||||
@@ -56,6 +59,9 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
$this->groupManager = $groupManager;
|
$this->groupManager = $groupManager;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
|
||||||
|
$this->userBoardCache = new CappedMemoryCache();
|
||||||
|
|
||||||
|
|
||||||
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles');
|
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,13 +95,21 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function findAllForUser(string $userId, int $since = -1, $includeArchived = true): array {
|
public function findAllForUser(string $userId, int $since = -1, $includeArchived = true): array {
|
||||||
|
$useCache = ($since === -1 && $includeArchived === true);
|
||||||
|
if (!isset($this->userBoardCache[$userId]) || !$useCache) {
|
||||||
$groups = $this->groupManager->getUserGroupIds(
|
$groups = $this->groupManager->getUserGroupIds(
|
||||||
$this->userManager->get($userId)
|
$this->userManager->get($userId)
|
||||||
);
|
);
|
||||||
$userBoards = $this->findAllByUser($userId, null, null, $since, $includeArchived);
|
$userBoards = $this->findAllByUser($userId, null, null, $since, $includeArchived);
|
||||||
$groupBoards = $this->findAllByGroups($userId, $groups, null, null, $since, $includeArchived);
|
$groupBoards = $this->findAllByGroups($userId, $groups, null, null, $since, $includeArchived);
|
||||||
$circleBoards = $this->findAllByCircles($userId, null, null, $since, $includeArchived);
|
$circleBoards = $this->findAllByCircles($userId, null, null, $since, $includeArchived);
|
||||||
return array_unique(array_merge($userBoards, $groupBoards, $circleBoards));
|
$allBoards = array_unique(array_merge($userBoards, $groupBoards, $circleBoards));
|
||||||
|
if ($useCache) {
|
||||||
|
$this->userBoardCache[$userId] = $allBoards;
|
||||||
|
}
|
||||||
|
return $allBoards;
|
||||||
|
}
|
||||||
|
return $this->userBoardCache[$userId];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
namespace OCA\Deck\Service;
|
namespace OCA\Deck\Service;
|
||||||
|
|
||||||
|
use OC\Cache\CappedMemoryCache;
|
||||||
use OCA\Deck\Db\Acl;
|
use OCA\Deck\Db\Acl;
|
||||||
use OCA\Deck\Db\AclMapper;
|
use OCA\Deck\Db\AclMapper;
|
||||||
use OCA\Deck\Db\Board;
|
use OCA\Deck\Db\Board;
|
||||||
@@ -61,6 +62,7 @@ class PermissionService {
|
|||||||
private $users = [];
|
private $users = [];
|
||||||
|
|
||||||
private $circlesEnabled = false;
|
private $circlesEnabled = false;
|
||||||
|
private $boardCache;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ILogger $logger,
|
ILogger $logger,
|
||||||
@@ -81,6 +83,8 @@ class PermissionService {
|
|||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
|
|
||||||
|
$this->boardCache = new CappedMemoryCache();
|
||||||
|
|
||||||
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles') &&
|
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles') &&
|
||||||
(version_compare(\OC::$server->getAppManager()->getAppVersion('circles'), '0.17.1') >= 0);
|
(version_compare(\OC::$server->getAppManager()->getAppVersion('circles'), '0.17.1') >= 0);
|
||||||
}
|
}
|
||||||
@@ -149,11 +153,14 @@ class PermissionService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$acls = $this->aclMapper->findAll($boardId);
|
try {
|
||||||
|
$acls = $this->getBoard($boardId)->getAcl();
|
||||||
$result = $this->userCan($acls, $permission, $userId);
|
$result = $this->userCan($acls, $permission, $userId);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
// Throw NoPermission to not leak information about existing entries
|
// Throw NoPermission to not leak information about existing entries
|
||||||
throw new NoPermissionException('Permission denied');
|
throw new NoPermissionException('Permission denied');
|
||||||
@@ -168,13 +175,24 @@ class PermissionService {
|
|||||||
$userId = $this->userId;
|
$userId = $this->userId;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$board = $this->boardMapper->find($boardId);
|
$board = $this->getBoard($boardId);
|
||||||
return $board && $userId === $board->getOwner();
|
return $userId === $board->getOwner();
|
||||||
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
|
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws MultipleObjectsReturnedException
|
||||||
|
* @throws DoesNotExistException
|
||||||
|
*/
|
||||||
|
private function getBoard($boardId): Board {
|
||||||
|
if (!isset($this->boardCache[$boardId])) {
|
||||||
|
$this->boardCache[$boardId] = $this->boardMapper->find($boardId, false, true);
|
||||||
|
}
|
||||||
|
return $this->boardCache[$boardId];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if permission matches the acl rules for current user and groups
|
* Check if permission matches the acl rules for current user and groups
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class PermissionServiceTest extends \Test\TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testUserIsBoardOwnerNull() {
|
public function testUserIsBoardOwnerNull() {
|
||||||
$this->boardMapper->expects($this->once())->method('find')->willReturn(null);
|
$this->boardMapper->expects($this->once())->method('find')->willThrowException(new DoesNotExistException('board does not exist'));
|
||||||
$this->assertEquals(false, $this->service->userIsBoardOwner(123));
|
$this->assertEquals(false, $this->service->userIsBoardOwner(123));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,12 +225,9 @@ class PermissionServiceTest extends \Test\TestCase {
|
|||||||
$board = new Board();
|
$board = new Board();
|
||||||
$board->setId($boardId);
|
$board->setId($boardId);
|
||||||
$board->setOwner($owner);
|
$board->setOwner($owner);
|
||||||
|
$board->setAcl($this->getAcls($boardId));
|
||||||
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
||||||
|
|
||||||
// acl check
|
|
||||||
$acls = $this->getAcls($boardId);
|
|
||||||
$this->aclMapper->expects($this->any())->method('findAll')->willReturn($acls);
|
|
||||||
|
|
||||||
$this->shareManager->expects($this->any())
|
$this->shareManager->expects($this->any())
|
||||||
->method('sharingDisabledForUser')
|
->method('sharingDisabledForUser')
|
||||||
->willReturn(false);
|
->willReturn(false);
|
||||||
@@ -250,14 +247,12 @@ class PermissionServiceTest extends \Test\TestCase {
|
|||||||
$board = new Board();
|
$board = new Board();
|
||||||
$board->setId($boardId);
|
$board->setId($boardId);
|
||||||
$board->setOwner($owner);
|
$board->setOwner($owner);
|
||||||
|
$board->setAcl($this->getAcls($boardId));
|
||||||
if ($boardId === null) {
|
if ($boardId === null) {
|
||||||
$this->boardMapper->expects($this->any())->method('find')->willThrowException(new DoesNotExistException('not found'));
|
$this->boardMapper->expects($this->any())->method('find')->willThrowException(new DoesNotExistException('not found'));
|
||||||
} else {
|
} else {
|
||||||
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
||||||
}
|
}
|
||||||
$acls = $this->getAcls($boardId);
|
|
||||||
$this->aclMapper->expects($this->any())->method('findAll')->willReturn($acls);
|
|
||||||
|
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$actual = $this->service->checkPermission($mapper, 1234, $permission);
|
$actual = $this->service->checkPermission($mapper, 1234, $permission);
|
||||||
|
|||||||
Reference in New Issue
Block a user