Merge remote-tracking branch 'origin/vue' into master-merge-vue

This commit is contained in:
Julius Härtl
2020-01-25 10:42:05 +01:00
137 changed files with 27543 additions and 17157 deletions

View File

@@ -194,9 +194,10 @@ class Application extends App {
$resourceManager = $this->getContainer()->query(\OCP\Collaboration\Resources\IProviderManager::class);
}
$resourceManager->registerResourceProvider(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
$resourceManager->registerResourceProvider(\OCA\Deck\Collaboration\Resources\ResourceProviderCard::class);
\OC::$server->getEventDispatcher()->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () {
\OCP\Util::addScript('deck', 'build/collections');
\OCP\Util::addScript('deck', 'collections');
});
}

View File

@@ -0,0 +1,160 @@
<?php
/**
* @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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\Deck\Collaboration\Resources;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Service\PermissionService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\QueryException;
use OCP\Collaboration\Resources\IManager;
use OCP\Collaboration\Resources\IProvider;
use OCP\Collaboration\Resources\IResource;
use OCP\Collaboration\Resources\ResourceException;
use OCP\IURLGenerator;
use OCP\IUser;
class ResourceProviderCard implements IProvider {
const RESOURCE_TYPE = 'deck-card';
/** @var CardMapper */
private $cardMapper;
/** @var BoardMapper */
private $boardMapper;
/** @var PermissionService */
private $permissionService;
/** @var IURLGenerator */
private $urlGenerator;
/** @var array */
protected $nodes = [];
public function __construct(CardMapper $cardMapper, BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
$this->cardMapper = $cardMapper;
$this->boardMapper = $boardMapper;
$this->permissionService = $permissionService;
$this->urlGenerator = $urlGenerator;
}
/**
* Get the type of a resource
*
* @return string
* @since 15.0.0
*/
public function getType(): string {
return self::RESOURCE_TYPE;
}
/**
* Get the rich object data of a resource
*
* @param IResource $resource
* @return array
* @since 16.0.0
*/
public function getResourceRichObject(IResource $resource): array {
try {
$card = $this->cardMapper->find($resource->getId());
$board = $this->getBoard($resource->getId());
} catch (DoesNotExistException $e) {
throw new ResourceException('No card found for resource');
} catch (MultipleObjectsReturnedException $e) {
throw new ResourceException('No unique card found for resource, this should never happen');
}
$link = $this->urlGenerator->linkToRoute('deck.page.index') . '#/board/' . $board->getId() . '/cards/' . $resource->getId();
return [
'type' => self::RESOURCE_TYPE,
'id' => $resource->getId(),
'name' => $board->getTitle() . ': ' . $card->getTitle(),
'link' => $link,
'iconUrl' => $this->urlGenerator->imagePath('core', 'actions/toggle-pictures.svg')
];
}
/**
* Can a user/guest access the collection
*
* @param IResource $resource
* @param IUser|null $user
* @return bool
* @since 16.0.0
*/
public function canAccessResource(IResource $resource, ?IUser $user): bool {
if (!$user instanceof IUser || $resource->getType() !== self::RESOURCE_TYPE) {
return false;
}
try {
$board = $this->getBoard($resource->getId());
} catch (DoesNotExistException $e) {
return false;
} catch (MultipleObjectsReturnedException $e) {
return false;
}
if ($board === null) {
return false;
}
if ($board->getOwner() === $user->getUID()) {
return true;
}
return $this->permissionService->userCan($board->getAcl(), Acl::PERMISSION_READ, $user->getUID());
}
/**
* @param $cardId
* @return Board
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
*/
private function getBoard($cardId) {
$boardId = $this->cardMapper->findBoardId($cardId);
return $this->boardMapper->find($boardId, false, true);
}
public function invalidateAccessCache($cardId = null) {
try {
/** @var IManager $resourceManager */
$resourceManager = \OC::$server->query(IManager::class);
} catch (QueryException $e) {
}
if ($cardId !== null) {
$resource = $resourceManager->getResourceForUser(self::RESOURCE_TYPE, (string)$cardId, null);
$resourceManager->invalidateAccessCacheForResource($resource);
} else {
$resourceManager->invalidateAccessCacheForProvider($this);
}
}
}

