Move to dedicated file attachment service
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -62,8 +62,6 @@ class AttachmentService {
|
||||
private $activityManager;
|
||||
/** @var ChangeHelper */
|
||||
private $changeHelper;
|
||||
/** @var DeckShareProvider */
|
||||
private $shareProvider;
|
||||
|
||||
public function __construct(AttachmentMapper $attachmentMapper, CardMapper $cardMapper, ChangeHelper $changeHelper, PermissionService $permissionService, Application $application, ICacheFactory $cacheFactory, $userId, IL10N $l10n, ActivityManager $activityManager, DeckShareProvider $shareProvider) {
|
||||
$this->attachmentMapper = $attachmentMapper;
|
||||
@@ -75,11 +73,11 @@ class AttachmentService {
|
||||
$this->l10n = $l10n;
|
||||
$this->activityManager = $activityManager;
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->shareProvider = $shareProvider;
|
||||
|
||||
// Register shipped attachment services
|
||||
// TODO: move this to a plugin based approach once we have different types of attachments
|
||||
$this->registerAttachmentService('deck_file', FileService::class);
|
||||
$this->registerAttachmentService('file', FilesAppService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,6 +118,15 @@ class AttachmentService {
|
||||
if ($withDeleted) {
|
||||
$attachments = array_merge($attachments, $this->attachmentMapper->findToDelete($cardId, false));
|
||||
}
|
||||
|
||||
foreach (array_keys($this->services) as $attachmentType) {
|
||||
/** @var IAttachmentService $service */
|
||||
$service = $this->getService($attachmentType);
|
||||
if ($service instanceof ICustomAttachmentService) {
|
||||
$attachments = array_merge($attachments, $service->listAttachments($cardId));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachments as &$attachment) {
|
||||
try {
|
||||
$service = $this->getService($attachment->getType());
|
||||
@@ -129,37 +136,7 @@ class AttachmentService {
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($attachments, $this->getFilesAppAttachments($cardId));
|
||||
}
|
||||
|
||||
private function getFilesAppAttachments($cardId) {
|
||||
/** @var IPreview $previewManager */
|
||||
$previewManager = \OC::$server->get(IPreview::class);
|
||||
$userFolder = \OC::$server->getRootFolder()->getUserFolder($this->userId);
|
||||
$shares = $this->shareProvider->getSharedWithByType($cardId, IShare::TYPE_DECK, -1, 0);
|
||||
return array_map(function (IShare $share) use ($cardId, $userFolder, $previewManager) {
|
||||
$file = $share->getNode();
|
||||
$nodes = $userFolder->getById($file->getId());
|
||||
$userNode = array_shift($nodes);
|
||||
return [
|
||||
// general attachment attributes
|
||||
'cardId' => $cardId,
|
||||
'type' => 'file',
|
||||
'data' => $file->getName(),
|
||||
'lastModified' => $file->getMTime(),
|
||||
'createdAt' => $file->getMTime(),
|
||||
'deletedAt' => 0,
|
||||
// file type attributes
|
||||
'fileid' => $file->getId(),
|
||||
'path' => $userFolder->getRelativePath($userNode->getPath()),
|
||||
'extendedData' => [
|
||||
'filesize' => $file->getSize(),
|
||||
'mimetype' => $file->getMimeType(),
|
||||
'info' => pathinfo($file->getName()),
|
||||
'hasPreview' => $previewManager->isAvailable($file),
|
||||
]
|
||||
];
|
||||
}, $shares);
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,22 +155,7 @@ class AttachmentService {
|
||||
$this->cache->set('card-' . $cardId, $count);
|
||||
}
|
||||
|
||||
/** @var IDBConnection $qb */
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$qb = $db->getQueryBuilder();
|
||||
$qb->select($qb->createFunction('count(s.id)'))
|
||||
->from('share', 's')
|
||||
->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
|
||||
->andWhere($qb->expr()->eq('s.share_with', $qb->createNamedParameter($cardId)))
|
||||
->andWhere($qb->expr()->isNull('s.parent'))
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('file')),
|
||||
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('folder'))
|
||||
));
|
||||
|
||||
$cursor = $qb->execute();
|
||||
$count += $cursor->fetchColumn(0);
|
||||
$cursor->closeCursor();
|
||||
|
||||
return $count;
|
||||
}
|
||||
@@ -234,21 +196,21 @@ class AttachmentService {
|
||||
try {
|
||||
$service = $this->getService($attachment->getType());
|
||||
$service->create($attachment);
|
||||
} catch (InvalidAttachmentType $e) {
|
||||
// just store the data
|
||||
}
|
||||
|
||||
if (!$service instanceof ICustomAttachmentService) {
|
||||
if ($attachment->getData() === null) {
|
||||
throw new StatusException($this->l10n->t('No data was provided to create an attachment.'));
|
||||
}
|
||||
$attachment = $this->attachmentMapper->insert($attachment);
|
||||
|
||||
// extend data so the frontend can use it properly after creating
|
||||
try {
|
||||
$service = $this->getService($attachment->getType());
|
||||
$attachment = $this->attachmentMapper->insert($attachment);
|
||||
}
|
||||
|
||||
$service->extendData($attachment);
|
||||
|
||||
} catch (InvalidAttachmentType $e) {
|
||||
// just store the data
|
||||
}
|
||||
|
||||
$this->changeHelper->cardChanged($attachment->getCardId());
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_CREATE);
|
||||
return $attachment;
|
||||
@@ -260,17 +222,11 @@ class AttachmentService {
|
||||
*
|
||||
* @param $attachmentId
|
||||
* @return Response
|
||||
* @throws BadRequestException
|
||||
* @throws NoPermissionException
|
||||
* @throws NotFoundException
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
*/
|
||||
public function display($attachmentId) {
|
||||
if (is_numeric($attachmentId) === false) {
|
||||
throw new BadRequestException('attachment id must be a number');
|
||||
}
|
||||
|
||||
if (is_numeric($attachmentId)) {
|
||||
try {
|
||||
$attachment = $this->attachmentMapper->find($attachmentId);
|
||||
} catch (\Exception $e) {
|
||||
@@ -286,16 +242,28 @@ class AttachmentService {
|
||||
}
|
||||
}
|
||||
|
||||
[$type, $attachmentId] = explode(':', $attachmentId);
|
||||
|
||||
try {
|
||||
$attachment = new Attachment();
|
||||
$attachment->setId($attachmentId);
|
||||
$attachment->setType($type);
|
||||
$service = $this->getService($type);
|
||||
return $service->display($attachment);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an attachment with custom data
|
||||
*
|
||||
* @param $attachmentId
|
||||
* @param $request
|
||||
* @param $data
|
||||
* @return mixed
|
||||
* @throws \OCA\Deck\NoPermissionException
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws BadRequestException
|
||||
* @throws NoPermissionException
|
||||
*/
|
||||
public function update($attachmentId, $data) {
|
||||
if (is_numeric($attachmentId) === false) {
|
||||
|
||||
@@ -148,4 +148,8 @@ class ConfigService {
|
||||
}, $groups);
|
||||
return array_filter($groups);
|
||||
}
|
||||
|
||||
public function getAttachmentFolder(): string {
|
||||
return $this->config->getUserValue($this->userId, 'deck', 'attachment_folder', '/Deck');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\Share\IManager;
|
||||
|
||||
class FileService implements IAttachmentService {
|
||||
private $l10n;
|
||||
@@ -57,7 +58,8 @@ class FileService implements IAttachmentService {
|
||||
ILogger $logger,
|
||||
IRootFolder $rootFolder,
|
||||
IConfig $config,
|
||||
AttachmentMapper $attachmentMapper
|
||||
AttachmentMapper $attachmentMapper,
|
||||
IManager $shareManager
|
||||
) {
|
||||
$this->l10n = $l10n;
|
||||
$this->appData = $appData;
|
||||
@@ -66,6 +68,7 @@ class FileService implements IAttachmentService {
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->config = $config;
|
||||
$this->attachmentMapper = $attachmentMapper;
|
||||
$this->shareManager = $shareManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
260
lib/Service/FilesAppService.php
Normal file
260
lib/Service/FilesAppService.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 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\Service;
|
||||
|
||||
use OCA\Deck\Db\Attachment;
|
||||
use OCA\Deck\Db\AttachmentMapper;
|
||||
use OCA\Deck\Sharing\DeckShareProvider;
|
||||
use OCA\Deck\StatusException;
|
||||
use OCA\Deck\Exceptions\ConflictException;
|
||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||
use OCP\AppFramework\Http\FileDisplayResponse;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use OCP\AppFramework\Http\StreamResponse;
|
||||
use OCP\Constants;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\NotPermittedException;
|
||||
use OCP\Files\SimpleFS\ISimpleFile;
|
||||
use OCP\Files\SimpleFS\ISimpleFolder;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IL10N;
|
||||
use OCP\ILogger;
|
||||
use OCP\IPreview;
|
||||
use OCP\IRequest;
|
||||
use OCP\Share;
|
||||
use OCP\Share\IManager;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
class FilesAppService implements IAttachmentService, ICustomAttachmentService {
|
||||
|
||||
private $request;
|
||||
private $rootFolder;
|
||||
private $shareProvider;
|
||||
private $shareManager;
|
||||
private $userId;
|
||||
private $configService;
|
||||
private $l10n;
|
||||
private $preview;
|
||||
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
IL10N $l10n,
|
||||
IRootFolder $rootFolder,
|
||||
IManager $shareManager,
|
||||
ConfigService $configService,
|
||||
DeckShareProvider $shareProvider,
|
||||
IPreview $preview,
|
||||
string $userId = null
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->l10n = $l10n;
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->configService = $configService;
|
||||
$this->shareProvider = $shareProvider;
|
||||
$this->shareManager = $shareManager;
|
||||
$this->userId = $userId;
|
||||
$this->preview = $preview;
|
||||
}
|
||||
|
||||
public function listAttachments(int $cardId): array {
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$shares = $this->shareProvider->getSharedWithByType($cardId, IShare::TYPE_DECK, -1, 0);
|
||||
return array_map(function (IShare $share) use ($cardId, $userFolder) {
|
||||
$file = $share->getNode();
|
||||
$nodes = $userFolder->getById($file->getId());
|
||||
$file = array_shift($nodes);
|
||||
$attachment = new Attachment();
|
||||
$attachment->setType('file');
|
||||
$attachment->setId($file->getId());
|
||||
$attachment->setCardId($cardId);
|
||||
$attachment->setCreatedBy($share->getSharedBy());
|
||||
$attachment->setData($file->getName());
|
||||
$attachment->setLastModified($file->getMTime());
|
||||
$attachment->setCreatedAt($share->getShareTime()->getTimestamp());
|
||||
$attachment->setDeletedAt(0);
|
||||
return $attachment;
|
||||
}, $shares);
|
||||
}
|
||||
|
||||
function getAttachmentCount(int $cardId): int {
|
||||
/** @var IDBConnection $qb */
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$qb = $db->getQueryBuilder();
|
||||
$qb->select($qb->createFunction('count(s.id)'))
|
||||
->from('share', 's')
|
||||
->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
|
||||
->andWhere($qb->expr()->eq('s.share_with', $qb->createNamedParameter($cardId)))
|
||||
->andWhere($qb->expr()->isNull('s.parent'))
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('file')),
|
||||
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('folder'))
|
||||
));
|
||||
|
||||
$cursor = $qb->execute();
|
||||
$count = $cursor->fetchColumn(0);
|
||||
$cursor->closeCursor();
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function extendData(Attachment $attachment) {
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$nodes = $userFolder->getById($attachment->getId());
|
||||
$file = array_shift($nodes);
|
||||
$attachment->setExtendedData([
|
||||
'path' => $userFolder->getRelativePath($file->getPath()),
|
||||
'fileid' => $file->getId(),
|
||||
'data' => $file->getName(),
|
||||
'filesize' => $file->getSize(),
|
||||
'mimetype' => $file->getMimeType(),
|
||||
'info' => pathinfo($file->getName()),
|
||||
'hasPreview' => $this->preview->isAvailable($file),
|
||||
]);
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
public function display(Attachment $attachment) {
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$nodes = $userFolder->getById($attachment->getId());
|
||||
$file = array_shift($nodes);
|
||||
if ($file === null) {
|
||||
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->addHeader('Content-Type', $file->getMimeType());
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function create(Attachment $attachment) {
|
||||
$file = $this->getUploadedFile();
|
||||
$fileName = $file['name'];
|
||||
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$folder = $userFolder->get($this->configService->getAttachmentFolder());
|
||||
|
||||
// FIXME: Add to docs that conflict handling is different here, no ConflictException will be thrown
|
||||
$fileName = $folder->getNonExistingName($fileName);
|
||||
$target = $folder->newFile($fileName);
|
||||
$content = fopen($file['tmp_name'], 'rb');
|
||||
if ($content === false) {
|
||||
throw new StatusException('Could not read file');
|
||||
}
|
||||
$target->putContent($content);
|
||||
if (is_resource($content)) {
|
||||
fclose($content);
|
||||
}
|
||||
|
||||
$share = $this->shareManager->newShare();
|
||||
$share->setNode($target);
|
||||
$share->setShareType(Share::SHARE_TYPE_DECK);
|
||||
$share->setSharedWith((string)$attachment->getCardId());
|
||||
$share->setPermissions(Constants::PERMISSION_READ);
|
||||
$share->setSharedBy($this->userId);
|
||||
$this->shareManager->createShare($share);
|
||||
$attachment->setId($target->getId());
|
||||
$attachment->setData($target->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws StatusException
|
||||
*/
|
||||
private function getUploadedFile() {
|
||||
$file = $this->request->getUploadedFile('file');
|
||||
$error = null;
|
||||
$phpFileUploadErrors = [
|
||||
UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
|
||||
UPLOAD_ERR_INI_SIZE => $this->l10n->t('The uploaded file exceeds the upload_max_filesize directive in php.ini'),
|
||||
UPLOAD_ERR_FORM_SIZE => $this->l10n->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
|
||||
UPLOAD_ERR_PARTIAL => $this->l10n->t('The file was only partially uploaded'),
|
||||
UPLOAD_ERR_NO_FILE => $this->l10n->t('No file was uploaded'),
|
||||
UPLOAD_ERR_NO_TMP_DIR => $this->l10n->t('Missing a temporary folder'),
|
||||
UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
|
||||
UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
|
||||
];
|
||||
|
||||
if (empty($file)) {
|
||||
$error = $this->l10n->t('No file uploaded or file size exceeds maximum of %s', [\OCP\Util::humanFileSize(\OCP\Util::uploadLimit())]);
|
||||
}
|
||||
if (!empty($file) && array_key_exists('error', $file) && $file['error'] !== UPLOAD_ERR_OK) {
|
||||
$error = $phpFileUploadErrors[$file['error']];
|
||||
}
|
||||
if ($error !== null) {
|
||||
throw new StatusException($error);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function update(Attachment $attachment) {
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
|
||||
public function delete(Attachment $attachment) {
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$nodes = $userFolder->getById($attachment->getId());
|
||||
$file = array_shift($nodes);
|
||||
if ($file === null) {
|
||||
throw new NotFoundException('File not found');
|
||||
}
|
||||
|
||||
if ($file->getOwner() !== null && $file->getOwner()->getUID() === $this->userId) {
|
||||
$file->delete();
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: only with manage permissions
|
||||
$shares = $this->shareProvider->getSharedWithByType($attachment->getCardId(), IShare::TYPE_DECK, -1, 0);
|
||||
foreach ($shares as $share) {
|
||||
if ($share->getNode()->getId() === $attachment->getId()) {
|
||||
$this->shareManager->deleteShare($share);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function allowUndo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function markAsDeleted(Attachment $attachment) {
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
}
|
||||
42
lib/Service/ICustomAttachmentService.php
Normal file
42
lib/Service/ICustomAttachmentService.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (c) 2020 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\Service;
|
||||
|
||||
|
||||
/**
|
||||
* Interface to implement in case attachments are handled by a different backend than
|
||||
* then oc_deck_attachments table, e.g. for file sharing. When this interface is used
|
||||
* for implementing an attachment handler no backlink will be stored in the deck attachments
|
||||
* table and it is up to the implementation to track attachment to card relation.
|
||||
*/
|
||||
interface ICustomAttachmentService {
|
||||
|
||||
public function listAttachments(int $cardId): array;
|
||||
|
||||
public function getAttachmentCount(int $cardId): int;
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace OCA\Deck\Sharing;
|
||||
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OCA\Deck\Service\ConfigService;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Share\Events\VerifyMountPointEvent;
|
||||
use OCP\Share\IShare;
|
||||
@@ -35,7 +36,13 @@ use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
class Listener {
|
||||
|
||||
public function __construct($userId) {
|
||||
/** @var ConfigService */
|
||||
private $configService;
|
||||
/** @var string|null */
|
||||
private $userId;
|
||||
|
||||
public function __construct(ConfigService $configService, $userId) {
|
||||
$this->configService = $configService;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
@@ -99,15 +106,11 @@ class Listener {
|
||||
}
|
||||
}
|
||||
|
||||
$parent = $this->getAttachmentFolder();
|
||||
$parent = $this->configService->getAttachmentFolder();
|
||||
$event->setParent($parent);
|
||||
if (!$event->getView()->is_dir($parent)) {
|
||||
$event->getView()->mkdir($parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getAttachmentFolder() {
|
||||
return \OC::$server->getConfig()->getUserValue($this->userId, 'deck', 'attachment_folder', '/Deck');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,17 +69,17 @@
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
<Actions v-if="removable" :force-menu="true">
|
||||
<ActionLink v-if="attachment.fileid" icon="icon-folder" :href="'/index.php/f/'+attachment.fileid">
|
||||
<ActionLink v-if="attachment.extendedData.fileid" icon="icon-folder" :href="'/index.php/f/'+attachment.extendedData.fileid">
|
||||
{{ t('deck', 'Show in files') }}
|
||||
</ActionLink>
|
||||
<ActionButton v-if="attachment.fileid" icon="icon-delete">
|
||||
<ActionButton v-if="attachment.extendedData.fileid" icon="icon-delete">
|
||||
{{ t('deck', 'Unshare file') }}
|
||||
</ActionButton>
|
||||
|
||||
<ActionButton v-if="!attachment.fileid && attachment.deletedAt === 0" icon="icon-delete" @click="$emit('deleteAttachment', attachment)">
|
||||
<ActionButton v-if="!attachment.extendedData.fileid && attachment.deletedAt === 0" icon="icon-delete" @click="$emit('deleteAttachment', attachment)">
|
||||
{{ t('deck', 'Delete Attachment') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-else-if="!attachment.fileid" icon="icon-history" @click="$emit('restoreAttachment', attachment)">
|
||||
<ActionButton v-else-if="!attachment.extendedData.fileid" icon="icon-history" @click="$emit('restoreAttachment', attachment)">
|
||||
{{ t('deck', 'Restore Attachment') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
@@ -89,11 +89,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from '@nextcloud/axios'
|
||||
import { Actions, ActionButton, ActionLink } from '@nextcloud/vue'
|
||||
import AttachmentDragAndDrop from '../AttachmentDragAndDrop'
|
||||
import relativeDate from '../../mixins/relativeDate'
|
||||
import { formatFileSize } from '@nextcloud/files'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { generateUrl, generateOcsUrl } from '@nextcloud/router'
|
||||
import { mapState } from 'vuex'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import attachmentUpload from '../../mixins/attachmentUpload'
|
||||
@@ -154,7 +155,7 @@ export default {
|
||||
}
|
||||
},
|
||||
attachmentPreview() {
|
||||
return (attachment) => (attachment.fileid ? generateUrl(`/core/preview?fileId=${attachment.fileid}&x=64&y=64&a=true`) : null)
|
||||
return (attachment) => (attachment.extendedData.fileid ? generateUrl(`/core/preview?fileId=${attachment.extendedData.fileid}&x=64&y=64&a=true`) : null)
|
||||
},
|
||||
attachmentUrl() {
|
||||
return (attachment) => generateUrl(`/apps/deck/cards/${attachment.cardId}/attachment/${attachment.id}`)
|
||||
@@ -202,7 +203,15 @@ export default {
|
||||
if (!path.startsWith('/')) {
|
||||
throw new Error(t('files', 'Invalid path selected'))
|
||||
}
|
||||
// FIXME: Share file
|
||||
|
||||
axios.post(generateOcsUrl('apps/files_sharing/api/v1', 2) + 'shares', {
|
||||
path,
|
||||
permissions: 19,
|
||||
shareType: 12,
|
||||
shareWith: '' + this.cardId,
|
||||
}).then(() => {
|
||||
this.$store.dispatch('fetchAttachments', this.cardId)
|
||||
})
|
||||
})
|
||||
},
|
||||
clickAddNewAttachmment() {
|
||||
@@ -210,10 +219,10 @@ export default {
|
||||
},
|
||||
showViewer(attachment) {
|
||||
if (window.OCA.Viewer.availableHandlers.map(handler => handler.mimes).flat().includes(attachment.extendedData.mimetype)) {
|
||||
window.OCA.Viewer.open(attachment.path)
|
||||
window.OCA.Viewer.open(attachment.extendedData.path)
|
||||
return
|
||||
}
|
||||
window.location = generateUrl('/f/' + attachment.fileid)
|
||||
window.location = generateUrl('/f/' + attachment.extendedData.fileid)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export default {
|
||||
this.$set(this.uploadQueue, file.name, { name: file.name, progress: 0 })
|
||||
const bodyFormData = new FormData()
|
||||
bodyFormData.append('cardId', this.cardId)
|
||||
bodyFormData.append('type', 'deck_file')
|
||||
bodyFormData.append('type', 'file')
|
||||
bodyFormData.append('file', file)
|
||||
await queue.add(async() => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user