+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Activity;
+
+
+use cogpowered\FineDiff\Diff;
+use OCA\Deck\Db\Acl;
+use OCP\Activity\IEvent;
+use OCP\Activity\IProvider;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\NotFoundException;
+use OCP\IConfig;
+use OCP\IURLGenerator;
+use OCP\IUserManager;
+use OCP\L10N\IFactory;
+
+class DeckProvider implements IProvider {
+
+ /** @var string */
+ private $userId;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+ /** @var ActivityManager */
+ private $activityManager;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var ICommentsManager */
+ private $commentsManager;
+ /** @var IFactory */
+ private $l10nFactory;
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(IURLGenerator $urlGenerator, ActivityManager $activityManager, IUserManager $userManager, ICommentsManager $commentsManager, IFactory $l10n, IConfig $config, $userId) {
+ $this->userId = $userId;
+ $this->urlGenerator = $urlGenerator;
+ $this->activityManager = $activityManager;
+ $this->commentsManager = $commentsManager;
+ $this->userManager = $userManager;
+ $this->l10nFactory = $l10n;
+ $this->config = $config;
+ }
+
+ /**
+ * @param string $language The language which should be used for translating, e.g. "en"
+ * @param IEvent $event The current event which should be parsed
+ * @param IEvent|null $previousEvent A potential previous event which you can combine with the current one.
+ * To do so, simply use setChildEvent($previousEvent) after setting the
+ * combined subject on the current event.
+ * @return IEvent
+ * @throws \InvalidArgumentException Should be thrown if your provider does not know this event
+ * @since 11.0.0
+ */
+ public function parse($language, IEvent $event, IEvent $previousEvent = null) {
+ if ($event->getApp() !== 'deck') {
+ throw new \InvalidArgumentException();
+ }
+
+ $event = $this->getIcon($event);
+
+ $subjectIdentifier = $event->getSubject();
+ $subjectParams = $event->getSubjectParameters();
+ $ownActivity = ($event->getAuthor() === $this->userId);
+
+ /**
+ * Map stored parameter objects to rich string types
+ */
+
+ $author = $event->getAuthor();
+ // get author if
+ if (($author === '' || $author === ActivityManager::DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED) && array_key_exists('author', $subjectParams)) {
+ $author = $subjectParams['author'];
+ unset($subjectParams['author']);
+ }
+ $user = $this->userManager->get($author);
+ if ($user !== null) {
+ $params = [
+ 'user' => [
+ 'type' => 'user',
+ 'id' => $author,
+ 'name' => $user !== null ? $user->getDisplayName() : $author
+ ],
+ ];
+ $event->setAuthor($author);
+ }
+ if ($event->getObjectType() === ActivityManager::DECK_OBJECT_BOARD) {
+ if (isset($subjectParams['board']) && $event->getObjectName() === '') {
+ $event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['board']['title']);
+ }
+ $board = [
+ 'type' => 'highlight',
+ 'id' => $event->getObjectId(),
+ 'name' => $event->getObjectName(),
+ 'link' => $this->deckUrl('/board/' . $event->getObjectId()),
+ ];
+ $params['board'] = $board;
+ }
+
+ if (isset($subjectParams['card']) && $event->getObjectType() === ActivityManager::DECK_OBJECT_CARD) {
+ if ($event->getObjectName() === '') {
+ $event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['card']['title']);
+ }
+ $card = [
+ 'type' => 'highlight',
+ 'id' => $event->getObjectId(),
+ 'name' => $event->getObjectName(),
+ ];
+
+ if (array_key_exists('board', $subjectParams)) {
+ $archivedParam = $subjectParams['card']['archived'] ? 'archived' : '';
+ $card['link'] = $this->deckUrl('/board/' . $subjectParams['board']['id'] . '/' . $archivedParam . '/card/' . $event->getObjectId());
+ }
+ $params['card'] = $card;
+ }
+
+ $params = $this->parseParamForBoard('board', $subjectParams, $params);
+ $params = $this->parseParamForStack('stack', $subjectParams, $params);
+ $params = $this->parseParamForStack('stackBefore', $subjectParams, $params);
+ $params = $this->parseParamForAttachment('attachment', $subjectParams, $params);
+ $params = $this->parseParamForLabel($subjectParams, $params);
+ $params = $this->parseParamForAssignedUser($subjectParams, $params);
+ $params = $this->parseParamForAcl($subjectParams, $params);
+ $params = $this->parseParamForChanges($subjectParams, $params, $event);
+ $params = $this->parseParamForComment($subjectParams, $params, $event);
+ $params = $this->parseParamForDuedate($subjectParams, $params, $event);
+
+ try {
+ $subject = $this->activityManager->getActivityFormat($subjectIdentifier, $subjectParams, $ownActivity);
+ $this->setSubjects($event, $subject, $params);
+ } catch (\Exception $e) {
+ }
+ return $event;
+ }
+
+ /**
+ * @param IEvent $event
+ * @param string $subject
+ * @param array $parameters
+ */
+ protected function setSubjects(IEvent $event, $subject, array $parameters) {
+ $placeholders = $replacements = $richParameters = [];
+ foreach ($parameters as $placeholder => $parameter) {
+ $placeholders[] = '{' . $placeholder . '}';
+ if (is_array($parameter) && array_key_exists('name', $parameter)) {
+ $replacements[] = $parameter['name'];
+ $richParameters[$placeholder] = $parameter;
+ } else {
+ $replacements[] = '';
+ }
+ }
+
+ $event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
+ ->setRichSubject($subject, $richParameters);
+ $event->setSubject($subject, $parameters);
+ }
+
+ private function getIcon(IEvent $event) {
+ $event->setIcon($this->urlGenerator->imagePath('deck', 'deck-dark.svg'));
+ if (strpos($event->getSubject(), '_update') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('files', 'change.svg'));
+ }
+ if (strpos($event->getSubject(), '_create') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('files', 'add-color.svg'));
+ }
+ if (strpos($event->getSubject(), '_delete') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('files', 'delete-color.svg'));
+ }
+ if (strpos($event->getSubject(), 'archive') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('deck', 'archive.svg'));
+ }
+ if (strpos($event->getSubject(), '_restore') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('core', 'actions/history.svg'));
+ }
+ if (strpos($event->getSubject(), 'attachment_') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('core', 'places/files.svg'));
+ }
+ if (strpos($event->getSubject(), 'comment_') !== false) {
+ $event->setIcon($this->urlGenerator->imagePath('core', 'actions/comment.svg'));
+ }
+ return $event;
+ }
+
+ private function parseParamForBoard($paramName, $subjectParams, $params) {
+ if (array_key_exists($paramName, $subjectParams)) {
+ $params[$paramName] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams[$paramName]['id'],
+ 'name' => $subjectParams[$paramName]['title'],
+ 'link' => $this->deckUrl('/board/' . $subjectParams[$paramName]['id'] . '/'),
+ ];
+ }
+ return $params;
+ }
+ private function parseParamForStack($paramName, $subjectParams, $params) {
+ if (array_key_exists($paramName, $subjectParams)) {
+ $params[$paramName] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams[$paramName]['id'],
+ 'name' => $subjectParams[$paramName]['title'],
+ ];
+ }
+ return $params;
+ }
+
+ private function parseParamForAttachment($paramName, $subjectParams, $params) {
+ if (array_key_exists($paramName, $subjectParams)) {
+ $params[$paramName] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams[$paramName]['id'],
+ 'name' => $subjectParams[$paramName]['data'],
+ 'link' => $this->urlGenerator->linkToRoute('deck.attachment.display', ['cardId' => $subjectParams['card']['id'], 'attachmentId' => $subjectParams['attachment']['id']]),
+ ];
+ }
+ return $params;
+ }
+
+ private function parseParamForAssignedUser($subjectParams, $params) {
+ if (array_key_exists('assigneduser', $subjectParams)) {
+ $user = $this->userManager->get($subjectParams['assigneduser']);
+ $params['assigneduser'] = [
+ 'type' => 'user',
+ 'id' => $subjectParams['assigneduser'],
+ 'name' => $user !== null ? $user->getDisplayName() : $subjectParams['assigneduser']
+ ];
+ }
+ return $params;
+ }
+
+ private function parseParamForLabel($subjectParams, $params) {
+ if (array_key_exists('label', $subjectParams)) {
+ $params['label'] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams['label']['id'],
+ 'name' => $subjectParams['label']['title']
+ ];
+ }
+ return $params;
+ }
+
+ private function parseParamForAcl($subjectParams, $params) {
+ if (array_key_exists('acl', $subjectParams)) {
+ if ($subjectParams['acl']['type'] === Acl::PERMISSION_TYPE_USER) {
+ $user = $this->userManager->get($subjectParams['acl']['participant']);
+ $params['acl'] = [
+ 'type' => 'user',
+ 'id' => $subjectParams['acl']['participant'],
+ 'name' => $user !== null ? $user->getDisplayName() : $subjectParams['acl']['participant']
+ ];
+ } else {
+ $params['acl'] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams['acl']['participant'],
+ 'name' => $subjectParams['acl']['participant']
+ ];
+ }
+ }
+ return $params;
+ }
+
+ private function parseParamForComment($subjectParams, $params, IEvent $event) {
+ if (array_key_exists('comment', $subjectParams)) {
+ /** @var IComment $comment */
+ try {
+ $comment = $this->commentsManager->get((int)$subjectParams['comment']);
+ $event->setParsedMessage($comment->getMessage());
+ $params['comment'] =[
+ 'type' => 'highlight',
+ 'id' => $subjectParams['comment'],
+ 'name' => $comment->getMessage()
+ ];
+ } catch (NotFoundException $e) {
+ }
+ }
+ return $params;
+ }
+
+ private function parseParamForDuedate($subjectParams, $params, IEvent $event) {
+ if (array_key_exists('after', $subjectParams) && $event->getSubject() === ActivityManager::SUBJECT_CARD_UPDATE_DUEDATE) {
+ $userLanguage = $this->config->getUserValue($event->getAuthor(), 'core', 'lang', $this->l10nFactory->findLanguage());
+ $userLocale = $this->config->getUserValue($event->getAuthor(), 'core', 'locale', $this->l10nFactory->findLocale());
+ $l10n = $this->l10nFactory->get('deck', $userLanguage, $userLocale);
+ $date = new \DateTime($subjectParams['after']);
+ $date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
+ $params['after'] = [
+ 'type' => 'highlight',
+ 'id' => 'dt:' . $subjectParams['after'],
+ 'name' => $l10n->l('datetime', $date)
+ ];
+ }
+ return $params;
+ }
+
+ /**
+ * Add diff to message if the subject parameter 'diff' is set, otherwise
+ * the changed values are added to before/after
+ *
+ * @param $subjectParams
+ * @param $params
+ * @return mixed
+ */
+ private function parseParamForChanges($subjectParams, $params, $event) {
+ if (array_key_exists('diff', $subjectParams) && $subjectParams['diff']) {
+ $diff = new Diff();
+ // Don't add diff as message since we are limited to 255 chars here
+ //$event->setMessage($subjectParams['after']);
+ $event->setParsedMessage('' . $diff->render($subjectParams['before'], $subjectParams['after']) . '
');
+ return $params;
+ }
+ if (array_key_exists('before', $subjectParams)) {
+ $params['before'] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams['before'],
+ 'name' => $subjectParams['before']
+ ];
+ }
+ if (array_key_exists('after', $subjectParams)) {
+ $params['after'] = [
+ 'type' => 'highlight',
+ 'id' => $subjectParams['after'],
+ 'name' => $subjectParams['after']
+ ];
+ }
+ return $params;
+ }
+
+ public function deckUrl($endpoint) {
+ return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#!' . $endpoint;
+ }
+}
diff --git a/lib/Activity/DescriptionSetting.php b/lib/Activity/DescriptionSetting.php
new file mode 100644
index 00000000..787647ff
--- /dev/null
+++ b/lib/Activity/DescriptionSetting.php
@@ -0,0 +1,45 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Activity;
+
+
+class DescriptionSetting extends Setting {
+
+ /**
+ * @return string Lowercase a-z and underscore only identifier
+ * @since 11.0.0
+ */
+ public function getIdentifier() {
+ return 'deck_card_description';
+ }
+
+ /**
+ * @return string A translated string
+ * @since 11.0.0
+ */
+ public function getName() {
+ return $this->l->t('A card description inside the Deck app has been changed');
+ }
+
+}
diff --git a/lib/Activity/Filter.php b/lib/Activity/Filter.php
new file mode 100644
index 00000000..62b9a7c8
--- /dev/null
+++ b/lib/Activity/Filter.php
@@ -0,0 +1,92 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Activity;
+
+use OCP\IL10N;
+use OCP\IURLGenerator;
+
+class Filter implements \OCP\Activity\IFilter {
+
+ private $l10n;
+ private $urlGenerator;
+
+ public function __construct(
+ IL10N $l10n,
+ IURLGenerator $urlGenerator
+ ) {
+ $this->l10n = $l10n;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ /**
+ * @return string Lowercase a-z and underscore only identifier
+ * @since 11.0.0
+ */
+ public function getIdentifier() {
+ return 'deck';
+ }
+
+ /**
+ * @return string A translated string
+ * @since 11.0.0
+ */
+ public function getName() {
+ return $this->l10n->t('Deck');
+ }
+
+ /**
+ * @return int whether the filter should be rather on the top or bottom of
+ * the admin section. The filters are arranged in ascending order of the
+ * priority values. It is required to return a value between 0 and 100.
+ * @since 11.0.0
+ */
+ public function getPriority() {
+ return 90;
+ }
+
+ /**
+ * @return string Full URL to an icon, empty string when none is given
+ * @since 11.0.0
+ */
+ public function getIcon() {
+ return $this->urlGenerator->imagePath('deck', 'deck-dark.svg');
+ }
+
+ /**
+ * @param string[] $types
+ * @return string[] An array of allowed apps from which activities should be displayed
+ * @since 11.0.0
+ */
+ public function filterTypes(array $types) {
+ return array_merge($types, ['deck_comment']);
+ }
+
+ /**
+ * @return string[] An array of allowed apps from which activities should be displayed
+ * @since 11.0.0
+ */
+ public function allowedApps() {
+ return ['deck'];
+ }
+}
diff --git a/lib/Activity/Setting.php b/lib/Activity/Setting.php
new file mode 100644
index 00000000..9da38530
--- /dev/null
+++ b/lib/Activity/Setting.php
@@ -0,0 +1,98 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Activity;
+
+
+use OCP\IL10N;
+
+class Setting implements \OCP\Activity\ISetting {
+
+ /** @var IL10N */
+ protected $l;
+
+ /**
+ * @param IL10N $l
+ */
+ public function __construct(IL10N $l) {
+ $this->l = $l;
+ }
+
+ /**
+ * @return string Lowercase a-z and underscore only identifier
+ * @since 11.0.0
+ */
+ public function getIdentifier() {
+ return 'deck';
+ }
+
+ /**
+ * @return string A translated string
+ * @since 11.0.0
+ */
+ public function getName() {
+ return $this->l->t('Changes in the Deck app');
+ }
+
+ /**
+ * @return int whether the filter should be rather on the top or bottom of
+ * the admin section. The filters are arranged in ascending order of the
+ * priority values. It is required to return a value between 0 and 100.
+ * @since 11.0.0
+ */
+ public function getPriority() {
+ return 90;
+ }
+
+ /**
+ * @return bool True when the option can be changed for the stream
+ * @since 11.0.0
+ */
+ public function canChangeStream() {
+ return true;
+ }
+
+ /**
+ * @return bool True when the option can be changed for the stream
+ * @since 11.0.0
+ */
+ public function isDefaultEnabledStream() {
+ return true;
+ }
+
+ /**
+ * @return bool True when the option can be changed for the mail
+ * @since 11.0.0
+ */
+ public function canChangeMail() {
+ return true;
+ }
+
+ /**
+ * @return bool True when the option can be changed for the stream
+ * @since 11.0.0
+ */
+ public function isDefaultEnabledMail() {
+ return false;
+ }
+}
diff --git a/lib/Activity/SettingComment.php b/lib/Activity/SettingComment.php
new file mode 100644
index 00000000..fd8ad178
--- /dev/null
+++ b/lib/Activity/SettingComment.php
@@ -0,0 +1,53 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Activity;
+
+
+class SettingComment extends Setting {
+
+ /**
+ * @return string Lowercase a-z and underscore only identifier
+ * @since 11.0.0
+ */
+ public function getIdentifier() {
+ return 'deck_comment';
+ }
+
+ /**
+ * @return string A translated string
+ * @since 11.0.0
+ */
+ public function getName() {
+ return $this->l->t('A comment was created on a card');
+ }
+
+ /**
+ * @return bool True when the option can be changed for the stream
+ * @since 11.0.0
+ */
+ public function canChangeStream() {
+ return false;
+ }
+
+}