Compare commits
3 Commits
enh/flow-c
...
enh/dashbo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7364f5dfe6 | ||
|
|
1d12ab93f5 | ||
|
|
435994fb1b |
@@ -107,16 +107,9 @@ OC.L10N.register(
|
|||||||
"Select the board to link to a project" : "Izberite zbirko za povezavo s projektom",
|
"Select the board to link to a project" : "Izberite zbirko za povezavo s projektom",
|
||||||
"Search by board title" : "Išči po imenu zbirke",
|
"Search by board title" : "Išči po imenu zbirke",
|
||||||
"Select board" : "Izbor zbirke",
|
"Select board" : "Izbor zbirke",
|
||||||
"Create a new card" : "Ustvari novo nalogo",
|
|
||||||
"Select a board" : "Izbor zbirke",
|
"Select a board" : "Izbor zbirke",
|
||||||
"Select a list" : "Izbor seznama",
|
"Select a list" : "Izbor seznama",
|
||||||
"Card title" : "Naslov naloge",
|
|
||||||
"Cancel" : "Prekliči",
|
"Cancel" : "Prekliči",
|
||||||
"Creating the new card…" : "Poteka ustvarjanje nove naloge ...",
|
|
||||||
"\"{card}\" was added to \"{board}\"" : "Naloga »{card}« je dodana v zbirko »{board}«.",
|
|
||||||
"Open card" : "Odpri nalogo",
|
|
||||||
"Close" : "Zapri",
|
|
||||||
"Create card" : "Ustvari nalogo",
|
|
||||||
"Select a card" : "Izbor naloge",
|
"Select a card" : "Izbor naloge",
|
||||||
"Select the card to link to a project" : "Izbor naloge za povezavo do projekta",
|
"Select the card to link to a project" : "Izbor naloge za povezavo do projekta",
|
||||||
"Link to card" : "Poveži nalogo",
|
"Link to card" : "Poveži nalogo",
|
||||||
@@ -265,7 +258,6 @@ OC.L10N.register(
|
|||||||
"upcoming cards" : "prihajajoče naloge",
|
"upcoming cards" : "prihajajoče naloge",
|
||||||
"Link to a board" : "Povezava do zbirke",
|
"Link to a board" : "Povezava do zbirke",
|
||||||
"Link to a card" : "Povezava do naloge",
|
"Link to a card" : "Povezava do naloge",
|
||||||
"Create a card" : "Ustvari nalogo",
|
|
||||||
"Something went wrong" : "Prišlo je do napake ...",
|
"Something went wrong" : "Prišlo je do napake ...",
|
||||||
"Failed to upload {name}" : "Pošiljanje {name} je spodletelo",
|
"Failed to upload {name}" : "Pošiljanje {name} je spodletelo",
|
||||||
"Maximum file size of {size} exceeded" : "Omejitev velikosti datoteke {size} je prekoračena.",
|
"Maximum file size of {size} exceeded" : "Omejitev velikosti datoteke {size} je prekoračena.",
|
||||||
|
|||||||
@@ -105,16 +105,9 @@
|
|||||||
"Select the board to link to a project" : "Izberite zbirko za povezavo s projektom",
|
"Select the board to link to a project" : "Izberite zbirko za povezavo s projektom",
|
||||||
"Search by board title" : "Išči po imenu zbirke",
|
"Search by board title" : "Išči po imenu zbirke",
|
||||||
"Select board" : "Izbor zbirke",
|
"Select board" : "Izbor zbirke",
|
||||||
"Create a new card" : "Ustvari novo nalogo",
|
|
||||||
"Select a board" : "Izbor zbirke",
|
"Select a board" : "Izbor zbirke",
|
||||||
"Select a list" : "Izbor seznama",
|
"Select a list" : "Izbor seznama",
|
||||||
"Card title" : "Naslov naloge",
|
|
||||||
"Cancel" : "Prekliči",
|
"Cancel" : "Prekliči",
|
||||||
"Creating the new card…" : "Poteka ustvarjanje nove naloge ...",
|
|
||||||
"\"{card}\" was added to \"{board}\"" : "Naloga »{card}« je dodana v zbirko »{board}«.",
|
|
||||||
"Open card" : "Odpri nalogo",
|
|
||||||
"Close" : "Zapri",
|
|
||||||
"Create card" : "Ustvari nalogo",
|
|
||||||
"Select a card" : "Izbor naloge",
|
"Select a card" : "Izbor naloge",
|
||||||
"Select the card to link to a project" : "Izbor naloge za povezavo do projekta",
|
"Select the card to link to a project" : "Izbor naloge za povezavo do projekta",
|
||||||
"Link to card" : "Poveži nalogo",
|
"Link to card" : "Poveži nalogo",
|
||||||
@@ -263,7 +256,6 @@
|
|||||||
"upcoming cards" : "prihajajoče naloge",
|
"upcoming cards" : "prihajajoče naloge",
|
||||||
"Link to a board" : "Povezava do zbirke",
|
"Link to a board" : "Povezava do zbirke",
|
||||||
"Link to a card" : "Povezava do naloge",
|
"Link to a card" : "Povezava do naloge",
|
||||||
"Create a card" : "Ustvari nalogo",
|
|
||||||
"Something went wrong" : "Prišlo je do napake ...",
|
"Something went wrong" : "Prišlo je do napake ...",
|
||||||
"Failed to upload {name}" : "Pošiljanje {name} je spodletelo",
|
"Failed to upload {name}" : "Pošiljanje {name} je spodletelo",
|
||||||
"Maximum file size of {size} exceeded" : "Omejitev velikosti datoteke {size} je prekoračena.",
|
"Maximum file size of {size} exceeded" : "Omejitev velikosti datoteke {size} je prekoračena.",
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ use OCA\Deck\Service\FullTextSearchService;
|
|||||||
use OCA\Deck\Service\PermissionService;
|
use OCA\Deck\Service\PermissionService;
|
||||||
use OCA\Deck\Sharing\DeckShareProvider;
|
use OCA\Deck\Sharing\DeckShareProvider;
|
||||||
use OCA\Deck\Sharing\Listener;
|
use OCA\Deck\Sharing\Listener;
|
||||||
use OCA\Deck\Listeners\RegisterChecksListener;
|
|
||||||
use OCA\Deck\Listeners\RegisterEntityListener;
|
|
||||||
use OCP\AppFramework\App;
|
use OCP\AppFramework\App;
|
||||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||||
@@ -68,8 +66,6 @@ use OCP\IUserManager;
|
|||||||
use OCP\Notification\IManager as NotificationManager;
|
use OCP\Notification\IManager as NotificationManager;
|
||||||
use OCP\Share\IManager;
|
use OCP\Share\IManager;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
use OCP\WorkflowEngine\Events\RegisterChecksEvent;
|
|
||||||
use OCP\WorkflowEngine\Events\RegisterEntitiesEvent;
|
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
class Application20 extends App implements IBootstrap {
|
class Application20 extends App implements IBootstrap {
|
||||||
@@ -131,9 +127,6 @@ class Application20 extends App implements IBootstrap {
|
|||||||
$context->registerDashboardWidget(DeckWidget::class);
|
$context->registerDashboardWidget(DeckWidget::class);
|
||||||
|
|
||||||
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
|
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
|
||||||
|
|
||||||
$context->registerEventListener(RegisterEntitiesEvent::class, RegisterEntityListener::class);
|
|
||||||
//$context->registerEventListener(RegisterChecksEvent::class, RegisterChecksListener::class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerNotifications(NotificationManager $notificationManager): void {
|
public function registerNotifications(NotificationManager $notificationManager): void {
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (c) 2021 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
|
|
||||||
namespace OCA\Deck\Event;
|
|
||||||
|
|
||||||
use OCA\Deck\Db\Card;
|
|
||||||
|
|
||||||
class CardCreatedEvent extends \OCP\EventDispatcher\Event {
|
|
||||||
|
|
||||||
/** @var Card */
|
|
||||||
private $card;
|
|
||||||
|
|
||||||
public function __construct(Card $card) {
|
|
||||||
$this->card = $card;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCard(): Card {
|
|
||||||
return $this->card;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (c) 2021 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
|
|
||||||
namespace OCA\Deck\Flow;
|
|
||||||
|
|
||||||
use OCA\Deck\Event\CardCreatedEvent;
|
|
||||||
use OCP\EventDispatcher\Event;
|
|
||||||
use OCP\IL10N;
|
|
||||||
use OCP\IURLGenerator;
|
|
||||||
use OCP\WorkflowEngine\EntityContext\IDisplayName;
|
|
||||||
use OCP\WorkflowEngine\EntityContext\IDisplayText;
|
|
||||||
use OCP\WorkflowEngine\EntityContext\IUrl;
|
|
||||||
use OCP\WorkflowEngine\IEntity;
|
|
||||||
use OCP\WorkflowEngine\IRuleMatcher;
|
|
||||||
|
|
||||||
class CardEntity implements IEntity, IDisplayText, IDisplayName, IUrl {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var IL10N
|
|
||||||
*/
|
|
||||||
private $l10n;
|
|
||||||
/**
|
|
||||||
* @var IURLGenerator
|
|
||||||
*/
|
|
||||||
private $urlGenerator;
|
|
||||||
|
|
||||||
private $card;
|
|
||||||
|
|
||||||
public function __construct(IL10N $l, IURLGenerator $urlGenerator) {
|
|
||||||
$this->l10n = $l;
|
|
||||||
$this->urlGenerator = $urlGenerator;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getName(): string {
|
|
||||||
return $this->l10n->t('Deck card');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getIcon(): string {
|
|
||||||
return $this->urlGenerator->imagePath('deck', 'deck-dark.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getEvents(): array {
|
|
||||||
return [new CardEntityCreatedEvent($this->l10n)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function prepareRuleMatcher(IRuleMatcher $ruleMatcher, string $eventName, Event $event): void {
|
|
||||||
if(!$event instanceof CardCreatedEvent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/** @var CardCreatedEvent $event */
|
|
||||||
$ruleMatcher->setEntitySubject($this, $event->getCard());
|
|
||||||
$this->card = $event->getCard();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function isLegitimatedForUserId(string $userId): bool {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDisplayName(): string {
|
|
||||||
return $this->card->getTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDisplayText(int $verbosity = 0): string {
|
|
||||||
return $this->card->getTitle() . PHP_EOL . $this->card->getDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUrl(): string {
|
|
||||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . '/board/1/card/' . $this->card->getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (c) 2021 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
|
|
||||||
namespace OCA\Deck\Flow;
|
|
||||||
|
|
||||||
use OCA\Deck\Event\CardCreatedEvent;
|
|
||||||
use OCP\IL10N;
|
|
||||||
use OCP\WorkflowEngine\IEntityEvent;
|
|
||||||
|
|
||||||
class CardEntityCreatedEvent implements IEntityEvent {
|
|
||||||
|
|
||||||
/** @var IL10N */
|
|
||||||
private $l10n;
|
|
||||||
|
|
||||||
public function __construct(IL10N $l10n) {
|
|
||||||
$this->l10n = $l10n;
|
|
||||||
}
|
|
||||||
public function getDisplayName(): string {
|
|
||||||
return $this->l10n->t('Card created');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEventName(): string {
|
|
||||||
return CardCreatedEvent::class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
|
||||||
*
|
|
||||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
|
||||||
*
|
|
||||||
* @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\Listeners;
|
|
||||||
|
|
||||||
use OCA\FlowWebhooks\AppInfo\Application;
|
|
||||||
use OCA\FlowWebhooks\Flow\ParameterCheck;
|
|
||||||
use OCP\EventDispatcher\Event;
|
|
||||||
use OCP\EventDispatcher\IEventListener;
|
|
||||||
use OCP\Util;
|
|
||||||
use OCP\WorkflowEngine\Events\RegisterChecksEvent;
|
|
||||||
|
|
||||||
class RegisterChecksListener implements IEventListener {
|
|
||||||
|
|
||||||
/** @var ParameterCheck */
|
|
||||||
private $parameterCheck;
|
|
||||||
|
|
||||||
public function __construct(ParameterCheck $parameterCheck) {
|
|
||||||
$this->parameterCheck = $parameterCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(Event $event): void {
|
|
||||||
if (!($event instanceof RegisterChecksEvent)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$event->registerCheck($this->parameterCheck);
|
|
||||||
|
|
||||||
Util::addScript(Application::APP_ID, Application::APP_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
|
||||||
*
|
|
||||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
|
||||||
*
|
|
||||||
* @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\Listeners;
|
|
||||||
|
|
||||||
use OCA\Deck\Flow\CardEntity;
|
|
||||||
use OCP\EventDispatcher\Event;
|
|
||||||
use OCP\EventDispatcher\IEventListener;
|
|
||||||
use OCP\WorkflowEngine\Events\RegisterEntitiesEvent;
|
|
||||||
|
|
||||||
class RegisterEntityListener implements IEventListener {
|
|
||||||
|
|
||||||
/** @var CardEntity */
|
|
||||||
private $cardEntity;
|
|
||||||
|
|
||||||
public function __construct(CardEntity $cardEntity) {
|
|
||||||
$this->cardEntity = $cardEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(Event $event): void {
|
|
||||||
if(!$event instanceof RegisterEntitiesEvent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$event->registerEntity($this->cardEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,7 +35,6 @@ use OCA\Deck\Db\CardMapper;
|
|||||||
use OCA\Deck\Db\Acl;
|
use OCA\Deck\Db\Acl;
|
||||||
use OCA\Deck\Db\ChangeHelper;
|
use OCA\Deck\Db\ChangeHelper;
|
||||||
use OCA\Deck\Db\StackMapper;
|
use OCA\Deck\Db\StackMapper;
|
||||||
use OCA\Deck\Event\CardCreatedEvent;
|
|
||||||
use OCA\Deck\Event\FTSEvent;
|
use OCA\Deck\Event\FTSEvent;
|
||||||
use OCA\Deck\Notification\NotificationHelper;
|
use OCA\Deck\Notification\NotificationHelper;
|
||||||
use OCA\Deck\Db\BoardMapper;
|
use OCA\Deck\Db\BoardMapper;
|
||||||
@@ -225,7 +224,6 @@ class CardService {
|
|||||||
$card = $this->cardMapper->insert($card);
|
$card = $this->cardMapper->insert($card);
|
||||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_CARD_CREATE);
|
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_CARD_CREATE);
|
||||||
$this->changeHelper->cardChanged($card->getId(), false);
|
$this->changeHelper->cardChanged($card->getId(), false);
|
||||||
$this->eventDispatcher->dispatchTyped(new CardCreatedEvent($card));
|
|
||||||
|
|
||||||
$this->eventDispatcher->dispatch(
|
$this->eventDispatcher->dispatch(
|
||||||
'\OCA\Deck\Card::onCreate',
|
'\OCA\Deck\Card::onCreate',
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ use OCA\Deck\Db\Attachment;
|
|||||||
use OCA\Deck\Db\AttachmentMapper;
|
use OCA\Deck\Db\AttachmentMapper;
|
||||||
use OCA\Deck\StatusException;
|
use OCA\Deck\StatusException;
|
||||||
use OCA\Deck\Exceptions\ConflictException;
|
use OCA\Deck\Exceptions\ConflictException;
|
||||||
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
|
use OCP\AppFramework\Http\FileDisplayResponse;
|
||||||
use OCP\AppFramework\Http\StreamResponse;
|
use OCP\AppFramework\Http\StreamResponse;
|
||||||
use OCP\Files\IAppData;
|
use OCP\Files\IAppData;
|
||||||
use OCP\Files\IMimeTypeDetector;
|
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
use OCP\Files\NotFoundException;
|
use OCP\Files\NotFoundException;
|
||||||
use OCP\Files\NotPermittedException;
|
use OCP\Files\NotPermittedException;
|
||||||
@@ -48,7 +49,6 @@ class FileService implements IAttachmentService {
|
|||||||
private $rootFolder;
|
private $rootFolder;
|
||||||
private $config;
|
private $config;
|
||||||
private $attachmentMapper;
|
private $attachmentMapper;
|
||||||
private $mimeTypeDetector;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IL10N $l10n,
|
IL10N $l10n,
|
||||||
@@ -57,8 +57,7 @@ class FileService implements IAttachmentService {
|
|||||||
ILogger $logger,
|
ILogger $logger,
|
||||||
IRootFolder $rootFolder,
|
IRootFolder $rootFolder,
|
||||||
IConfig $config,
|
IConfig $config,
|
||||||
AttachmentMapper $attachmentMapper,
|
AttachmentMapper $attachmentMapper
|
||||||
IMimeTypeDetector $mimeTypeDetector
|
|
||||||
) {
|
) {
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
$this->appData = $appData;
|
$this->appData = $appData;
|
||||||
@@ -67,7 +66,6 @@ class FileService implements IAttachmentService {
|
|||||||
$this->rootFolder = $rootFolder;
|
$this->rootFolder = $rootFolder;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->attachmentMapper = $attachmentMapper;
|
$this->attachmentMapper = $attachmentMapper;
|
||||||
$this->mimeTypeDetector = $mimeTypeDetector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -227,14 +225,27 @@ class FileService implements IAttachmentService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Attachment $attachment
|
* @param Attachment $attachment
|
||||||
* @return StreamResponse
|
* @return FileDisplayResponse|\OCP\AppFramework\Http\Response|StreamResponse
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function display(Attachment $attachment) {
|
public function display(Attachment $attachment) {
|
||||||
$file = $this->getFileFromRootFolder($attachment);
|
$file = $this->getFileFromRootFolder($attachment);
|
||||||
$response = new StreamResponse($file->fopen('rb'));
|
if (method_exists($file, 'fopen')) {
|
||||||
$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurldecode($file->getName()) . '"');
|
$response = new StreamResponse($file->fopen('r'));
|
||||||
$response->addHeader('Content-Type', $this->mimeTypeDetector->getSecureMimeType($file->getMimeType()));
|
$response->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
||||||
|
} else {
|
||||||
|
$response = new FileDisplayResponse($file);
|
||||||
|
}
|
||||||
|
// We need those since otherwise chrome won't show the PDF file with CSP rule object-src 'none'
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=271452
|
||||||
|
$policy = new ContentSecurityPolicy();
|
||||||
|
$policy->addAllowedObjectDomain('\'self\'');
|
||||||
|
$policy->addAllowedObjectDomain('blob:');
|
||||||
|
$policy->addAllowedMediaDomain('\'self\'');
|
||||||
|
$policy->addAllowedMediaDomain('blob:');
|
||||||
|
$response->setContentSecurityPolicy($policy);
|
||||||
|
|
||||||
|
$response->addHeader('Content-Type', $file->getMimeType());
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ namespace OCA\Deck\Service;
|
|||||||
use OCA\Deck\Db\Attachment;
|
use OCA\Deck\Db\Attachment;
|
||||||
use OCA\Deck\Sharing\DeckShareProvider;
|
use OCA\Deck\Sharing\DeckShareProvider;
|
||||||
use OCA\Deck\StatusException;
|
use OCA\Deck\StatusException;
|
||||||
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
|
use OCP\AppFramework\Http\FileDisplayResponse;
|
||||||
use OCP\AppFramework\Http\StreamResponse;
|
use OCP\AppFramework\Http\StreamResponse;
|
||||||
use OCP\Constants;
|
use OCP\Constants;
|
||||||
use OCP\Files\IMimeTypeDetector;
|
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
use OCP\Files\NotFoundException;
|
use OCP\Files\NotFoundException;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
@@ -49,7 +50,6 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
|
|||||||
private $l10n;
|
private $l10n;
|
||||||
private $preview;
|
private $preview;
|
||||||
private $permissionService;
|
private $permissionService;
|
||||||
private $mimeTypeDetector;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
@@ -60,7 +60,6 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
|
|||||||
DeckShareProvider $shareProvider,
|
DeckShareProvider $shareProvider,
|
||||||
IPreview $preview,
|
IPreview $preview,
|
||||||
PermissionService $permissionService,
|
PermissionService $permissionService,
|
||||||
IMimeTypeDetector $mimeTypeDetector,
|
|
||||||
string $userId = null
|
string $userId = null
|
||||||
) {
|
) {
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
@@ -71,7 +70,6 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
|
|||||||
$this->shareManager = $shareManager;
|
$this->shareManager = $shareManager;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
$this->preview = $preview;
|
$this->preview = $preview;
|
||||||
$this->mimeTypeDetector = $mimeTypeDetector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function listAttachments(int $cardId): array {
|
public function listAttachments(int $cardId): array {
|
||||||
@@ -149,10 +147,22 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
|
|||||||
if ($file === null || $share->getSharedWith() !== (string)$attachment->getCardId()) {
|
if ($file === null || $share->getSharedWith() !== (string)$attachment->getCardId()) {
|
||||||
throw new NotFoundException('File not found');
|
throw new NotFoundException('File not found');
|
||||||
}
|
}
|
||||||
|
if (method_exists($file, 'fopen')) {
|
||||||
|
$response = new StreamResponse($file->fopen('r'));
|
||||||
|
$response->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
||||||
|
} else {
|
||||||
|
$response = new FileDisplayResponse($file);
|
||||||
|
}
|
||||||
|
// We need those since otherwise chrome won't show the PDF file with CSP rule object-src 'none'
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=271452
|
||||||
|
$policy = new ContentSecurityPolicy();
|
||||||
|
$policy->addAllowedObjectDomain('\'self\'');
|
||||||
|
$policy->addAllowedObjectDomain('blob:');
|
||||||
|
$policy->addAllowedMediaDomain('\'self\'');
|
||||||
|
$policy->addAllowedMediaDomain('blob:');
|
||||||
|
$response->setContentSecurityPolicy($policy);
|
||||||
|
|
||||||
$response = new StreamResponse($file->fopen('rb'));
|
$response->addHeader('Content-Type', $file->getMimeType());
|
||||||
$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurldecode($file->getName()) . '"');
|
|
||||||
$response->addHeader('Content-Type', $this->mimeTypeDetector->getSecureMimeType($file->getMimeType()));
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
|
this.$emit('close')
|
||||||
this.$root.$emit('close')
|
this.$root.$emit('close')
|
||||||
},
|
},
|
||||||
async select() {
|
async select() {
|
||||||
|
|||||||
@@ -28,11 +28,11 @@
|
|||||||
:members="members"
|
:members="members"
|
||||||
name-key="uid"
|
name-key="uid"
|
||||||
:tab-select="true">
|
:tab-select="true">
|
||||||
<template v-slot:item="s">
|
<template #item="s">
|
||||||
<Avatar class="atwho-li--avatar" :user="s.item.uid" :size="24" />
|
<Avatar class="atwho-li--avatar" :user="s.item.uid" :size="24" />
|
||||||
<span class="atwho-li--name" v-text="s.item.displayname" />
|
<span class="atwho-li--name" v-text="s.item.displayname" />
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:embeddedItem="scope">
|
<template #embeddedItem="scope">
|
||||||
<span>
|
<span>
|
||||||
<UserBubble v-if="scope.current.uid"
|
<UserBubble v-if="scope.current.uid"
|
||||||
:data-mention-id="scope.current.uid"
|
:data-mention-id="scope.current.uid"
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ export default {
|
|||||||
directives: {
|
directives: {
|
||||||
ClickOutside,
|
ClickOutside,
|
||||||
},
|
},
|
||||||
|
inject: [
|
||||||
|
'boardApi',
|
||||||
|
],
|
||||||
props: {
|
props: {
|
||||||
board: {
|
board: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -312,9 +315,6 @@ export default {
|
|||||||
this.updateDueSetting = null
|
this.updateDueSetting = null
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inject: [
|
|
||||||
'boardApi',
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -21,32 +21,40 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DashboardWidget :items="cards"
|
<div>
|
||||||
empty-content-icon="icon-deck"
|
<DashboardWidget :items="cards"
|
||||||
:empty-content-message="t('deck', 'No upcoming cards')"
|
empty-content-icon="icon-deck"
|
||||||
:show-more-text="t('deck', 'upcoming cards')"
|
:empty-content-message="t('deck', 'No upcoming cards')"
|
||||||
:show-more-url="showMoreUrl"
|
:show-more-text="t('deck', 'upcoming cards')"
|
||||||
:loading="loading"
|
:show-more-url="showMoreUrl"
|
||||||
@hide="() => {}"
|
:loading="loading"
|
||||||
@markDone="() => {}">
|
@hide="() => {}"
|
||||||
<template v-slot:default="{ item }">
|
@markDone="() => {}">
|
||||||
<a :key="item.id"
|
<template #default="{ item }">
|
||||||
:href="cardLink(item)"
|
<a :key="item.id"
|
||||||
target="_blank"
|
:href="cardLink(item)"
|
||||||
class="card">
|
target="_blank"
|
||||||
<div class="card--header">
|
class="card">
|
||||||
<DueDate class="right" :card="item" />
|
<div class="card--header">
|
||||||
<span class="title">{{ item.title }}</span>
|
<DueDate class="right" :card="item" />
|
||||||
</div>
|
<span class="title">{{ item.title }}</span>
|
||||||
<ul v-if="item.labels && item.labels.length"
|
</div>
|
||||||
class="labels">
|
<ul v-if="item.labels && item.labels.length"
|
||||||
<li v-for="label in item.labels" :key="label.id" :style="labelStyle(label)">
|
class="labels">
|
||||||
<span>{{ label.title }}</span>
|
<li v-for="label in item.labels" :key="label.id" :style="labelStyle(label)">
|
||||||
</li>
|
<span>{{ label.title }}</span>
|
||||||
</ul>
|
</li>
|
||||||
</a>
|
</ul>
|
||||||
</template>
|
</a>
|
||||||
</DashboardWidget>
|
</template>
|
||||||
|
</DashboardWidget>
|
||||||
|
<div class="center-button">
|
||||||
|
<button @click="toggleAddCardModel">
|
||||||
|
{{ t('deck', 'Add card') }}
|
||||||
|
</button>
|
||||||
|
<CardCreateDialog v-if="showAddCardModal" @close="toggleAddCardModel" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -55,17 +63,20 @@ import { mapGetters } from 'vuex'
|
|||||||
import labelStyle from './../mixins/labelStyle'
|
import labelStyle from './../mixins/labelStyle'
|
||||||
import DueDate from '../components/cards/badges/DueDate'
|
import DueDate from '../components/cards/badges/DueDate'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import CardCreateDialog from '../CardCreateDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
components: {
|
components: {
|
||||||
DueDate,
|
DueDate,
|
||||||
DashboardWidget,
|
DashboardWidget,
|
||||||
|
CardCreateDialog,
|
||||||
},
|
},
|
||||||
mixins: [labelStyle],
|
mixins: [labelStyle],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
showAddCardModal: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -73,11 +84,17 @@ export default {
|
|||||||
'assignedCardsDashboard',
|
'assignedCardsDashboard',
|
||||||
]),
|
]),
|
||||||
cards() {
|
cards() {
|
||||||
const list = [
|
/* const list = [
|
||||||
...this.assignedCardsDashboard,
|
...this.assignedCardsDashboard,
|
||||||
].filter((card) => {
|
].filter((card) => {
|
||||||
return card.duedate !== null
|
return card.duedate !== null
|
||||||
})
|
}) */
|
||||||
|
|
||||||
|
const list = this.assignedCardsDashboard.slice(0, 6)
|
||||||
|
.filter((card) => {
|
||||||
|
return card.duedate !== null
|
||||||
|
})
|
||||||
|
|
||||||
list.sort((a, b) => {
|
list.sort((a, b) => {
|
||||||
return (new Date(a.duedate)).getTime() - (new Date(b.duedate)).getTime()
|
return (new Date(a.duedate)).getTime() - (new Date(b.duedate)).getTime()
|
||||||
})
|
})
|
||||||
@@ -98,6 +115,11 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
toggleAddCardModel() {
|
||||||
|
this.showAddCardModal = !this.showAddCardModal
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -145,4 +167,8 @@ export default {
|
|||||||
.right {
|
.right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center-button {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ namespace OCA\Deck\Service;
|
|||||||
|
|
||||||
use OCA\Deck\Db\Attachment;
|
use OCA\Deck\Db\Attachment;
|
||||||
use OCA\Deck\Db\AttachmentMapper;
|
use OCA\Deck\Db\AttachmentMapper;
|
||||||
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
use OCP\AppFramework\Http\StreamResponse;
|
use OCP\AppFramework\Http\StreamResponse;
|
||||||
use OCP\Files\Folder;
|
use OCP\Files\Folder;
|
||||||
use OCP\Files\IAppData;
|
use OCP\Files\IAppData;
|
||||||
use OCP\Files\IMimeTypeDetector;
|
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
use OCP\Files\SimpleFS\ISimpleFile;
|
use OCP\Files\SimpleFS\ISimpleFile;
|
||||||
use OCP\Files\SimpleFS\ISimpleFolder;
|
use OCP\Files\SimpleFS\ISimpleFolder;
|
||||||
@@ -57,8 +57,6 @@ class FileServiceTest extends TestCase {
|
|||||||
private $config;
|
private $config;
|
||||||
/** @var AttachmentMapper|MockObject */
|
/** @var AttachmentMapper|MockObject */
|
||||||
private $attachmentMapper;
|
private $attachmentMapper;
|
||||||
/** @var IMimeTypeDetector|MockObject */
|
|
||||||
private $mimeTypeDetector;
|
|
||||||
|
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
@@ -69,8 +67,7 @@ class FileServiceTest extends TestCase {
|
|||||||
$this->rootFolder = $this->createMock(IRootFolder::class);
|
$this->rootFolder = $this->createMock(IRootFolder::class);
|
||||||
$this->config = $this->createMock(IConfig::class);
|
$this->config = $this->createMock(IConfig::class);
|
||||||
$this->attachmentMapper = $this->createMock(AttachmentMapper::class);
|
$this->attachmentMapper = $this->createMock(AttachmentMapper::class);
|
||||||
$this->mimeTypeDetector = $this->createMock(IMimeTypeDetector::class);
|
$this->fileService = new FileService($this->l10n, $this->appData, $this->request, $this->logger, $this->rootFolder, $this->config, $this->attachmentMapper);
|
||||||
$this->fileService = new FileService($this->l10n, $this->appData, $this->request, $this->logger, $this->rootFolder, $this->config, $this->attachmentMapper, $this->mimeTypeDetector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mockGetFolder($cardId) {
|
public function mockGetFolder($cardId) {
|
||||||
@@ -271,13 +268,51 @@ class FileServiceTest extends TestCase {
|
|||||||
$file->expects($this->any())
|
$file->expects($this->any())
|
||||||
->method('fopen')
|
->method('fopen')
|
||||||
->willReturn('fileresource');
|
->willReturn('fileresource');
|
||||||
$this->mimeTypeDetector->expects($this->once())
|
|
||||||
->method('getSecureMimeType')
|
|
||||||
->willReturn('image/jpeg');
|
|
||||||
$actual = $this->fileService->display($attachment);
|
$actual = $this->fileService->display($attachment);
|
||||||
$expected = new StreamResponse('fileresource');
|
$expected = new StreamResponse('fileresource');
|
||||||
$expected->addHeader('Content-Type', 'image/jpeg');
|
$expected->addHeader('Content-Type', 'image/jpeg');
|
||||||
$expected->addHeader('Content-Disposition', 'attachment; filename="' . rawurldecode($file->getName()) . '"');
|
$expected->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
||||||
|
$policy = new ContentSecurityPolicy();
|
||||||
|
$policy->addAllowedObjectDomain('\'self\'');
|
||||||
|
$policy->addAllowedObjectDomain('blob:');
|
||||||
|
$policy->addAllowedMediaDomain('\'self\'');
|
||||||
|
$policy->addAllowedMediaDomain('blob:');
|
||||||
|
$expected->setContentSecurityPolicy($policy);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisplayPdf() {
|
||||||
|
$this->config->expects($this->once())
|
||||||
|
->method('getSystemValue')
|
||||||
|
->willReturn('123');
|
||||||
|
$appDataFolder = $this->createMock(Folder::class);
|
||||||
|
$deckAppDataFolder = $this->createMock(Folder::class);
|
||||||
|
$cardFolder = $this->createMock(Folder::class);
|
||||||
|
$this->rootFolder->expects($this->once())->method('get')->willReturn($appDataFolder);
|
||||||
|
$appDataFolder->expects($this->once())->method('get')->willReturn($deckAppDataFolder);
|
||||||
|
$deckAppDataFolder->expects($this->once())->method('get')->willReturn($cardFolder);
|
||||||
|
$attachment = $this->getAttachment();
|
||||||
|
$file = $this->createMock(\OCP\Files\File::class);
|
||||||
|
$cardFolder->expects($this->once())->method('get')->willReturn($file);
|
||||||
|
$file->expects($this->any())
|
||||||
|
->method('getMimeType')
|
||||||
|
->willReturn('application/pdf');
|
||||||
|
$file->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->willReturn('file1');
|
||||||
|
$file->expects($this->any())
|
||||||
|
->method('fopen')
|
||||||
|
->willReturn('fileresource');
|
||||||
|
$actual = $this->fileService->display($attachment);
|
||||||
|
$expected = new StreamResponse('fileresource');
|
||||||
|
$expected->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
||||||
|
$expected->addHeader('Content-Type', 'application/pdf');
|
||||||
|
$policy = new ContentSecurityPolicy();
|
||||||
|
$policy->addAllowedObjectDomain('\'self\'');
|
||||||
|
$policy->addAllowedObjectDomain('blob:');
|
||||||
|
$policy->addAllowedMediaDomain('\'self\'');
|
||||||
|
$policy->addAllowedMediaDomain('blob:');
|
||||||
|
$expected->setContentSecurityPolicy($policy);
|
||||||
$this->assertEquals($expected, $actual);
|
$this->assertEquals($expected, $actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const config = {
|
|||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
jsonpFunction: 'webpackJsonpOCADeck',
|
// jsonpFunction: 'webpackJsonpOCADeck',
|
||||||
chunkFilename: '[name].js?v=[contenthash]',
|
chunkFilename: '[name].js?v=[contenthash]',
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|||||||
Reference in New Issue
Block a user