diff --git a/appinfo/routes.php b/appinfo/routes.php index 056e37b4b3..86e0ea3c71 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -94,5 +94,7 @@ ['name' => 'Target#getTargets', 'url' => '/api/v1/targets', 'verb' => 'GET'], ['name' => 'Target#getPreview', 'url' => '/api/v1/targets/preview', 'verb' => 'GET'], + + ['name' => 'Mention#mention', 'url' => '/api/v1/mention/{fileId}', 'verb' => 'POST'], ], ]; diff --git a/composer/composer/autoload_classmap.php b/composer/composer/autoload_classmap.php index 2aa64bd592..7ec7e01a2a 100644 --- a/composer/composer/autoload_classmap.php +++ b/composer/composer/autoload_classmap.php @@ -21,6 +21,7 @@ 'OCA\\Richdocuments\\Controller\\DocumentController' => $baseDir . '/../lib/Controller/DocumentController.php', 'OCA\\Richdocuments\\Controller\\DocumentTrait' => $baseDir . '/../lib/Controller/DocumentTrait.php', 'OCA\\Richdocuments\\Controller\\FederationController' => $baseDir . '/../lib/Controller/FederationController.php', + 'OCA\\Richdocuments\\Controller\\MentionController' => $baseDir . '/../lib/Controller/MentionController.php', 'OCA\\Richdocuments\\Controller\\OCSController' => $baseDir . '/../lib/Controller/OCSController.php', 'OCA\\Richdocuments\\Controller\\SettingsController' => $baseDir . '/../lib/Controller/SettingsController.php', 'OCA\\Richdocuments\\Controller\\TargetController' => $baseDir . '/../lib/Controller/TargetController.php', @@ -51,6 +52,7 @@ 'OCA\\Richdocuments\\Migration\\Version30709Date20201111104147' => $baseDir . '/../lib/Migration/Version30709Date20201111104147.php', 'OCA\\Richdocuments\\Migration\\Version30717Date20210310164901' => $baseDir . '/../lib/Migration/Version30717Date20210310164901.php', 'OCA\\Richdocuments\\Migration\\Version50200Date20211220212457' => $baseDir . '/../lib/Migration/Version50200Date20211220212457.php', + 'OCA\\Richdocuments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php', 'OCA\\Richdocuments\\PermissionManager' => $baseDir . '/../lib/PermissionManager.php', 'OCA\\Richdocuments\\Preview\\MSExcel' => $baseDir . '/../lib/Preview/MSExcel.php', 'OCA\\Richdocuments\\Preview\\MSWord' => $baseDir . '/../lib/Preview/MSWord.php', diff --git a/composer/composer/autoload_static.php b/composer/composer/autoload_static.php index 7a0f9877b8..a3ffe242e3 100644 --- a/composer/composer/autoload_static.php +++ b/composer/composer/autoload_static.php @@ -36,6 +36,7 @@ class ComposerStaticInitRichdocuments 'OCA\\Richdocuments\\Controller\\DocumentController' => __DIR__ . '/..' . '/../lib/Controller/DocumentController.php', 'OCA\\Richdocuments\\Controller\\DocumentTrait' => __DIR__ . '/..' . '/../lib/Controller/DocumentTrait.php', 'OCA\\Richdocuments\\Controller\\FederationController' => __DIR__ . '/..' . '/../lib/Controller/FederationController.php', + 'OCA\\Richdocuments\\Controller\\MentionController' => __DIR__ . '/..' . '/../lib/Controller/MentionController.php', 'OCA\\Richdocuments\\Controller\\OCSController' => __DIR__ . '/..' . '/../lib/Controller/OCSController.php', 'OCA\\Richdocuments\\Controller\\SettingsController' => __DIR__ . '/..' . '/../lib/Controller/SettingsController.php', 'OCA\\Richdocuments\\Controller\\TargetController' => __DIR__ . '/..' . '/../lib/Controller/TargetController.php', @@ -66,6 +67,7 @@ class ComposerStaticInitRichdocuments 'OCA\\Richdocuments\\Migration\\Version30709Date20201111104147' => __DIR__ . '/..' . '/../lib/Migration/Version30709Date20201111104147.php', 'OCA\\Richdocuments\\Migration\\Version30717Date20210310164901' => __DIR__ . '/..' . '/../lib/Migration/Version30717Date20210310164901.php', 'OCA\\Richdocuments\\Migration\\Version50200Date20211220212457' => __DIR__ . '/..' . '/../lib/Migration/Version50200Date20211220212457.php', + 'OCA\\Richdocuments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php', 'OCA\\Richdocuments\\PermissionManager' => __DIR__ . '/..' . '/../lib/PermissionManager.php', 'OCA\\Richdocuments\\Preview\\MSExcel' => __DIR__ . '/..' . '/../lib/Preview/MSExcel.php', 'OCA\\Richdocuments\\Preview\\MSWord' => __DIR__ . '/..' . '/../lib/Preview/MSWord.php', diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 5b43f4467c..7d677efc2d 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -36,6 +36,7 @@ use OCA\Richdocuments\Listener\ReferenceListener; use OCA\Richdocuments\Listener\ShareLinkListener; use OCA\Richdocuments\Middleware\WOPIMiddleware; +use OCA\Richdocuments\Notification\Notifier; use OCA\Richdocuments\PermissionManager; use OCA\Richdocuments\Preview\MSExcel; use OCA\Richdocuments\Preview\MSWord; @@ -86,6 +87,8 @@ public function register(IRegistrationContext $context): void { 'getPathForToken', 'getWopiForToken', ]); + + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { diff --git a/lib/Controller/MentionController.php b/lib/Controller/MentionController.php new file mode 100644 index 0000000000..3269acc76d --- /dev/null +++ b/lib/Controller/MentionController.php @@ -0,0 +1,66 @@ +rootFolder->getUserFolder($this->userId); + $file = $userFolder->getById($fileId)[0]; + if ($file === null) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + $userFolder = $this->rootFolder->getUserFolder($mention); + $file = $userFolder->getById($fileId)[0]; + if ($file === null) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + $notification = $this->manager->createNotification(); + $notification->setUser($mention) + ->setApp(Application::APPNAME) + ->setSubject(Notifier::TYPE_MENTIONED, [ + Notifier::SUBJECT_MENTIONED_SOURCE_USER => $this->userId, + Notifier::SUBJECT_MENTIONED_TARGET_USER => $mention, + ]) + ->setObject('file', (string)$fileId); + + if ($this->manager->getCount($notification) === 0) { + $notification->setDateTime(\DateTime::createFromImmutable($this->timeFactory->now())); + $this->manager->notify($notification); + return new DataResponse([], Http::STATUS_OK); + + } + + return new DataResponse([], Http::STATUS_NOT_FOUND); + } +} diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php new file mode 100644 index 0000000000..3294e71ce6 --- /dev/null +++ b/lib/Notification/Notifier.php @@ -0,0 +1,112 @@ +getApp() !== Application::APPNAME) { + throw new InvalidArgumentException('Application should be text instead of ' . $notification->getApp()); + } + + $l = $this->factory->get(Application::APPNAME, $languageCode); + + switch ($notification->getSubject()) { + case self::TYPE_MENTIONED: + $parameters = $notification->getSubjectParameters(); + $sourceUser = $parameters[self::SUBJECT_MENTIONED_SOURCE_USER]; + $sourceUserDisplayName = $this->userManager->getDisplayName($sourceUser); + $targetUser = $notification->getUser(); + $fileId = (int)$notification->getObjectId(); + + if ($sourceUserDisplayName === null) { + throw new InvalidArgumentException(); + } + + try { + $userFolder = $this->rootFolder->getUserFolder($targetUser); + } catch (NotPermittedException|NoUserException $e) { + throw new InvalidArgumentException(); + } + $node = $userFolder->getById($fileId)[0]; + + if ($node === null) { + throw new InvalidArgumentException(); + } + + $fileLink = $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $node->getId()]); + + $notification->setRichSubject($l->t('{user} has mentioned you in {node}'), [ + 'user' => [ + 'type' => 'user', + 'id' => $sourceUser, + 'name' => $sourceUserDisplayName, + ], + 'node' => [ + 'type' => 'file', + 'id' => (string)$node->getId(), + 'name' => $node->getName(), + 'path' => $userFolder->getRelativePath($node->getPath()) ?? '', + 'link' => $fileLink, + ], + ]); + break; + default: + throw new InvalidArgumentException(); + } + $notification->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('text', 'app-dark.svg'))); + $notification->setLink($fileLink); + $this->setParsedSubjectFromRichSubject($notification); + return $notification; + } + + protected function setParsedSubjectFromRichSubject(INotification $notification): void { + $placeholders = $replacements = []; + foreach ($notification->getRichSubjectParameters() as $placeholder => $parameter) { + $placeholders[] = '{' . $placeholder . '}'; + if ($parameter['type'] === 'file') { + $replacements[] = $parameter['path']; + } else { + $replacements[] = $parameter['name']; + } + } + + $notification->setParsedSubject(str_replace($placeholders, $replacements, $notification->getRichSubject())); + } +} diff --git a/src/mixins/uiMention.js b/src/mixins/uiMention.js index f84b5dab61..1ffb74ca6c 100644 --- a/src/mixins/uiMention.js +++ b/src/mixins/uiMention.js @@ -26,24 +26,33 @@ import { getNextcloudUrl } from '../helpers/url.js' export default { methods: { - async uiMention(search) { - let users = [] + async uiMention({ type, text, username }) { + if (type === 'autocomplete') { + let users = [] - if (Config.get('userId') !== null) { - try { - const result = await axios.get(generateOcsUrl('core/autocomplete/get'), { - params: { search }, - }) - users = result.data.ocs.data - } catch (e) { } - } + if (Config.get('userId') !== null) { + try { + const result = await axios.get(generateOcsUrl('core/autocomplete/get'), { + params: { search: text }, + }) + users = result.data.ocs.data + } catch (e) { + } + } - const list = users.map((user) => { - const profile = window.location.protocol + '//' + getNextcloudUrl() + '/index.php/u/' + user.id - return { username: user.label, profile } - }) + const list = users.map((user) => { + const profile = window.location.protocol + '//' + getNextcloudUrl() + '/index.php/u/' + user.id + return { + username: user.label, + profile, + } + }) - this.sendPostMessage('Action_Mention', { list }) + this.sendPostMessage('Action_Mention', { list }) + } + if (type === 'selected') { + await axios.post(generateOcsUrl(`apps/richdocuments/api/v1/mention/${this.fileid}`), { mention: username }) + } }, }, } diff --git a/src/view/Office.vue b/src/view/Office.vue index 48c48daee5..1fd73ed416 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -405,9 +405,7 @@ export default { }) break case 'UI_Mention': - if (parsed.args.type === 'autocomplete') { - this.uiMention(parsed.args.text) - } + this.uiMention(parsed.args) break case 'UI_CreateFile': FilesAppIntegration.createNewFile(args.DocumentType)