diff options
Diffstat (limited to 'apps/files/lib')
-rw-r--r-- | apps/files/lib/AppInfo/Application.php | 12 | ||||
-rw-r--r-- | apps/files/lib/BackgroundJob/CleanupDirectEditingTokens.php | 31 | ||||
-rw-r--r-- | apps/files/lib/BackgroundJob/TransferOwnership.php | 183 | ||||
-rw-r--r-- | apps/files/lib/Capabilities.php | 25 | ||||
-rw-r--r-- | apps/files/lib/Controller/DirectEditingController.php | 128 | ||||
-rw-r--r-- | apps/files/lib/Controller/DirectEditingViewController.php | 72 | ||||
-rw-r--r-- | apps/files/lib/Controller/TransferOwnershipController.php | 181 | ||||
-rw-r--r-- | apps/files/lib/Db/TransferOwnership.php | 60 | ||||
-rw-r--r-- | apps/files/lib/Db/TransferOwnershipMapper.php | 47 | ||||
-rw-r--r-- | apps/files/lib/Migration/Version11301Date20191113195931.php | 72 | ||||
-rw-r--r-- | apps/files/lib/Notification/Notifier.php | 247 | ||||
-rw-r--r-- | apps/files/lib/Service/DirectEditingService.php | 85 | ||||
-rw-r--r-- | apps/files/lib/Service/OwnershipTransferService.php | 2 | ||||
-rw-r--r-- | apps/files/lib/Settings/PersonalSettings.php | 46 |
14 files changed, 1187 insertions, 4 deletions
diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 1ffd5e96471..f4897d08e54 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -35,6 +35,7 @@ use OCA\Files\Controller\ApiController; use OCA\Files\Controller\ViewController; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Listener\LegacyLoadAdditionalScriptsAdapter; +use OCA\Files\Notification\Notifier; use OCA\Files\Service\TagService; use OCP\AppFramework\App; use OCP\Collaboration\Resources\IManager; @@ -42,8 +43,11 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\IContainer; class Application extends App { + + public const APP_ID = 'files'; + public function __construct(array $urlParams=array()) { - parent::__construct('files', $urlParams); + parent::__construct(self::APP_ID, $urlParams); $container = $this->getContainer(); $server = $container->getServer(); @@ -71,7 +75,7 @@ class Application extends App { return new TagService( $c->query('ServerContainer')->getUserSession(), $c->query('ServerContainer')->getActivityManager(), - $c->query('ServerContainer')->getTagManager()->load('files'), + $c->query('ServerContainer')->getTagManager()->load(self::APP_ID), $homeFolder, $server->getEventDispatcher() ); @@ -93,5 +97,9 @@ class Application extends App { /** @var IEventDispatcher $dispatcher */ $dispatcher = $container->query(IEventDispatcher::class); $dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LegacyLoadAdditionalScriptsAdapter::class); + + /** @var \OCP\Notification\IManager $notifications */ + $notifications = $container->query(\OCP\Notification\IManager::class); + $notifications->registerNotifierService(Notifier::class); } } diff --git a/apps/files/lib/BackgroundJob/CleanupDirectEditingTokens.php b/apps/files/lib/BackgroundJob/CleanupDirectEditingTokens.php new file mode 100644 index 00000000000..8d4a3f23787 --- /dev/null +++ b/apps/files/lib/BackgroundJob/CleanupDirectEditingTokens.php @@ -0,0 +1,31 @@ +<?php + +namespace OCA\Files\BackgroundJob; + +use OC\BackgroundJob\TimedJob; +use OCP\DirectEditing\IManager; + +class CleanupDirectEditingTokens extends TimedJob { + + private const INTERVAL_MINUTES = 15 * 60; + + /** + * @var IManager + */ + private $manager; + + public function __construct(IManager $manager) { + $this->interval = self::INTERVAL_MINUTES; + $this->manager = $manager; + } + + /** + * Makes the background job do its work + * + * @param array $argument unused argument + * @throws \Exception + */ + public function run($argument) { + $this->manager->cleanup(); + } +} diff --git a/apps/files/lib/BackgroundJob/TransferOwnership.php b/apps/files/lib/BackgroundJob/TransferOwnership.php new file mode 100644 index 00000000000..3e505cb19bf --- /dev/null +++ b/apps/files/lib/BackgroundJob/TransferOwnership.php @@ -0,0 +1,183 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\BackgroundJob; + +use OCA\Files\AppInfo\Application; +use OCA\Files\Db\TransferOwnership as Transfer; +use OCA\Files\Db\TransferOwnershipMapper; +use OCA\Files\Exception\TransferOwnershipException; +use OCA\Files\Service\OwnershipTransferService; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob; +use OCP\Files\IRootFolder; +use OCP\ILogger; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Notification\IManager as NotificationManager; +use function ltrim; + +class TransferOwnership extends QueuedJob { + + /** @var IUserManager $userManager */ + private $userManager; + + /** @var OwnershipTransferService */ + private $transferService; + + /** @var ILogger */ + private $logger; + + /** @var NotificationManager */ + private $notificationManager; + + /** @var TransferOwnershipMapper */ + private $mapper; + /** @var IRootFolder */ + private $rootFolder; + + public function __construct(ITimeFactory $timeFactory, + IUserManager $userManager, + OwnershipTransferService $transferService, + ILogger $logger, + NotificationManager $notificationManager, + TransferOwnershipMapper $mapper, + IRootFolder $rootFolder) { + parent::__construct($timeFactory); + + $this->userManager = $userManager; + $this->transferService = $transferService; + $this->logger = $logger; + $this->notificationManager = $notificationManager; + $this->mapper = $mapper; + $this->rootFolder = $rootFolder; + } + + protected function run($argument) { + $id = $argument['id']; + + $transfer = $this->mapper->getById($id); + $sourceUser = $transfer->getSourceUser(); + $destinationUser = $transfer->getTargetUser(); + $fileId = $transfer->getFileId(); + + $userFolder = $this->rootFolder->getUserFolder($sourceUser); + $nodes = $userFolder->getById($fileId); + + if (empty($nodes)) { + $this->logger->alert('Could not transfer ownership: Node not found'); + $this->failedNotication($transfer); + return; + } + $path = $userFolder->getRelativePath($nodes[0]->getPath()); + + $sourceUserObject = $this->userManager->get($sourceUser); + $destinationUserObject = $this->userManager->get($destinationUser); + + if (!$sourceUserObject instanceof IUser) { + $this->logger->alert('Could not transfer ownership: Unknown source user ' . $sourceUser); + $this->failedNotication($transfer); + return; + } + + if (!$destinationUserObject instanceof IUser) { + $this->logger->alert("Unknown destination user $destinationUser"); + $this->failedNotication($transfer); + return; + } + + try { + $this->transferService->transfer( + $sourceUserObject, + $destinationUserObject, + ltrim($path, '/') + ); + $this->successNotification($transfer); + } catch (TransferOwnershipException $e) { + $this->logger->logException($e); + $this->failedNotication($transfer); + } + + $this->mapper->delete($transfer); + + } + + private function failedNotication(Transfer $transfer): void { + // Send notification to source user + $notification = $this->notificationManager->createNotification(); + $notification->setUser($transfer->getSourceUser()) + ->setApp(Application::APP_ID) + ->setDateTime($this->time->getDateTime()) + ->setSubject('transferOwnershipFailedSource', [ + 'sourceUser' => $transfer->getSourceUser(), + 'targetUser' => $transfer->getTargetUser(), + 'nodeName' => $transfer->getNodeName(), + ]) + ->setObject('transfer', (string)$transfer->getId()); + $this->notificationManager->notify($notification); + + // Send notification to source user + $notification = $this->notificationManager->createNotification(); + $notification->setUser($transfer->getTargetUser()) + ->setApp(Application::APP_ID) + ->setDateTime($this->time->getDateTime()) + ->setSubject('transferOwnershipFailedTarget', [ + 'sourceUser' => $transfer->getSourceUser(), + 'targetUser' => $transfer->getTargetUser(), + 'nodeName' => $transfer->getNodeName(), + ]) + ->setObject('transfer', (string)$transfer->getId()); + $this->notificationManager->notify($notification); + } + + private function successNotification(Transfer $transfer): void { + // Send notification to source user + $notification = $this->notificationManager->createNotification(); + $notification->setUser($transfer->getSourceUser()) + ->setApp(Application::APP_ID) + ->setDateTime($this->time->getDateTime()) + ->setSubject('transferOwnershipDoneSource', [ + 'sourceUser' => $transfer->getSourceUser(), + 'targetUser' => $transfer->getTargetUser(), + 'nodeName' => $transfer->getNodeName(), + ]) + ->setObject('transfer', (string)$transfer->getId()); + $this->notificationManager->notify($notification); + + // Send notification to source user + $notification = $this->notificationManager->createNotification(); + $notification->setUser($transfer->getTargetUser()) + ->setApp(Application::APP_ID) + ->setDateTime($this->time->getDateTime()) + ->setSubject('transferOwnershipDoneTarget', [ + 'sourceUser' => $transfer->getSourceUser(), + 'targetUser' => $transfer->getTargetUser(), + 'nodeName' => $transfer->getNodeName(), + ]) + ->setObject('transfer', (string)$transfer->getId()); + $this->notificationManager->notify($notification); + } +} diff --git a/apps/files/lib/Capabilities.php b/apps/files/lib/Capabilities.php index 2b6bf57b90d..20ef0c4d229 100644 --- a/apps/files/lib/Capabilities.php +++ b/apps/files/lib/Capabilities.php @@ -25,8 +25,16 @@ namespace OCA\Files; +use OC\DirectEditing\Manager; +use OCA\Files\Service\DirectEditingService; use OCP\Capabilities\ICapability; +use OCP\DirectEditing\ACreateEmpty; +use OCP\DirectEditing\ACreateFromTemplate; +use OCP\DirectEditing\IEditor; +use OCP\DirectEditing\RegisterDirectEditorEvent; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; +use OCP\IURLGenerator; /** * Class Capabilities @@ -34,16 +42,25 @@ use OCP\IConfig; * @package OCA\Files */ class Capabilities implements ICapability { + /** @var IConfig */ protected $config; + /** @var DirectEditingService */ + protected $directEditingService; + + /** @var IURLGenerator */ + private $urlGenerator; + /** * Capabilities constructor. * * @param IConfig $config */ - public function __construct(IConfig $config) { + public function __construct(IConfig $config, DirectEditingService $directEditingService, IURLGenerator $urlGenerator) { $this->config = $config; + $this->directEditingService = $directEditingService; + $this->urlGenerator = $urlGenerator; } /** @@ -56,7 +73,13 @@ class Capabilities implements ICapability { 'files' => [ 'bigfilechunking' => true, 'blacklisted_files' => $this->config->getSystemValue('blacklisted_files', ['.htaccess']), + 'directEditing' => [ + 'url' => $this->urlGenerator->linkToOCSRouteAbsolute('files.DirectEditing.info'), + 'etag' => $this->directEditingService->getDirectEditingETag() + ] ], ]; } + + } diff --git a/apps/files/lib/Controller/DirectEditingController.php b/apps/files/lib/Controller/DirectEditingController.php new file mode 100644 index 00000000000..0a086c3da60 --- /dev/null +++ b/apps/files/lib/Controller/DirectEditingController.php @@ -0,0 +1,128 @@ +<?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\Files\Controller; + + +use Exception; +use OCA\Files\Service\DirectEditingService; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; +use OCP\DirectEditing\ACreateEmpty; +use OCP\DirectEditing\ACreateFromTemplate; +use OCP\DirectEditing\IEditor; +use OCP\DirectEditing\IManager; +use OCP\DirectEditing\RegisterDirectEditorEvent; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use OCP\IRequest; +use OCP\IURLGenerator; + +class DirectEditingController extends OCSController { + + /** @var IEventDispatcher */ + private $eventDispatcher; + + /** @var IManager */ + private $directEditingManager; + + /** @var IURLGenerator */ + private $urlGenerator; + + /** @var ILogger */ + private $logger; + + /** @var DirectEditingService */ + private $directEditingService; + + public function __construct($appName, IRequest $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge, + IEventDispatcher $eventDispatcher, IURLGenerator $urlGenerator, IManager $manager, DirectEditingService $directEditingService, ILogger $logger) { + parent::__construct($appName, $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge); + + $this->eventDispatcher = $eventDispatcher; + $this->directEditingManager = $manager; + $this->directEditingService = $directEditingService; + $this->logger = $logger; + $this->urlGenerator = $urlGenerator; + } + + /** + * @NoAdminRequired + */ + public function info(): DataResponse { + $response = new DataResponse($this->directEditingService->getDirectEditingCapabilitites()); + $response->setETag($this->directEditingService->getDirectEditingETag()); + return $response; + } + + /** + * @NoAdminRequired + */ + public function create(string $path, string $editorId, string $creatorId, string $templateId = null): DataResponse { + $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager)); + + try { + $token = $this->directEditingManager->create($path, $editorId, $creatorId, $templateId); + return new DataResponse([ + 'url' => $this->urlGenerator->linkToRouteAbsolute('files.DirectEditingView.edit', ['token' => $token]) + ]); + } catch (Exception $e) { + $this->logger->logException($e, ['message' => 'Exception when creating a new file through direct editing']); + return new DataResponse('Failed to create file', Http::STATUS_FORBIDDEN); + } + } + + /** + * @NoAdminRequired + */ + public function open(int $fileId, string $editorId = null): DataResponse { + $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager)); + + try { + $token = $this->directEditingManager->open($fileId, $editorId); + return new DataResponse([ + 'url' => $this->urlGenerator->linkToRouteAbsolute('files.DirectEditingView.edit', ['token' => $token]) + ]); + } catch (Exception $e) { + $this->logger->logException($e, ['message' => 'Exception when opening a file through direct editing']); + return new DataResponse('Failed to open file', Http::STATUS_FORBIDDEN); + } + } + + + + /** + * @NoAdminRequired + */ + public function templates(string $editorId, string $creatorId): DataResponse { + $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager)); + + try { + return new DataResponse($this->directEditingManager->getTemplates($editorId, $creatorId)); + } catch (Exception $e) { + $this->logger->logException($e); + return new DataResponse('Failed to open file', Http::STATUS_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/apps/files/lib/Controller/DirectEditingViewController.php b/apps/files/lib/Controller/DirectEditingViewController.php new file mode 100644 index 00000000000..9fbce4ece12 --- /dev/null +++ b/apps/files/lib/Controller/DirectEditingViewController.php @@ -0,0 +1,72 @@ +<?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\Files\Controller; + + +use Exception; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\AppFramework\Http\Response; +use OCP\DirectEditing\IManager; +use OCP\DirectEditing\RegisterDirectEditorEvent; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use OCP\IRequest; + +class DirectEditingViewController extends Controller { + + /** @var IEventDispatcher */ + private $eventDispatcher; + + /** @var IManager */ + private $directEditingManager; + + /** @var ILogger */ + private $logger; + + public function __construct($appName, IRequest $request, IEventDispatcher $eventDispatcher, IManager $manager, ILogger $logger) { + parent::__construct($appName, $request); + + $this->eventDispatcher = $eventDispatcher; + $this->directEditingManager = $manager; + $this->logger = $logger; + } + + /** + * @PublicPage + * @NoCSRFRequired + * + * @param string $token + * @return Response + */ + public function edit(string $token): Response { + $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager)); + try { + return $this->directEditingManager->edit($token); + } catch (Exception $e) { + $this->logger->logException($e); + return new NotFoundResponse(); + } + } +} diff --git a/apps/files/lib/Controller/TransferOwnershipController.php b/apps/files/lib/Controller/TransferOwnershipController.php new file mode 100644 index 00000000000..b01596fc29d --- /dev/null +++ b/apps/files/lib/Controller/TransferOwnershipController.php @@ -0,0 +1,181 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\Controller; + +use OCA\Files\BackgroundJob\TransferOwnership; +use OCA\Files\Db\TransferOwnershipMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\Files\IRootFolder; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\Notification\IManager as NotificationManager; + +class TransferOwnershipController extends OCSController { + + /** @var string */ + private $userId; + /** @var NotificationManager */ + private $notificationManager; + /** @var ITimeFactory */ + private $timeFactory; + /** @var IJobList */ + private $jobList; + /** @var TransferOwnershipMapper */ + private $mapper; + /** @var IUserManager */ + private $userManager; + /** @var IRootFolder */ + private $rootFolder; + + public function __construct(string $appName, + IRequest $request, + string $userId, + NotificationManager $notificationManager, + ITimeFactory $timeFactory, + IJobList $jobList, + TransferOwnershipMapper $mapper, + IUserManager $userManager, + IRootFolder $rootFolder) { + parent::__construct($appName, $request); + + $this->userId = $userId; + $this->notificationManager = $notificationManager; + $this->timeFactory = $timeFactory; + $this->jobList = $jobList; + $this->mapper = $mapper; + $this->userManager = $userManager; + $this->rootFolder = $rootFolder; + } + + + /** + * @NoAdminRequired + */ + public function transfer(string $recipient, string $path): DataResponse { + $recipientUser = $this->userManager->get($recipient); + + if ($recipientUser === null) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + $userRoot = $this->rootFolder->getUserFolder($this->userId); + + try { + $node = $userRoot->get($path); + } catch (\Exception $e) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + $transferOwnership = new \OCA\Files\Db\TransferOwnership(); + $transferOwnership->setSourceUser($this->userId); + $transferOwnership->setTargetUser($recipient); + $transferOwnership->setFileId($node->getId()); + $transferOwnership->setNodeName($node->getName()); + $transferOwnership = $this->mapper->insert($transferOwnership); + + $notification = $this->notificationManager->createNotification(); + $notification->setUser($recipient) + ->setApp($this->appName) + ->setDateTime($this->timeFactory->getDateTime()) + ->setSubject('transferownershipRequest', [ + 'sourceUser' => $this->userId, + 'targetUser' => $recipient, + 'nodeName' => $node->getName(), + ]) + ->setObject('transfer', (string)$transferOwnership->getId()); + + $this->notificationManager->notify($notification); + + return new DataResponse([]); + } + + /** + * @NoAdminRequired + */ + public function accept(int $id): DataResponse { + try { + $transferOwnership = $this->mapper->getById($id); + } catch (DoesNotExistException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + if ($transferOwnership->getTargetUser() !== $this->userId) { + return new DataResponse([], Http::STATUS_FORBIDDEN); + } + + $this->jobList->add(TransferOwnership::class, [ + 'id' => $transferOwnership->getId(), + ]); + + $notification = $this->notificationManager->createNotification(); + $notification->setApp('files') + ->setObject('transfer', (string)$id); + $this->notificationManager->markProcessed($notification); + + return new DataResponse([], Http::STATUS_OK); + } + + /** + * @NoAdminRequired + */ + public function reject(int $id): DataResponse { + try { + $transferOwnership = $this->mapper->getById($id); + } catch (DoesNotExistException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + if ($transferOwnership->getTargetUser() !== $this->userId) { + return new DataResponse([], Http::STATUS_FORBIDDEN); + } + + $notification = $this->notificationManager->createNotification(); + $notification->setApp('files') + ->setObject('transfer', (string)$id); + $this->notificationManager->markProcessed($notification); + + $notification = $this->notificationManager->createNotification(); + $notification->setUser($transferOwnership->getSourceUser()) + ->setApp($this->appName) + ->setDateTime($this->timeFactory->getDateTime()) + ->setSubject('transferownershipRequestDenied', [ + 'sourceUser' => $transferOwnership->getSourceUser(), + 'targetUser' => $transferOwnership->getTargetUser(), + 'nodeName' => $transferOwnership->getNodeName() + ]) + ->setObject('transfer', (string)$transferOwnership->getId()); + $this->notificationManager->notify($notification); + + $this->mapper->delete($transferOwnership); + + return new DataResponse([], Http::STATUS_OK); + } + +} diff --git a/apps/files/lib/Db/TransferOwnership.php b/apps/files/lib/Db/TransferOwnership.php new file mode 100644 index 00000000000..34384991354 --- /dev/null +++ b/apps/files/lib/Db/TransferOwnership.php @@ -0,0 +1,60 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\Db; + +use OCP\AppFramework\Db\Entity; + +/** + * @method void setSourceUser(string $uid) + * @method string getSourceUser() + * @method void setTargetUser(string $uid) + * @method string getTargetUser() + * @method void setFileId(int $fileId) + * @method int getFileId() + * @method void setNodeName(string $name) + * @method string getNodeName() + */ +class TransferOwnership extends Entity { + /** @var string */ + protected $sourceUser; + + /** @var string */ + protected $targetUser; + + /** @var integer */ + protected $fileId; + + /** @var string */ + protected $nodeName; + + public function __construct() { + $this->addType('sourceUser', 'string'); + $this->addType('targetUser', 'string'); + $this->addType('fileId', 'integer'); + $this->addType('nodeName', 'string'); + } + + +} diff --git a/apps/files/lib/Db/TransferOwnershipMapper.php b/apps/files/lib/Db/TransferOwnershipMapper.php new file mode 100644 index 00000000000..4918d4cdbf7 --- /dev/null +++ b/apps/files/lib/Db/TransferOwnershipMapper.php @@ -0,0 +1,47 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\Db; + +use OCP\AppFramework\Db\QBMapper; +use OCP\IDBConnection; + +class TransferOwnershipMapper extends QBMapper { + public function __construct(IDBConnection $db) { + parent::__construct($db, 'user_transfer_ownership', TransferOwnership::class); + } + + public function getById(int $id): TransferOwnership { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('id', $qb->createNamedParameter($id)) + ); + + return $this->findEntity($qb); + } + +} diff --git a/apps/files/lib/Migration/Version11301Date20191113195931.php b/apps/files/lib/Migration/Version11301Date20191113195931.php new file mode 100644 index 00000000000..d4044434c76 --- /dev/null +++ b/apps/files/lib/Migration/Version11301Date20191113195931.php @@ -0,0 +1,72 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +class Version11301Date20191113195931 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->createTable('user_transfer_ownership'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('source_user', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('target_user', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('file_id', 'bigint', [ + 'notnull' => true, + 'length' => 20, + ]); + $table->addColumn('node_name', 'string', [ + 'notnull' => true, + 'length' => 255, + ]); + $table->setPrimaryKey(['id']); + + return $schema; + } + +} diff --git a/apps/files/lib/Notification/Notifier.php b/apps/files/lib/Notification/Notifier.php new file mode 100644 index 00000000000..2de05cac2e1 --- /dev/null +++ b/apps/files/lib/Notification/Notifier.php @@ -0,0 +1,247 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Files\Notification; + +use OCP\IURLGenerator; +use OCP\L10N\IFactory; +use OCP\Notification\IAction; +use OCP\Notification\INotification; +use OCP\Notification\INotifier; + +class Notifier implements INotifier { + + /** @var IFactory */ + protected $l10nFactory; + + /** @var IURLGenerator */ + protected $urlGenerator; + + /** + * @param IFactory $l10nFactory + * @param IURLGenerator $urlGenerator + */ + public function __construct(IFactory $l10nFactory, IURLGenerator $urlGenerator) { + $this->l10nFactory = $l10nFactory; + $this->urlGenerator = $urlGenerator; + } + + public function getID(): string { + return 'files'; + } + + public function getName(): string { + return $this->l10nFactory->get('files')->t('Files'); + } + + /** + * @param INotification $notification + * @param string $languageCode The code of the language that should be used to prepare the notification + * @return INotification + * @throws \InvalidArgumentException When the notification was not prepared by a notifier + */ + public function prepare(INotification $notification, string $languageCode): INotification { + if ($notification->getApp() !== 'files') { + throw new \InvalidArgumentException('Unhandled app'); + } + + if ($notification->getSubject() === 'transferownershipRequest') { + return $this->handleTransferownershipRequest($notification, $languageCode); + } + if ($notification->getSubject() === 'transferOwnershipFailedSource') { + return $this->handleTransferOwnershipFailedSource($notification, $languageCode); + } + if ($notification->getSubject() === 'transferOwnershipFailedTarget') { + return $this->handleTransferOwnershipFailedTarget($notification, $languageCode); + } + if ($notification->getSubject() === 'transferOwnershipDoneSource') { + return $this->handleTransferOwnershipDoneSource($notification, $languageCode); + } + if ($notification->getSubject() === 'transferOwnershipDoneTarget') { + return $this->handleTransferOwnershipDoneTarget($notification, $languageCode); + } + + throw new \InvalidArgumentException('Unhandled subject'); + } + + public function handleTransferownershipRequest(INotification $notification, string $languageCode): INotification { + $l = $this->l10nFactory->get('files', $languageCode); + $id = $notification->getObjectId(); + $param = $notification->getSubjectParameters(); + + $approveAction = $notification->createAction() + ->setParsedLabel($l->t('Accept')) + ->setPrimary(true) + ->setLink( + $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkTo( + '', + 'ocs/v2.php/apps/files/api/v1/transferownership/' . $id + ) + ), + IAction::TYPE_POST + ); + + $disapproveAction = $notification->createAction() + ->setParsedLabel($l->t('Decline')) + ->setPrimary(false) + ->setLink( + $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkTo( + '', + 'ocs/v2.php/apps/files/api/v1/transferownership/' . $id + ) + ), + IAction::TYPE_DELETE + ); + + $notification->addParsedAction($approveAction) + ->addParsedAction($disapproveAction) + ->setRichSubject( + $l->t('Incoming file transfer from {user}'), + [ + 'user' => [ + 'type' => 'user', + 'id' => $param['sourceUser'], + 'name' => $param['sourceUser'], + ], + ]) + ->setParsedSubject(str_replace('{user}', $param['sourceUser'], $l->t('Incoming file transfer from {user}'))) + ->setRichMessage( + $l->t('Do you want to accept {path}?'), + [ + 'path' => [ + 'type' => 'highlight', + 'id' => $param['targetUser'] . '::' . $param['nodeName'], + 'name' => $param['nodeName'], + ] + ]) + ->setParsedMessage(str_replace('{path}', $param['nodeName'], $l->t('Do you want to accept {path}?'))); + + return $notification; + } + + public function handleTransferOwnershipFailedSource(INotification $notification, string $languageCode): INotification { + $l = $this->l10nFactory->get('files', $languageCode); + $param = $notification->getSubjectParameters(); + + $notification->setRichSubject($l->t('File transfer failed')) + ->setParsedSubject($l->t('File transfer failed')) + + ->setRichMessage( + $l->t('Your transfer of {path} to {user} failed.'), + [ + 'path' => [ + 'type' => 'highlight', + 'id' => $param['targetUser'] . '::' . $param['nodeName'], + 'name' => $param['nodeName'], + ], + 'user' => [ + 'type' => 'user', + 'id' => $param['targetUser'], + 'name' => $param['targetUser'], + ], + ]) + ->setParsedMessage(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['targetUser']], $l->t('Your transfer of {path} to {user} failed.'))); + return $notification; + } + + public function handleTransferOwnershipFailedTarget(INotification $notification, string $languageCode): INotification { + $l = $this->l10nFactory->get('files', $languageCode); + $param = $notification->getSubjectParameters(); + + $notification->setRichSubject($l->t('File transfer failed')) + ->setParsedSubject($l->t('File transfer failed')) + + ->setRichMessage( + $l->t('The transfer of {path} from {user} failed.'), + [ + 'path' => [ + 'type' => 'highlight', + 'id' => $param['sourceUser'] . '::' . $param['nodeName'], + 'name' => $param['nodeName'], + ], + 'user' => [ + 'type' => 'user', + 'id' => $param['sourceUser'], + 'name' => $param['sourceUser'], + ], + ]) + ->setParsedMessage(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['sourceUser']], $l->t('The transfer of {path} from {user} failed.'))); + + return $notification; + } + + public function handleTransferOwnershipDoneSource(INotification $notification, string $languageCode): INotification { + $l = $this->l10nFactory->get('files', $languageCode); + $param = $notification->getSubjectParameters(); + + $notification->setRichSubject($l->t('File transfer done')) + ->setParsedSubject($l->t('File transfer done')) + + ->setRichMessage( + $l->t('Your transfer of {path} to {user} has completed.'), + [ + 'path' => [ + 'type' => 'highlight', + 'id' => $param['targetUser'] . '::' . $param['nodeName'], + 'name' => $param['nodeName'], + ], + 'user' => [ + 'type' => 'user', + 'id' => $param['targetUser'], + 'name' => $param['targetUser'], + ], + ]) + ->setParsedMessage(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['targetUser']], $l->t('Your transfer of {path} to {user} has completed.'))); + + return $notification; + } + + public function handleTransferOwnershipDoneTarget(INotification $notification, string $languageCode): INotification { + $l = $this->l10nFactory->get('files', $languageCode); + $param = $notification->getSubjectParameters(); + + $notification->setRichSubject($l->t('File transfer done')) + ->setParsedSubject($l->t('File transfer done')) + + ->setRichMessage( + $l->t('The transfer of {path} from {user} has completed.'), + [ + 'path' => [ + 'type' => 'highlight', + 'id' => $param['sourceUser'] . '::' . $param['nodeName'], + 'name' => $param['nodeName'], + ], + 'user' => [ + 'type' => 'user', + 'id' => $param['sourceUser'], + 'name' => $param['sourceUser'], + ], + ]) + ->setParsedMessage(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['sourceUser']], $l->t('The transfer of {path} from {user} has completed.'))); + + return $notification; + } +} diff --git a/apps/files/lib/Service/DirectEditingService.php b/apps/files/lib/Service/DirectEditingService.php new file mode 100644 index 00000000000..7e906238d87 --- /dev/null +++ b/apps/files/lib/Service/DirectEditingService.php @@ -0,0 +1,85 @@ +<?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\Files\Service; + + +use OCP\DirectEditing\ACreateEmpty; +use OCP\DirectEditing\ACreateFromTemplate; +use OCP\DirectEditing\IEditor; +use OCP\DirectEditing\IManager; +use OCP\DirectEditing\RegisterDirectEditorEvent; +use OCP\EventDispatcher\IEventDispatcher; + +class DirectEditingService { + + /** @var IManager */ + private $directEditingManager; + /** @var IEventDispatcher */ + private $eventDispatcher; + + public function __construct(IEventDispatcher $eventDispatcher, IManager $directEditingManager) { + $this->directEditingManager = $directEditingManager; + $this->eventDispatcher = $eventDispatcher; + } + + public function getDirectEditingETag(): string { + return \md5(\json_encode($this->getDirectEditingCapabilitites())); + } + + public function getDirectEditingCapabilitites(): array { + $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager)); + + $capabilities = [ + 'editors' => [], + 'creators' => [] + ]; + + /** + * @var string $id + * @var IEditor $editor + */ + foreach ($this->directEditingManager->getEditors() as $id => $editor) { + $capabilities['editors'][$id] = [ + 'name' => $editor->getName(), + 'mimetypes' => $editor->getMimetypes(), + 'optionalMimetypes' => $editor->getMimetypesOptional(), + 'secure' => $editor->isSecure(), + ]; + /** @var ACreateEmpty|ACreateFromTemplate $creator */ + foreach ($editor->getCreators() as $creator) { + $id = $creator->getId(); + $capabilities['creators'][$id] = [ + 'id' => $id, + 'editor' => $editor->getId(), + 'name' => $creator->getName(), + 'extension' => $creator->getExtension(), + 'templates' => $creator instanceof ACreateFromTemplate, + 'mimetype' => $creator->getMimetype() + ]; + } + } + return $capabilities; + } + +} diff --git a/apps/files/lib/Service/OwnershipTransferService.php b/apps/files/lib/Service/OwnershipTransferService.php index 0c5c25237b9..d664163041f 100644 --- a/apps/files/lib/Service/OwnershipTransferService.php +++ b/apps/files/lib/Service/OwnershipTransferService.php @@ -91,7 +91,7 @@ class OwnershipTransferService { Filesystem::initMountPoints($destinationUid); $view = new View(); - if (!$view->is_dir($sourcePath)) { + if (!($view->is_dir($sourcePath) || $view->is_file($sourcePath))) { throw new TransferOwnershipException("Unknown path provided: $path", 1); } diff --git a/apps/files/lib/Settings/PersonalSettings.php b/apps/files/lib/Settings/PersonalSettings.php new file mode 100644 index 00000000000..3348d394dc5 --- /dev/null +++ b/apps/files/lib/Settings/PersonalSettings.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Files\Settings; + +use OCA\Files\AppInfo\Application; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\Settings\ISettings; + +class PersonalSettings implements ISettings { + + public function getForm(): TemplateResponse { + return new TemplateResponse(Application::APP_ID, 'settings-personal'); + } + + public function getSection(): string { + return 'sharing'; + } + + public function getPriority(): int { + return 90; + } + +} |