View File

@@ -150,4 +150,13 @@ class BoardController extends ApiController {
return $this->boardService->deleteAcl($aclId);
}
/**
* @NoAdminRequired
* @param $boardId
* @return \OCP\Deck\DB\Board
*/
public function clone($boardId) {
return $this->boardService->clone($boardId);
}
}

View File

@@ -55,7 +55,7 @@ class CardController extends Controller {
* @return array
*/
public function reorder($cardId, $stackId, $order) {
return $this->cardService->reorder($cardId, $stackId, $order);
return $this->cardService->reorder((int)$cardId, (int)$stackId, (int)$order);
}
/**
@@ -76,7 +76,7 @@ class CardController extends Controller {
* @param int $order
* @return \OCP\AppFramework\Db\Entity
*/
public function create($title, $stackId, $type, $order = 999) {
public function create($title, $stackId, $type = 'plain', $order = 999) {
return $this->cardService->create($title, $stackId, $type, $order, $this->userId);
}

View File

@@ -69,7 +69,7 @@ class PageController extends Controller {
if ($this->defaultBoardService->checkFirstRun($this->userId, $this->appName)) {
if ($this->permissionService->canCreate()) {
$this->defaultBoardService->createDefaultBoard($this->l10n->t('Personal'), $this->userId, '000000');
$this->defaultBoardService->createDefaultBoard($this->l10n->t('Personal'), $this->userId, '0087C5');
}
}

View File

@@ -88,7 +88,7 @@ class StackController extends Controller {
* @return array
*/
public function reorder($stackId, $order) {
return $this->stackService->reorder($stackId, $order);
return $this->stackService->reorder((int)$stackId, (int)$order);
}
/**

View File

@@ -33,6 +33,7 @@ use OCA\Deck\Db\AssignedUsersMapper;
use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\IPermissionMapper;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Notification\NotificationHelper;
@@ -614,6 +615,49 @@ class BoardService {
return $delete;
}
/**
* @param $id
* @return Board
* @throws DoesNotExistException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function clone($id) {
if (is_numeric($id) === false) {
throw new BadRequestException('board id must be a number');
}
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ);
$board = $this->boardMapper->find($id);
$newBoard = new Board();
$newBoard->setTitle($board->getTitle() . ' (' . $this->l10n->t('copy') . ')');
$newBoard->setOwner($board->getOwner());
$newBoard->setColor($board->getColor());
$this->boardMapper->insert($newBoard);
$labels = $this->labelMapper->findAll($id);
foreach ($labels as $label) {
$newLabel = new Label();
$newLabel->setTitle($label->getTitle());
$newLabel->setColor($label->getColor());
$newLabel->setBoardId($newBoard->getId());
$this->labelMapper->insert($newLabel);
}
$stacks = $this->stackMapper->findAll($id);
foreach ($stacks as $stack) {
$newStack = new Stack();
$newStack->setTitle($stack->getTitle());
$newStack->setBoardId($newBoard->getId());
$this->stackMapper->insert($newStack);
}
return $newBoard;
}
private function enrichWithStacks($board, $since = -1) {
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since);

View File

@@ -400,6 +400,14 @@ class CardService {
if ($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
if ($card->getArchived()) {
throw new StatusException('Operation not allowed. This card is archived.');
}
$card->setStackId($stackId);
$this->cardMapper->update($card);
$cards = $this->cardMapper->findAll($stackId);
$result = [];
$i = 0;

View File

@@ -262,6 +262,27 @@ class PermissionService {
$users[$user->getUID()] = new User($user);
}
}
if ($this->circlesEnabled && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
try {
$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($acl->getParticipant(), true);
if ($circle === null) {
$this->logger->info('No circle found for acl rule ' . $acl->getId());
continue;
}
foreach ($circle->getMembers() as $member) {
$user = $this->userManager->get($member->getUserId());
if ($user === null) {
$this->logger->info('No user found for circle member ' . $member->getUserId());
} else {
$users[$member->getUserId()] = new User($user);
}
}
} catch (\Exception $e) {
$this->logger->info('Member not found in circle that was accessed. This should not happen.');
}
}
}
$this->users[(string) $boardId] = $users;
return $this->users[(string) $boardId];