From 7ce97459d437a98ece0077b28bb36771aa36ed82 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 23 Feb 2022 02:10:57 -0500 Subject: [PATCH 1/9] Deprecated the notify table/classes --- database.sql | 2 +- doc/database.md | 2 +- doc/database/db_notify.md | 2 +- src/DI.php | 4 +- src/Module/BaseNotifications.php | 32 +- src/Module/Notifications/Notifications.php | 22 +- ...otifications.php => FormattedNotifies.php} | 9 +- .../Notifications/Entity/Notify.php | 2 + .../Notifications/Factory/FormattedNotify.php | 378 ++++++++++++++++++ .../Notifications/Factory/Notify.php | 3 + .../Notifications/Repository/Notify.php | 3 + .../ValueObject/FormattedNotify.php | 67 ++++ static/dbstructure.config.php | 2 +- 13 files changed, 492 insertions(+), 36 deletions(-) rename src/Navigation/Notifications/Collection/{FormattedNotifications.php => FormattedNotifies.php} (79%) create mode 100644 src/Navigation/Notifications/Factory/FormattedNotify.php create mode 100644 src/Navigation/Notifications/ValueObject/FormattedNotify.php diff --git a/database.sql b/database.sql index a36adad015..39e40c044a 100644 --- a/database.sql +++ b/database.sql @@ -882,7 +882,7 @@ CREATE TABLE IF NOT EXISTS `notify` ( FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`parent-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) DEFAULT COLLATE utf8mb4_general_ci COMMENT='notifications'; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='[Deprecated] User notifications'; -- -- TABLE notify-threads diff --git a/doc/database.md b/doc/database.md index 628e84e211..f64434b886 100644 --- a/doc/database.md +++ b/doc/database.md @@ -37,7 +37,7 @@ Database Tables | [mailacct](help/database/db_mailacct) | Mail account data for fetching mails | | [manage](help/database/db_manage) | table of accounts that can manage each other | | [notification](help/database/db_notification) | notifications | -| [notify](help/database/db_notify) | notifications | +| [notify](help/database/db_notify) | [Deprecated] User notifications | | [notify-threads](help/database/db_notify-threads) | | | [oembed](help/database/db_oembed) | cache for OEmbed queries | | [openwebauth-token](help/database/db_openwebauth-token) | Store OpenWebAuth token to verify contacts | diff --git a/doc/database/db_notify.md b/doc/database/db_notify.md index 250734e56c..88d814c040 100644 --- a/doc/database/db_notify.md +++ b/doc/database/db_notify.md @@ -1,7 +1,7 @@ Table notify =========== -notifications +[Deprecated] User notifications Fields ------ diff --git a/src/DI.php b/src/DI.php index 708fb7d836..43234946cb 100644 --- a/src/DI.php +++ b/src/DI.php @@ -527,9 +527,9 @@ abstract class DI return self::$dice->create(Navigation\Notifications\Factory\Notify::class); } - public static function formattedNotificationFactory(): Navigation\Notifications\Factory\FormattedNotification + public static function formattedNotificationFactory(): Navigation\Notifications\Factory\FormattedNotify { - return self::$dice->create(Navigation\Notifications\Factory\FormattedNotification::class); + return self::$dice->create(Navigation\Notifications\Factory\FormattedNotify::class); } // diff --git a/src/Module/BaseNotifications.php b/src/Module/BaseNotifications.php index d7319fa4ea..1190e046df 100644 --- a/src/Module/BaseNotifications.php +++ b/src/Module/BaseNotifications.php @@ -29,7 +29,7 @@ use Friendica\Content\Pager; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Core\System; -use Friendica\Navigation\Notifications\ValueObject\FormattedNotification; +use Friendica\Navigation\Notifications\ValueObject\FormattedNotify; use Friendica\Network\HTTPException\ForbiddenException; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -43,29 +43,29 @@ abstract class BaseNotifications extends BaseModule { /** @var array Array of URL parameters */ const URL_TYPES = [ - FormattedNotification::NETWORK => 'network', - FormattedNotification::SYSTEM => 'system', - FormattedNotification::HOME => 'home', - FormattedNotification::PERSONAL => 'personal', - FormattedNotification::INTRO => 'intros', + FormattedNotify::NETWORK => 'network', + FormattedNotify::SYSTEM => 'system', + FormattedNotify::HOME => 'home', + FormattedNotify::PERSONAL => 'personal', + FormattedNotify::INTRO => 'intros', ]; /** @var array Array of the allowed notifications and their printable name */ const PRINT_TYPES = [ - FormattedNotification::NETWORK => 'Network', - FormattedNotification::SYSTEM => 'System', - FormattedNotification::HOME => 'Home', - FormattedNotification::PERSONAL => 'Personal', - FormattedNotification::INTRO => 'Introductions', + FormattedNotify::NETWORK => 'Network', + FormattedNotify::SYSTEM => 'System', + FormattedNotify::HOME => 'Home', + FormattedNotify::PERSONAL => 'Personal', + FormattedNotify::INTRO => 'Introductions', ]; /** @var array The array of access keys for notification pages */ const ACCESS_KEYS = [ - FormattedNotification::NETWORK => 'w', - FormattedNotification::SYSTEM => 'y', - FormattedNotification::HOME => 'h', - FormattedNotification::PERSONAL => 'r', - FormattedNotification::INTRO => 'i', + FormattedNotify::NETWORK => 'w', + FormattedNotify::SYSTEM => 'y', + FormattedNotify::HOME => 'h', + FormattedNotify::PERSONAL => 'r', + FormattedNotify::INTRO => 'i', ]; /** @var int The default count of items per page */ diff --git a/src/Module/Notifications/Notifications.php b/src/Module/Notifications/Notifications.php index e090aa5a38..90ea9c28ba 100644 --- a/src/Module/Notifications/Notifications.php +++ b/src/Module/Notifications/Notifications.php @@ -28,7 +28,7 @@ use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Module\BaseNotifications; use Friendica\Module\Response; -use Friendica\Navigation\Notifications\ValueObject\FormattedNotification; +use Friendica\Navigation\Notifications\ValueObject\FormattedNotify; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -41,14 +41,14 @@ use Psr\Log\LoggerInterface; */ class Notifications extends BaseNotifications { - /** @var \Friendica\Navigation\Notifications\Factory\FormattedNotification */ - protected $formattedNotificationFactory; + /** @var \Friendica\Navigation\Notifications\Factory\FormattedNotify */ + protected $formattedNotifyFactory; - public function __construct(L10n $l10n, App\BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, \Friendica\Navigation\Notifications\Factory\FormattedNotification $formattedNotificationFactory, array $server, array $parameters = []) + public function __construct(L10n $l10n, App\BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, \Friendica\Navigation\Notifications\Factory\FormattedNotify $formattedNotifyFactory, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->formattedNotificationFactory = $formattedNotificationFactory; + $this->formattedNotifyFactory = $formattedNotifyFactory; } /** @@ -59,30 +59,30 @@ class Notifications extends BaseNotifications $notificationHeader = ''; $notifications = []; - $factory = $this->formattedNotificationFactory; + $factory = $this->formattedNotifyFactory; if (($this->args->get(1) == 'network')) { $notificationHeader = $this->t('Network Notifications'); $notifications = [ - 'ident' => FormattedNotification::NETWORK, + 'ident' => FormattedNotify::NETWORK, 'notifications' => $factory->getNetworkList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE), ]; } elseif (($this->args->get(1) == 'system')) { $notificationHeader = $this->t('System Notifications'); $notifications = [ - 'ident' => FormattedNotification::SYSTEM, + 'ident' => FormattedNotify::SYSTEM, 'notifications' => $factory->getSystemList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE), ]; } elseif (($this->args->get(1) == 'personal')) { $notificationHeader = $this->t('Personal Notifications'); $notifications = [ - 'ident' => FormattedNotification::PERSONAL, + 'ident' => FormattedNotify::PERSONAL, 'notifications' => $factory->getPersonalList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE), ]; } elseif (($this->args->get(1) == 'home')) { $notificationHeader = $this->t('Home Notifications'); $notifications = [ - 'ident' => FormattedNotification::HOME, + 'ident' => FormattedNotify::HOME, 'notifications' => $factory->getHomeList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE), ]; } else { @@ -120,7 +120,7 @@ class Notifications extends BaseNotifications ]; // Loop trough ever notification This creates an array with the output html for each // notification and apply the correct template according to the notificationtype (label). - /** @var FormattedNotification $Notification */ + /** @var FormattedNotify $Notification */ foreach ($notifications['notifications'] as $Notification) { $notificationArray = $Notification->toArray(); diff --git a/src/Navigation/Notifications/Collection/FormattedNotifications.php b/src/Navigation/Notifications/Collection/FormattedNotifies.php similarity index 79% rename from src/Navigation/Notifications/Collection/FormattedNotifications.php rename to src/Navigation/Notifications/Collection/FormattedNotifies.php index 8dad2f6af2..0b907caf7d 100644 --- a/src/Navigation/Notifications/Collection/FormattedNotifications.php +++ b/src/Navigation/Notifications/Collection/FormattedNotifies.php @@ -24,12 +24,15 @@ namespace Friendica\Navigation\Notifications\Collection; use Friendica\BaseCollection; use Friendica\Navigation\Notifications\ValueObject; -class FormattedNotifications extends BaseCollection +/** + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Collection\FormattedNotifications instead + */ +class FormattedNotifies extends BaseCollection { /** - * @return ValueObject\FormattedNotification + * @return ValueObject\FormattedNotify */ - public function current(): ValueObject\FormattedNotification + public function current(): ValueObject\FormattedNotify { return parent::current(); } diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index bf47bdafc6..8f8166ab90 100644 --- a/src/Navigation/Notifications/Entity/Notify.php +++ b/src/Navigation/Notifications/Entity/Notify.php @@ -46,6 +46,8 @@ use Psr\Http\Message\UriInterface; * @property-read $uriId * @property-read $parentUriId * @property-read $id + * + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Entity\Notification instead */ class Notify extends BaseEntity { diff --git a/src/Navigation/Notifications/Factory/FormattedNotify.php b/src/Navigation/Notifications/Factory/FormattedNotify.php new file mode 100644 index 0000000000..2551de1a14 --- /dev/null +++ b/src/Navigation/Notifications/Factory/FormattedNotify.php @@ -0,0 +1,378 @@ +. + * + */ + +namespace Friendica\Navigation\Notifications\Factory; + +use Exception; +use Friendica\App\BaseURL; +use Friendica\BaseFactory; +use Friendica\Content\Text\BBCode; +use Friendica\Core\L10n; +use Friendica\Core\Protocol; +use Friendica\Database\Database; +use Friendica\Model\Contact; +use Friendica\Model\Post; +use Friendica\Module\BaseNotifications; +use Friendica\Navigation\Notifications\Collection\FormattedNotifies; +use Friendica\Navigation\Notifications\Repository; +use Friendica\Navigation\Notifications\ValueObject; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Protocol\Activity; +use Friendica\Util\DateTimeFormat; +use Friendica\Util\Proxy; +use Friendica\Util\Temporal; +use Friendica\Util\XML; +use Psr\Log\LoggerInterface; + +/** + * Factory for creating notification objects based on items + * Currently, there are the following types of item based notifications: + * - network + * - system + * - home + * - personal + * + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Factory\FormattedNotification instead + */ +class FormattedNotify extends BaseFactory +{ + /** @var Database */ + private $dba; + /** @var Repository\Notify */ + private $notify; + /** @var BaseURL */ + private $baseUrl; + /** @var L10n */ + private $l10n; + + public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notification, BaseURL $baseUrl, L10n $l10n) + { + parent::__construct($logger); + + $this->dba = $dba; + $this->notify = $notification; + $this->baseUrl = $baseUrl; + $this->l10n = $l10n; + } + + /** + * @param array $formattedItem The return of $this->formatItem + * + * @return ValueObject\FormattedNotify + */ + private function createFromFormattedItem(array $formattedItem): ValueObject\FormattedNotify + { + // Transform the different types of notification in a usable array + switch ($formattedItem['verb'] ?? '') { + case Activity::LIKE: + return new ValueObject\FormattedNotify( + 'like', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s liked %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + case Activity::DISLIKE: + return new ValueObject\FormattedNotify( + 'dislike', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s disliked %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + case Activity::ATTEND: + return new ValueObject\FormattedNotify( + 'attend', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s is attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + case Activity::ATTENDNO: + return new ValueObject\FormattedNotify( + 'attendno', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s is not attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + case Activity::ATTENDMAYBE: + return new ValueObject\FormattedNotify( + 'attendmaybe', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s may attending %s's event", $formattedItem['author-name'], $formattedItem['parent-author-name']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + case Activity::FRIEND: + if (!isset($formattedItem['object'])) { + return new ValueObject\FormattedNotify( + 'friend', + $formattedItem['link'], + $formattedItem['image'], + $formattedItem['url'], + $formattedItem['text'], + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + } + + $xmlHead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">"; + $obj = XML::parseString($xmlHead . $formattedItem['object']); + + $formattedItem['fname'] = $obj->title; + + return new ValueObject\FormattedNotify( + 'friend', + $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], + $formattedItem['author-avatar'], + $formattedItem['author-link'], + $this->l10n->t("%s is now friends with %s", $formattedItem['author-name'], $formattedItem['fname']), + $formattedItem['when'], + $formattedItem['ago'], + $formattedItem['seen'] + ); + + default: + return new ValueObject\FormattedNotify( + $formattedItem['label'] ?? '', + $formattedItem['link'] ?? '', + $formattedItem['image'] ?? '', + $formattedItem['url'] ?? '', + $formattedItem['text'] ?? '', + $formattedItem['when'] ?? '', + $formattedItem['ago'] ?? '', + $formattedItem['seen'] ?? false + ); + } + } + + /** + * Get system notifications + * + * @param bool $seen False => only include notifications into the query + * which aren't marked as "seen" + * @param int $start Start the query at this point + * @param int $limit Maximum number of query results + * + * @return FormattedNotifies + */ + public function getSystemList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies + { + $conditions = []; + if (!$seen) { + $conditions['seen'] = false; + } + + $params = []; + $params['order'] = ['date' => 'DESC']; + $params['limit'] = [$start, $limit]; + + $formattedNotifications = new FormattedNotifies(); + try { + $Notifies = $this->notify->selectForUser(local_user(), $conditions, $params); + + foreach ($Notifies as $Notify) { + $formattedNotifications[] = new ValueObject\FormattedNotify( + 'notification', + $this->baseUrl->get(true) . '/notification/' . $Notify->id, + Contact::getAvatarUrlForUrl($Notify->url, $Notify->uid, Proxy::SIZE_MICRO), + $Notify->url, + strip_tags(BBCode::toPlaintext($Notify->msg)), + DateTimeFormat::local($Notify->date->format(DateTimeFormat::MYSQL), 'r'), + Temporal::getRelativeDate($Notify->date->format(DateTimeFormat::MYSQL)), + $Notify->seen + ); + } + } catch (Exception $e) { + $this->logger->warning('Select failed.', ['conditions' => $conditions, 'exception' => $e]); + } + + return $formattedNotifications; + } + + /** + * Get network notifications + * + * @param bool $seen False => only include notifications into the query + * which aren't marked as "seen" + * @param int $start Start the query at this point + * @param int $limit Maximum number of query results + * + * @return FormattedNotifies + */ + public function getNetworkList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies + { + $condition = ['wall' => false, 'uid' => local_user()]; + + if (!$seen) { + $condition['unseen'] = true; + } + + $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar', + 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; + $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; + + $formattedNotifications = new FormattedNotifies(); + + try { + $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); + while ($userPost = $this->dba->fetch($userPosts)) { + $formattedNotifications[] = $this->createFromFormattedItem($this->formatItem($userPost)); + } + } catch (Exception $e) { + $this->logger->warning('Select failed.', ['condition' => $condition, 'exception' => $e]); + } + + return $formattedNotifications; + } + + /** + * Get personal notifications + * + * @param bool $seen False => only include notifications into the query + * which aren't marked as "seen" + * @param int $start Start the query at this point + * @param int $limit Maximum number of query results + * + * @return FormattedNotifies + */ + public function getPersonalList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies + { + $condition = ['wall' => false, 'uid' => local_user(), 'author-id' => public_contact()]; + + if (!$seen) { + $condition['unseen'] = true; + } + + $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar', + 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; + $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; + + $formattedNotifications = new FormattedNotifies(); + + try { + $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); + while ($userPost = $this->dba->fetch($userPosts)) { + $formattedNotifications[] = $this->createFromFormattedItem($this->formatItem($userPost)); + } + } catch (Exception $e) { + $this->logger->warning('Select failed.', ['conditions' => $condition, 'exception' => $e]); + } + + return $formattedNotifications; + } + + /** + * Get home notifications + * + * @param bool $seen False => only include notifications into the query + * which aren't marked as "seen" + * @param int $start Start the query at this point + * @param int $limit Maximum number of query results + * + * @return FormattedNotifies + */ + public function getHomeList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies + { + $condition = ['wall' => true, 'uid' => local_user()]; + + if (!$seen) { + $condition['unseen'] = true; + } + + $fields = ['id', 'parent', 'verb', 'author-name', 'unseen', 'author-link', 'author-avatar', 'contact-avatar', + 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; + $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; + + $formattedNotifications = new FormattedNotifies(); + + try { + $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); + while ($userPost = $this->dba->fetch($userPosts)) { + $formattedItem = $this->formatItem($userPost); + + // Overwrite specific fields, not default item format + $formattedItem['label'] = 'comment'; + $formattedItem['text'] = $this->l10n->t("%s commented on %s's post", $formattedItem['author-name'], $formattedItem['parent-author-name']); + + $formattedNotifications[] = $this->createFromFormattedItem($formattedItem); + } + } catch (Exception $e) { + $this->logger->warning('Select failed.', ['conditions' => $condition, 'exception' => $e]); + } + + return $formattedNotifications; + } + + /** + * Format the item query in a usable array + * + * @param array $item The item from the db query + * + * @return array The item, extended with the notification-specific information + * + * @throws InternalServerErrorException + * @throws Exception + */ + private function formatItem(array $item): array + { + $item['seen'] = !($item['unseen'] > 0); + + // For feed items we use the user's contact, since the avatar is mostly self choosen. + if (!empty($item['network']) && $item['network'] == Protocol::FEED) { + $item['author-avatar'] = $item['contact-avatar']; + } + + $item['label'] = (($item['gravity'] == GRAVITY_PARENT) ? 'post' : 'comment'); + $item['link'] = $this->baseUrl->get(true) . '/display/' . $item['parent-guid']; + $item['image'] = $item['author-avatar']; + $item['url'] = $item['author-link']; + $item['when'] = DateTimeFormat::local($item['created'], 'r'); + $item['ago'] = Temporal::getRelativeDate($item['created']); + $item['text'] = (($item['gravity'] == GRAVITY_PARENT) + ? $this->l10n->t("%s created a new post", $item['author-name']) + : $this->l10n->t("%s commented on %s's post", $item['author-name'], $item['parent-author-name'])); + + return $item; + } +} diff --git a/src/Navigation/Notifications/Factory/Notify.php b/src/Navigation/Notifications/Factory/Notify.php index fbc6144702..d6c777e6f2 100644 --- a/src/Navigation/Notifications/Factory/Notify.php +++ b/src/Navigation/Notifications/Factory/Notify.php @@ -26,6 +26,9 @@ use Friendica\Capabilities\ICanCreateFromTableRow; use Friendica\Content\Text\BBCode; use GuzzleHttp\Psr7\Uri; +/** + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Factory\Notification instead + */ class Notify extends BaseFactory implements ICanCreateFromTableRow { public function createFromTableRow(array $row): \Friendica\Navigation\Notifications\Entity\Notify diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 6d56258b37..959418bbfa 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -41,6 +41,9 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; use Psr\Log\LoggerInterface; +/** + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Repository\Notification instead + */ class Notify extends BaseRepository { /** @var Factory\Notify */ diff --git a/src/Navigation/Notifications/ValueObject/FormattedNotify.php b/src/Navigation/Notifications/ValueObject/FormattedNotify.php new file mode 100644 index 0000000000..ac0db65ad2 --- /dev/null +++ b/src/Navigation/Notifications/ValueObject/FormattedNotify.php @@ -0,0 +1,67 @@ +. + * + */ + +namespace Friendica\Navigation\Notifications\ValueObject; + +use Friendica\BaseDataTransferObject; + +/** + * A view-only object for printing item notifications to the frontend + * + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\ValueObject\FormattedNotification instead + */ +class FormattedNotify extends BaseDataTransferObject +{ + const SYSTEM = 'system'; + const PERSONAL = 'personal'; + const NETWORK = 'network'; + const INTRO = 'intro'; + const HOME = 'home'; + + /** @var string */ + protected $label = ''; + /** @var string */ + protected $link = ''; + /** @var string */ + protected $image = ''; + /** @var string */ + protected $url = ''; + /** @var string */ + protected $text = ''; + /** @var string */ + protected $when = ''; + /** @var string */ + protected $ago = ''; + /** @var boolean */ + protected $seen = false; + + public function __construct(string $label, string $link, string $image, string $url, string $text, string $when, string $ago, bool $seen) + { + $this->label = $label ?? ''; + $this->link = $link ?? ''; + $this->image = $image ?? ''; + $this->url = $url ?? ''; + $this->text = $text ?? ''; + $this->when = $when ?? ''; + $this->ago = $ago ?? ''; + $this->seen = $seen ?? false; + } +} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index f7e02b10b9..8963b1df60 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -904,7 +904,7 @@ return [ ] ], "notify" => [ - "comment" => "notifications", + "comment" => "[Deprecated] User notifications", "fields" => [ "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], "type" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], From deafdcde956b6fd973bf922abc9cb6d2ad66e880 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 3 Mar 2022 08:49:07 -0500 Subject: [PATCH 2/9] Use public contact ID in Model\Post\UserNotification::insertNotification - Add localRelationship dependency to Notification factory - Remove dependencies from Factory\Notification->getMessageFromNotification method --- src/DI.php | 5 + src/Model/Contact.php | 8 +- src/Model/Post/UserNotification.php | 6 +- .../Notifications/Entity/Notification.php | 8 +- .../Notifications/Factory/Notification.php | 140 +++++++++++------- .../Notifications/Repository/Notification.php | 4 +- .../Notifications/Repository/Notify.php | 2 +- src/Worker/PushSubscription.php | 2 +- 8 files changed, 105 insertions(+), 70 deletions(-) diff --git a/src/DI.php b/src/DI.php index 43234946cb..1283100313 100644 --- a/src/DI.php +++ b/src/DI.php @@ -487,6 +487,11 @@ abstract class DI return self::$dice->create(Contact\Introduction\Factory\Introduction::class); } + public static function localRelationship(): Contact\LocalRelationship\Repository\LocalRelationship + { + return self::$dice->create(Contact\LocalRelationship\Repository\LocalRelationship::class); + } + public static function permissionSet(): Security\PermissionSet\Repository\PermissionSet { return self::$dice->create(Security\PermissionSet\Repository\PermissionSet::class); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index f0be457722..cdb347e8be 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -2665,7 +2665,7 @@ class Contact // Ensure to always have the correct network type, independent from the connection request method self::updateFromProbe($contact['id']); - Post\UserNotification::insertNotification($contact['id'], Activity::FOLLOW, $importer['uid']); + Post\UserNotification::insertNotification($pub_contact['id'], Activity::FOLLOW, $importer['uid']); return true; } else { @@ -2696,7 +2696,7 @@ class Contact self::updateAvatar($contact_id, $photo, true); - Post\UserNotification::insertNotification($contact_id, Activity::FOLLOW, $importer['uid']); + Post\UserNotification::insertNotification($pub_contact['id'], Activity::FOLLOW, $importer['uid']); $contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo'], ['id' => $contact_id]); @@ -2716,9 +2716,7 @@ class Contact Group::addMember(User::getDefaultGroup($importer['uid']), $contact_record['id']); - if (($user['notify-flags'] & Notification\Type::INTRO) && - in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) { - + if (($user['notify-flags'] & Notification\Type::INTRO) && $user['page-flags'] == User::PAGE_FLAGS_NORMAL) { DI::notify()->createFromArray([ 'type' => Notification\Type::INTRO, 'otype' => Notification\ObjectType::INTRO, diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index d9bd2256f2..0873646a41 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -308,7 +308,7 @@ class UserNotification return; } - $notification = (new Notifications\Factory\Notification(DI::logger()))->createForUser( + $notification = (new Notifications\Factory\Notification(DI::baseUrl(), DI::l10n(), DI::localRelationship(), DI::logger()))->createForUser( $uid, $item['vid'], $type, @@ -328,7 +328,7 @@ class UserNotification /** * Add a notification entry * - * @param int $actor Contact ID of the actor + * @param int $actor Public contact ID of the actor * @param string $verb One of the Activity verb constant values * @param int $uid User ID * @return boolean @@ -336,7 +336,7 @@ class UserNotification */ public static function insertNotification(int $actor, string $verb, int $uid): bool { - $notification = (new Notifications\Factory\Notification(DI::logger()))->createForRelationship( + $notification = (new Notifications\Factory\Notification(DI::baseUrl(), DI::l10n(), DI::localRelationship(), DI::logger()))->createForRelationship( $uid, $actor, $verb diff --git a/src/Navigation/Notifications/Entity/Notification.php b/src/Navigation/Notifications/Entity/Notification.php index 15cf3be537..0f12bfe84f 100644 --- a/src/Navigation/Notifications/Entity/Notification.php +++ b/src/Navigation/Notifications/Entity/Notification.php @@ -34,6 +34,7 @@ use Friendica\BaseEntity; * @property-read $parentUriId * @property-read $created * @property-read $seen + * @property-read $dismissed */ class Notification extends BaseEntity { @@ -72,11 +73,11 @@ class Notification extends BaseEntity * @param int|null $parentUriId * @param DateTime|null $created * @param bool $seen - * @param int|null $id * @param bool $dismissed + * @param int|null $id * @see \Friendica\Navigation\Notifications\Factory\Notification */ - public function __construct(int $uid, string $verb, int $type, int $actorId, int $targetUriId = null, int $parentUriId = null, DateTime $created = null, bool $seen = false, int $id = null, bool $dismissed = false) + public function __construct(int $uid, string $verb, int $type, int $actorId, int $targetUriId = null, int $parentUriId = null, DateTime $created = null, bool $seen = false, bool $dismissed = false, int $id = null) { $this->uid = $uid; $this->verb = $verb; @@ -86,8 +87,9 @@ class Notification extends BaseEntity $this->parentUriId = $parentUriId ?: $targetUriId; $this->created = $created; $this->seen = $seen; - $this->id = $id; $this->dismissed = $dismissed; + + $this->id = $id; } public function setSeen() diff --git a/src/Navigation/Notifications/Factory/Notification.php b/src/Navigation/Notifications/Factory/Notification.php index 7cc17f8fe3..50180a9203 100644 --- a/src/Navigation/Notifications/Factory/Notification.php +++ b/src/Navigation/Notifications/Factory/Notification.php @@ -24,16 +24,35 @@ namespace Friendica\Navigation\Notifications\Factory; use Friendica\App\BaseURL; use Friendica\BaseFactory; use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Contact\LocalRelationship\Repository\LocalRelationship; use Friendica\Content\Text\Plaintext; use Friendica\Core\L10n; use Friendica\Model\Contact; use Friendica\Model\Post; use Friendica\Model\Verb; use Friendica\Navigation\Notifications\Entity; +use Friendica\Network\HTTPException; use Friendica\Protocol\Activity; +use Psr\Log\LoggerInterface; class Notification extends BaseFactory implements ICanCreateFromTableRow { + /** @var BaseURL */ + private $baseUrl; + /** @var L10n */ + private $l10n; + /** @var LocalRelationship */ + private $localRelationshipRepo; + + public function __construct(\Friendica\App\BaseURL $baseUrl, \Friendica\Core\L10n $l10n, \Friendica\Contact\LocalRelationship\Repository\LocalRelationship $localRelationshipRepo, LoggerInterface $logger) + { + parent::__construct($logger); + + $this->baseUrl = $baseUrl; + $this->l10n = $l10n; + $this->localRelationshipRepo = $localRelationshipRepo; + } + public function createFromTableRow(array $row): Entity\Notification { return new Entity\Notification( @@ -45,7 +64,8 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow $row['parent-uri-id'], new \DateTime($row['created'], new \DateTimeZone('UTC')), $row['seen'], - $row['id'] + $row['dismissed'], + $row['id'], ); } @@ -61,6 +81,12 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow ); } + /** + * @param int $uid + * @param int $contactId Public contact id + * @param string $verb + * @return Entity\Notification + */ public function createForRelationship(int $uid, int $contactId, string $verb): Entity\Notification { return new Entity\Notification( @@ -73,12 +99,11 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow /** * @param Entity\Notification $Notification - * @param BaseURL $baseUrl - * @param L10n $userL10n Seeded with the language of the user we mean the notification for * @return array - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws HTTPException\InternalServerErrorException + * @throws HTTPException\NotFoundException */ - public function getMessageFromNotification(Entity\Notification $Notification, BaseURL $baseUrl, L10n $userL10n) + public function getMessageFromNotification(Entity\Notification $Notification): array { $message = []; @@ -89,37 +114,41 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow } if ($Notification->type === Post\UserNotification::TYPE_NONE) { - if ($causer['pending']) { - $msg = $userL10n->t('%1$s wants to follow you'); + $localRelationship = $this->localRelationshipRepo->getForUserContact($Notification->uid, $Notification->actorId); + if ($localRelationship->pending) { + $msg = $this->l10n->t('%1$s wants to follow you'); } else { - $msg = $userL10n->t('%1$s had started following you'); + $msg = $this->l10n->t('%1$s had started following you'); } + $title = $causer['name']; - $link = $baseUrl . '/contact/' . $causer['id']; + $link = $this->baseUrl . '/contact/' . $causer['id']; } else { if (!$Notification->targetUriId) { return $message; } - if (in_array($Notification->type, [Post\UserNotification::TYPE_THREAD_COMMENT, Post\UserNotification::TYPE_COMMENT_PARTICIPATION, Post\UserNotification::TYPE_ACTIVITY_PARTICIPATION, Post\UserNotification::TYPE_EXPLICIT_TAGGED])) { - $item = Post::selectFirst([], ['uri-id' => $Notification->parentUriId, 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); - if (empty($item)) { - $this->logger->info('Parent post not found', ['uri-id' => $Notification->parentUriId]); - return $message; - } - } else { - $item = Post::selectFirst([], ['uri-id' => $Notification->targetUriId, 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); - if (empty($item)) { - $this->logger->info('Post not found', ['uri-id' => $Notification->targetUriId]); - return $message; - } + $item = Post::selectFirst([], ['uri-id' => $Notification->targetUriId, 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); + if (empty($item)) { + $this->logger->info('Post not found', ['uri-id' => $Notification->targetUriId]); + return $message; + } - if (($Notification->verb == Activity::POST) || ($Notification->type === Post\UserNotification::TYPE_SHARED)) { - $item = Post::selectFirst([], ['uri-id' => $item['thr-parent-id'], 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); - if (empty($item)) { - $this->logger->info('Thread parent post not found', ['uri-id' => $item['thr-parent-id']]); - return $message; - } + if ($Notification->type == Post\UserNotification::TYPE_ACTIVITY_PARTICIPATION) { + $thrParentId = $item['thr-parent-id']; + $item = Post::selectFirst([], ['uri-id' => $thrParentId, 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); + if (empty($item)) { + $this->logger->info('Thread parent post not found', ['uri-id' => $thrParentId]); + return $message; + } + } + + $parent = $item; + if ($Notification->targetUriId != $Notification->parentUriId) { + $parent = Post::selectFirst([], ['uri-id' => $Notification->parentUriId, 'uid' => [0, $Notification->uid]], ['order' => ['uid' => true]]); + if (empty($parent)) { + $this->logger->info('Top level post not found', ['uri-id' => $Notification->parentUriId]); + return $message; } } @@ -131,9 +160,9 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow } } - $link = $baseUrl . '/display/' . urlencode($item['guid']); + $link = $this->baseUrl . '/display/' . urlencode($item['guid']); - $content = Plaintext::getPost($item, 70); + $content = Plaintext::getPost($parent, 70); if (!empty($content['text'])) { $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"'; } else { @@ -146,40 +175,40 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow case Activity::LIKE: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_COMMENT: - $msg = $userL10n->t('%1$s liked your comment %2$s'); + $msg = $this->l10n->t('%1$s liked your comment %2$s'); break; case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s liked your post %2$s'); + $msg = $this->l10n->t('%1$s liked your post %2$s'); break; } break; case Activity::DISLIKE: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_COMMENT: - $msg = $userL10n->t('%1$s disliked your comment %2$s'); + $msg = $this->l10n->t('%1$s disliked your comment %2$s'); break; case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s disliked your post %2$s'); + $msg = $this->l10n->t('%1$s disliked your post %2$s'); break; } break; case Activity::ANNOUNCE: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_COMMENT: - $msg = $userL10n->t('%1$s shared your comment %2$s'); + $msg = $this->l10n->t('%1$s shared your comment %2$s'); break; case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s shared your post %2$s'); + $msg = $this->l10n->t('%1$s shared your post %2$s'); break; case Post\UserNotification::TYPE_SHARED: if (($causer['id'] != $author['id']) && ($title != '')) { - $msg = $userL10n->t('%1$s shared the post %2$s from %3$s'); + $msg = $this->l10n->t('%1$s shared the post %2$s from %3$s'); } elseif ($causer['id'] != $author['id']) { - $msg = $userL10n->t('%1$s shared a post from %3$s'); + $msg = $this->l10n->t('%1$s shared a post from %3$s'); } elseif ($title != '') { - $msg = $userL10n->t('%1$s shared the post %2$s'); + $msg = $this->l10n->t('%1$s shared the post %2$s'); } else { - $msg = $userL10n->t('%1$s shared a post'); + $msg = $this->l10n->t('%1$s shared a post'); } break; } @@ -187,68 +216,68 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow case Activity::ATTEND: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s wants to attend your event %2$s'); + $msg = $this->l10n->t('%1$s wants to attend your event %2$s'); break; } break; case Activity::ATTENDNO: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s does not want to attend your event %2$s'); + $msg = $this->l10n->t('%1$s does not want to attend your event %2$s'); break; } break; case Activity::ATTENDMAYBE: switch ($Notification->type) { case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s maybe wants to attend your event %2$s'); + $msg = $this->l10n->t('%1$s maybe wants to attend your event %2$s'); break; } break; case Activity::POST: switch ($Notification->type) { case Post\UserNotification::TYPE_EXPLICIT_TAGGED: - $msg = $userL10n->t('%1$s tagged you on %2$s'); + $msg = $this->l10n->t('%1$s tagged you on %2$s'); break; case Post\UserNotification::TYPE_IMPLICIT_TAGGED: - $msg = $userL10n->t('%1$s replied to you on %2$s'); + $msg = $this->l10n->t('%1$s replied to you on %2$s'); break; case Post\UserNotification::TYPE_THREAD_COMMENT: - $msg = $userL10n->t('%1$s commented in your thread %2$s'); + $msg = $this->l10n->t('%1$s commented in your thread %2$s'); break; case Post\UserNotification::TYPE_DIRECT_COMMENT: - $msg = $userL10n->t('%1$s commented on your comment %2$s'); + $msg = $this->l10n->t('%1$s commented on your comment %2$s'); break; case Post\UserNotification::TYPE_COMMENT_PARTICIPATION: case Post\UserNotification::TYPE_ACTIVITY_PARTICIPATION: if (($causer['id'] == $author['id']) && ($title != '')) { - $msg = $userL10n->t('%1$s commented in their thread %2$s'); + $msg = $this->l10n->t('%1$s commented in their thread %2$s'); } elseif ($causer['id'] == $author['id']) { - $msg = $userL10n->t('%1$s commented in their thread'); + $msg = $this->l10n->t('%1$s commented in their thread'); } elseif ($title != '') { - $msg = $userL10n->t('%1$s commented in the thread %2$s from %3$s'); + $msg = $this->l10n->t('%1$s commented in the thread %2$s from %3$s'); } else { - $msg = $userL10n->t('%1$s commented in the thread from %3$s'); + $msg = $this->l10n->t('%1$s commented in the thread from %3$s'); } break; case Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT: - $msg = $userL10n->t('%1$s commented on your thread %2$s'); + $msg = $this->l10n->t('%1$s commented on your thread %2$s'); break; case Post\UserNotification::TYPE_SHARED: if (($causer['id'] != $author['id']) && ($title != '')) { - $msg = $userL10n->t('%1$s shared the post %2$s from %3$s'); + $msg = $this->l10n->t('%1$s shared the post %2$s from %3$s'); } elseif ($causer['id'] != $author['id']) { - $msg = $userL10n->t('%1$s shared a post from %3$s'); + $msg = $this->l10n->t('%1$s shared a post from %3$s'); } elseif ($title != '') { - $msg = $userL10n->t('%1$s shared the post %2$s'); + $msg = $this->l10n->t('%1$s shared the post %2$s'); } else { - $msg = $userL10n->t('%1$s shared a post'); + $msg = $this->l10n->t('%1$s shared a post'); } break; } @@ -268,6 +297,7 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow '[url=' . $causer['url'] . ']' . $causer['name'] . '[/url]', '[url=' . $link . ']' . $title . '[/url]', '[url=' . $author['url'] . ']' . $author['name'] . '[/url]'); + $message['link'] = $link; } return $message; diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index c4035663b0..2269f5bc54 100644 --- a/src/Navigation/Notifications/Repository/Notification.php +++ b/src/Navigation/Notifications/Repository/Notification.php @@ -41,9 +41,9 @@ class Notification extends BaseRepository protected static $table_name = 'notification'; - public function __construct(Database $database, LoggerInterface $logger, Factory\Notification $factory = null) + public function __construct(Database $database, LoggerInterface $logger, Factory\Notification $factory) { - parent::__construct($database, $logger, $factory ?? new Factory\Notification($logger)); + parent::__construct($database, $logger, $factory); } /** diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 959418bbfa..eb65ed4a41 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -732,7 +732,7 @@ class Notify extends BaseRepository $subject = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $item['parent'], $contact['name']); } - $msg = $this->notification->getMessageFromNotification($Notification, $this->baseUrl, $l10n); + $msg = $this->notification->getMessageFromNotification($Notification); if (empty($msg)) { $this->logger->info('No notification message, quitting', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]); return false; diff --git a/src/Worker/PushSubscription.php b/src/Worker/PushSubscription.php index 7b9f5acbd9..45ecb62291 100644 --- a/src/Worker/PushSubscription.php +++ b/src/Worker/PushSubscription.php @@ -82,7 +82,7 @@ class PushSubscription } } - $message = DI::notificationFactory()->getMessageFromNotification($Notification, DI::baseUrl(), $l10n); + $message = DI::notificationFactory()->getMessageFromNotification($Notification); $title = $message['plain'] ?: ''; $push = Subscription::create([ From b7cee324b0e4fe9048ffdee660cfc3a0f2dfd56a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 3 Mar 2022 09:07:37 -0500 Subject: [PATCH 3/9] Add legacy notification endpoint for deprecated Notify entity - Add dependencies to Notifications\Notification module class --- mod/ping.php | 2 +- src/Module/Notifications/Notification.php | 144 +++++++++++++----- .../Notifications/Factory/FormattedNotify.php | 2 +- .../Notifications/Repository/Notify.php | 2 +- static/routes.config.php | 2 + tests/datasets/api.fixture.php | 8 +- .../Module/Api/Friendica/NotificationTest.php | 2 +- 7 files changed, 112 insertions(+), 50 deletions(-) diff --git a/mod/ping.php b/mod/ping.php index 1afab5f726..d5b43d6ea4 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -442,7 +442,7 @@ function ping_get_notifications($uid) DBA::update('notify', ['name_cache' => $notification["name"], 'msg_cache' => $notification["message"]], ['id' => $notification["id"]]); } - $notification["href"] = DI::baseUrl() . "/notification/" . $notification["id"]; + $notification["href"] = DI::baseUrl() . "/notify/" . $notification["id"]; if ($notification["visible"] && !$notification["deleted"] diff --git a/src/Module/Notifications/Notification.php b/src/Module/Notifications/Notification.php index d72e3c2502..a28b5d6f65 100644 --- a/src/Module/Notifications/Notification.php +++ b/src/Module/Notifications/Notification.php @@ -21,18 +21,45 @@ namespace Friendica\Module\Notifications; +use Friendica\App; use Friendica\BaseModule; +use Friendica\Contact\Introduction\Repository\Introduction; +use Friendica\Core\L10n; +use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\System; -use Friendica\DI; use Friendica\Model\Contact; +use Friendica\Module\Response; use Friendica\Module\Security\Login; +use Friendica\Navigation\Notifications\Factory; +use Friendica\Navigation\Notifications\Repository; use Friendica\Network\HTTPException; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; -/** - * Interacting with the /notification command - */ class Notification extends BaseModule { + /** @var Introduction */ + private $introductionRepo; + /** @var Repository\Notification */ + private $notificationRepo; + /** @var Repository\Notify */ + private $notifyRepo; + /** @var IManagePersonalConfigValues */ + private $pconfig; + /** @var Factory\Notification */ + private $notificationFactory; + + public function __construct(Introduction $introductionRepo, Repository\Notification $notificationRepo, Factory\Notification $notificationFactory, Repository\Notify $notifyRepo, IManagePersonalConfigValues $pconfig, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->introductionRepo = $introductionRepo; + $this->notificationRepo = $notificationRepo; + $this->notificationFactory = $notificationFactory; + $this->notifyRepo = $notifyRepo; + $this->pconfig = $pconfig; + } + /** * {@inheritDoc} * @@ -45,26 +72,26 @@ class Notification extends BaseModule protected function post(array $request = []) { if (!local_user()) { - throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.')); + throw new HTTPException\UnauthorizedException($this->l10n->t('Permission denied.')); } $request_id = $this->parameters['id'] ?? false; if ($request_id) { - $intro = DI::intro()->selectOneById($request_id, local_user()); + $intro = $this->introductionRepo->selectOneById($request_id, local_user()); switch ($_POST['submit']) { - case DI::l10n()->t('Discard'): + case $this->l10n->t('Discard'): Contact\Introduction::discard($intro); - DI::intro()->delete($intro); + $this->introductionRepo->delete($intro); break; - case DI::l10n()->t('Ignore'): + case $this->l10n->t('Ignore'): $intro->ignore(); - DI::intro()->save($intro); + $this->introductionRepo->save($intro); break; } - DI::baseUrl()->redirect('notifications/intros'); + $this->baseUrl->redirect('notifications/intros'); } } @@ -76,15 +103,15 @@ class Notification extends BaseModule protected function rawContent(array $request = []) { if (!local_user()) { - throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.')); + throw new HTTPException\UnauthorizedException($this->l10n->t('Permission denied.')); } - if (DI::args()->get(1) === 'mark' && DI::args()->get(2) === 'all') { + if ($this->args->get(1) === 'mark' && $this->args->get(2) === 'all') { try { - DI::notification()->setAllSeenForUser(local_user()); - $success = DI::notify()->setAllSeenForUser(local_user()); + $this->notificationRepo->setAllSeenForUser(local_user()); + $success = $this->notifyRepo->setAllSeenForUser(local_user()); } catch (\Exception $e) { - DI::logger()->warning('set all seen failed.', ['exception' => $e]); + $this->logger->warning('set all seen failed.', ['exception' => $e]); $success = false; } @@ -104,38 +131,71 @@ class Notification extends BaseModule protected function content(array $request = []): string { if (!local_user()) { - notice(DI::l10n()->t('You must be logged in to show this page.')); + notice($this->l10n->t('You must be logged in to show this page.')); return Login::form(); } - $request_id = $this->parameters['id'] ?? false; - - if ($request_id) { - $Notify = DI::notify()->selectOneById($request_id); - if ($Notify->uid !== local_user()) { - throw new HTTPException\ForbiddenException(); - } - - if (DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { - $Notify->setSeen(); - DI::notify()->save($Notify); - } else { - if ($Notify->uriId) { - DI::notification()->setAllSeenForUser($Notify->uid, ['target-uri-id' => $Notify->uriId]); - } - - DI::notify()->setAllSeenForRelatedNotify($Notify); - } - - if ((string)$Notify->link) { - System::externalRedirect($Notify->link); - } - - DI::baseUrl()->redirect(); + if (isset($this->parameters['notify_id'])) { + $this->handleNotify($this->parameters['notify_id']); + } elseif (isset($this->parameters['id'])) { + $this->handleNotification($this->parameters['id']); } - DI::baseUrl()->redirect('notifications/system'); + $this->baseUrl->redirect('notifications/system'); return ''; } + + private function handleNotify(int $notifyId) + { + $Notify = $this->notifyRepo->selectOneById($notifyId); + if ($Notify->uid !== local_user()) { + throw new HTTPException\ForbiddenException(); + } + + if ($this->pconfig->get(local_user(), 'system', 'detailed_notif')) { + $Notify->setSeen(); + $this->notifyRepo->save($Notify); + } else { + if ($Notify->uriId) { + $this->notificationRepo->setAllSeenForUser($Notify->uid, ['target-uri-id' => $Notify->uriId]); + } + + $this->notifyRepo->setAllSeenForRelatedNotify($Notify); + } + + if ((string)$Notify->link) { + System::externalRedirect($Notify->link); + } + + $this->baseUrl->redirect(); + } + + private function handleNotification(int $notificationId) + { + $Notification = $this->notificationRepo->selectOneById($notificationId); + if ($Notification->uid !== local_user()) { + throw new HTTPException\ForbiddenException(); + } + + if ($this->pconfig->get(local_user(), 'system', 'detailed_notif')) { + $Notification->setSeen(); + $this->notificationRepo->save($Notification); + } else { + if ($Notification->parentUriId) { + $this->notificationRepo->setAllSeenForUser($Notification->uid, ['parent-uri-id' => $Notification->parentUriId]); + } else { + $Notification->setSeen(); + $this->notificationRepo->save($Notification); + } + } + + $message = $this->notificationFactory->getMessageFromNotification($Notification); + + if ($message['link']) { + System::externalRedirect($message['link']); + } + + $this->baseUrl->redirect(); + } } diff --git a/src/Navigation/Notifications/Factory/FormattedNotify.php b/src/Navigation/Notifications/Factory/FormattedNotify.php index 2551de1a14..d4aba639c5 100644 --- a/src/Navigation/Notifications/Factory/FormattedNotify.php +++ b/src/Navigation/Notifications/Factory/FormattedNotify.php @@ -214,7 +214,7 @@ class FormattedNotify extends BaseFactory foreach ($Notifies as $Notify) { $formattedNotifications[] = new ValueObject\FormattedNotify( 'notification', - $this->baseUrl->get(true) . '/notification/' . $Notify->id, + $this->baseUrl->get(true) . '/notify/' . $Notify->id, Contact::getAvatarUrlForUrl($Notify->url, $Notify->uid, Proxy::SIZE_MICRO), $Notify->url, strip_tags(BBCode::toPlaintext($Notify->msg)), diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index eb65ed4a41..9773b6446a 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -570,7 +570,7 @@ class Notify extends BaseRepository $Notify->updateMsgFromPreamble($epreamble); $Notify = $this->save($Notify); - $itemlink = $this->baseUrl->get() . '/notification/' . $Notify->id; + $itemlink = $this->baseUrl->get() . '/notify/' . $Notify->id; $notify_id = $Notify->id; } diff --git a/static/routes.config.php b/static/routes.config.php index e10ec2aedf..bc3f15e4e1 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -449,6 +449,8 @@ return [ '/{id:\d+}' => [Module\Notifications\Notification::class, [R::GET, R::POST]], ], + '/notify/{notify_id:\d+}' => [Module\Notifications\Notification::class, [R::GET]], + '/oauth' => [ '/acknowledge' => [Module\OAuth\Acknowledge::class, [R::GET, R::POST]], '/authorize' => [Module\OAuth\Authorize::class, [R::GET]], diff --git a/tests/datasets/api.fixture.php b/tests/datasets/api.fixture.php index 1b52baa354..ace928b090 100644 --- a/tests/datasets/api.fixture.php +++ b/tests/datasets/api.fixture.php @@ -903,18 +903,18 @@ return [ [ 'id' => 1, 'type' => 8, - 'name' => 'Reply to', - 'url' => 'http://localhost/display/1', + 'name' => 'Friend contact', + 'url' => 'http://localhost/profile/friendcontact', 'photo' => 'http://localhost/', 'date' => '2020-01-01 12:12:02', 'msg' => 'A test reply from an item', 'uid' => 42, - 'link' => 'http://localhost/notification/1', + 'link' => 'http://localhost/display/1', 'iid' => 4, 'seen' => 0, 'verb' => \Friendica\Protocol\Activity::POST, 'otype' => Notification\ObjectType::ITEM, - 'name_cache' => 'Reply to', + 'name_cache' => 'Friend contact', 'msg_cache' => 'A test reply from an item', ], ], diff --git a/tests/src/Module/Api/Friendica/NotificationTest.php b/tests/src/Module/Api/Friendica/NotificationTest.php index 4e8509b4eb..3c17471b03 100644 --- a/tests/src/Module/Api/Friendica/NotificationTest.php +++ b/tests/src/Module/Api/Friendica/NotificationTest.php @@ -62,7 +62,7 @@ class NotificationTest extends ApiTest $assertXml = << - + XML; From 5a12bd87f39ab6fda311a1916ec5ad0b22279831 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 4 Mar 2022 00:21:06 -0500 Subject: [PATCH 4/9] Replace Javascript notification string formatting with Smarty templates --- mod/ping.php | 136 ++++++++++-------- .../Notifications/Entity/Notify.php | 12 +- view/js/main.js | 33 ++--- view/templates/nav.tpl | 4 - view/templates/notifications/nav/notify.tpl | 3 + view/theme/duepuntozero/templates/nav.tpl | 4 - view/theme/frio/templates/nav.tpl | 16 --- .../templates/notifications/nav/notify.tpl | 11 ++ view/theme/quattro/templates/nav.tpl | 3 - view/theme/smoothly/templates/nav.tpl | 4 - view/theme/vier/templates/nav.tpl | 12 +- .../templates/notifications/nav/notify.tpl | 9 ++ 12 files changed, 107 insertions(+), 140 deletions(-) create mode 100644 view/templates/notifications/nav/notify.tpl create mode 100644 view/theme/frio/templates/notifications/nav/notify.tpl create mode 100644 view/theme/vier/templates/notifications/nav/notify.tpl diff --git a/mod/ping.php b/mod/ping.php index d5b43d6ea4..813ea6a1ad 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -31,6 +31,7 @@ use Friendica\Model\Group; use Friendica\Model\Notification; use Friendica\Model\Post; use Friendica\Model\Verb; +use Friendica\Navigation\Notifications\Entity; use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy; @@ -253,58 +254,53 @@ function ping_init(App $a) $data['birthdays'] = $birthdays; $data['birthdays-today'] = $birthdays_today; - if (DBA::isResult($notifications)) { - foreach ($notifications as $notif) { - if ($notif['seen'] == 0) { - $sysnotify_count ++; - } + foreach ($notifications as $notification) { + if ($notification['seen'] == 0) { + $sysnotify_count ++; } } // merge all notification types in one array if (DBA::isResult($intros)) { foreach ($intros as $intro) { - $notif = [ - 'id' => 0, + $notifications[] = [ 'href' => DI::baseUrl() . '/notifications/intros/' . $intro['id'], - 'name' => BBCode::convert($intro['name']), - 'url' => $intro['url'], - 'photo' => $intro['photo'], + 'contact' => [ + 'name' => strip_tags(BBCode::convert($intro['name'])), + 'url' => $intro['url'], + ], + 'message' => DI::l10n()->t('{0}} wants to follow you'), 'date' => $intro['datetime'], 'seen' => false, - 'message' => DI::l10n()->t('{0} wants to be your friend'), ]; - $notifications[] = $notif; } } if (DBA::isResult($regs)) { if (count($regs) <= 1 || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { foreach ($regs as $reg) { - $notif = [ - 'id' => 0, + $notifications[] = [ 'href' => DI::baseUrl()->get(true) . '/admin/users/pending', - 'name' => $reg['name'], - 'url' => $reg['url'], - 'photo' => $reg['micro'], + 'contact' => [ + 'name' => $reg['name'], + 'url' => $reg['url'], + ], + 'message' => DI::l10n()->t('{0} requested registration'), 'date' => $reg['created'], 'seen' => false, - 'message' => DI::l10n()->t('{0} requested registration'), ]; - $notifications[] = $notif; } } else { - $notif = [ - 'id' => 0, + $notifications[] = [ 'href' => DI::baseUrl()->get(true) . '/admin/users/pending', - 'name' => $regs[0]['name'], - 'url' => $regs[0]['url'], - 'photo' => $regs[0]['micro'], + 'contact' => [ + 'name' => $regs[0]['name'], + 'url' => $regs[0]['url'], + ], + 'message' => DI::l10n()->t('{0} and %d others requested registration', count($regs) - 1), 'date' => $regs[0]['created'], 'seen' => false, - 'message' => DI::l10n()->t('{0} and %d others requested registration', count($regs) - 1), ]; - $notifications[] = $notif; } } @@ -328,12 +324,6 @@ function ping_init(App $a) return ($adate < $bdate) ? 1 : -1; }; usort($notifications, $sort_function); - - array_walk($notifications, function (&$notification) { - $notification['photo'] = Contact::getAvatarUrlForUrl($notification['url'], local_user(), Proxy::SIZE_MICRO); - $notification['timestamp'] = DateTimeFormat::local($notification['date']); - $notification['date'] = Temporal::getRelativeDate($notification['date']); - }); } $sysmsgs = []; @@ -351,11 +341,26 @@ function ping_init(App $a) if ($format == 'json') { $notification_count = $sysnotify_count + $intro_count + $register_count; - + + $tpl = \Friendica\Core\Renderer::getMarkupTemplate('notifications/nav/notify.tpl'); + $data['groups'] = $groups_unseen; $data['forums'] = $forums_unseen; $data['notification'] = ($notification_count < 50) ? $notification_count : '49+'; - $data['notifications'] = $notifications; + $data['notifications'] = array_map(function ($navNotification) use ($tpl) { + $navNotification['contact']['photo'] = Contact::getAvatarUrlForUrl($navNotification['contact']['url'], local_user(), Proxy::SIZE_MICRO); + + $navNotification['timestamp'] = strtotime($navNotification['date']); + $navNotification['localdate'] = DateTimeFormat::local($navNotification['date']); + $navNotification['ago'] = Temporal::getRelativeDate($navNotification['date']); + $navNotification['richtext'] = Entity\Notify::formatMessage($navNotification['contact']['name'], $navNotification['message']); + $navNotification['plaintext'] = strip_tags($navNotification['richtext']); + $navNotification['html'] = \Friendica\Core\Renderer::replaceMacros($tpl, [ + 'notify' => $navNotification, + ]); + + return $navNotification; + }, $notifications); $data['sysmsgs'] = [ 'notice' => $sysmsgs, 'info' => $sysmsgs_info @@ -394,14 +399,15 @@ function ping_get_notifications($uid) $result = []; $offset = 0; $seen = false; - $seensql = "NOT"; - $order = "DESC"; + $seensql = 'NOT'; + $order = 'DESC'; $quit = false; do { - $r = DBA::toArray(DBA::p( + $notifies = DBA::toArray(DBA::p( "SELECT `notify`.*, `post`.`visible`, `post`.`deleted` - FROM `notify` LEFT JOIN `post` ON `post`.`uri-id` = `notify`.`uri-id` + FROM `notify` + LEFT JOIN `post` ON `post`.`uri-id` = `notify`.`uri-id` WHERE `notify`.`uid` = ? AND `notify`.`msg` != '' AND NOT (`notify`.`type` IN (?, ?)) AND $seensql `notify`.`seen` ORDER BY `notify`.`date` $order LIMIT ?, 50", @@ -411,48 +417,52 @@ function ping_get_notifications($uid) $offset )); - if (!$r && !$seen) { + if (!$notifies && !$seen) { $seen = true; - $seensql = ""; - $order = "DESC"; + $seensql = ''; + $order = 'DESC'; $offset = 0; - } elseif (!$r) { + } elseif (!$notifies) { $quit = true; } else { $offset += 50; } - foreach ($r as $notification) { - if (is_null($notification["visible"])) { - $notification["visible"] = true; - } + foreach ($notifies as $notify) { + $notify['visible'] = $notify['visible'] ?? true; + $notify['deleted'] = $notify['deleted'] ?? 0; - if (is_null($notification["deleted"])) { - $notification["deleted"] = 0; - } - - if ($notification["msg_cache"]) { - $notification["name"] = $notification["name_cache"]; - $notification["message"] = $notification["msg_cache"]; + if ($notify['msg_cache']) { + $notify['name'] = $notify['name_cache']; + $notify['message'] = $notify['msg_cache']; } else { - $notification["name"] = strip_tags(BBCode::convert($notification["name"])); - $notification["message"] = \Friendica\Navigation\Notifications\Entity\Notify::formatMessage($notification["name"], BBCode::toPlaintext($notification["msg"])); + $notify['name'] = strip_tags(BBCode::convert($notify['name'])); + $notify['message'] = BBCode::toPlaintext($notify['msg']); // @todo Replace this with a call of the Notify model class - DBA::update('notify', ['name_cache' => $notification["name"], 'msg_cache' => $notification["message"]], ['id' => $notification["id"]]); + DBA::update('notify', ['name_cache' => $notify['name'], 'msg_cache' => $notify['message']], ['id' => $notify['id']]); } - $notification["href"] = DI::baseUrl() . "/notify/" . $notification["id"]; - - if ($notification["visible"] - && !$notification["deleted"] - && empty($result['p:' . $notification['parent']]) + if ($notify['visible'] + && !$notify['deleted'] + && empty($result['p:' . $notify['parent']]) ) { + $notification = [ + 'href' => DI::baseUrl() . '/notify/' . $notify['id'], + 'contact' => [ + 'name' => $notify['name'], + 'url' => $notify['url'], + ], + 'message' => $notify['message'], + 'date' => $notify['date'], + 'seen' => $notify['seen'], + ]; + // Should we condense the notifications or show them all? - if (($notification['verb'] != Activity::POST) || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { + if (($notify['verb'] != Activity::POST) || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { $result[] = $notification; } else { - $result['p:' . $notification['parent']] = $notification; + $result['p:' . $notify['parent']] = $notification; } } } diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index 8f8166ab90..1070440073 100644 --- a/src/Navigation/Notifications/Entity/Notify.php +++ b/src/Navigation/Notifications/Entity/Notify.php @@ -134,16 +134,6 @@ class Notify extends BaseEntity */ public static function formatMessage(string $name, string $message): string { - if ($name != '') { - $pos = strpos($message, $name); - } else { - $pos = false; - } - - if ($pos !== false) { - $message = substr_replace($message, '{0}', $pos, strlen($name)); - } - - return $message; + return str_replace('{0}', '' . strip_tags(BBCode::convert($name)) . '', $message); } } diff --git a/view/js/main.js b/view/js/main.js index d029ec13bc..c4109a8c70 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -239,7 +239,6 @@ $(function() { }); /* notifications template */ - var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); var notifications_all = unescape($('
').append($("#nav-notifications-see-all").clone()).html()); //outerHtml hack var notifications_mark = unescape($('
').append($("#nav-notifications-mark-all").clone()).html()); //outerHtml hack var notifications_empty = unescape($("#nav-notifications-menu").html()); @@ -315,34 +314,20 @@ $(function() { var notification_id = 0; // Insert notifs into the notifications-menu - $(data.notifications).each(function(key, notification) { - var text = notification.message.format('' + notification.name + ''); - var contact = ('' + notification.name + ''); - var seenclass = (notification.seen == 1) ? "notification-seen" : "notification-unseen"; - var html = notifications_tpl.format( - notification.href, // {0} // link to the source - notification.photo, // {1} // photo of the contact - text, // {2} // preformatted text (autor + text) - notification.date, // {3} // date of notification (time ago) - seenclass, // {4} // visited status of the notification - new Date(notification.timestamp*1000), // {5} // date of notification - notification.url, // {6} // profile url of the contact - notification.message.format(contact), // {7} // preformatted html (text including author profile url) - '' // {8} // Deprecated - ); - nnm.append(html); + $(data.notifications).each(function(key, navNotif) { + nnm.append(navNotif.html); }); // Desktop Notifications - $(data.notifications.reverse()).each(function(key, e) { - notification_id = parseInt(e.timestamp); - if (notification_lastitem !== null && notification_id > notification_lastitem && Number(e.seen) === 0) { + $(data.notifications.reverse()).each(function(key, navNotif) { + notification_id = parseInt(navNotif.timestamp); + if (notification_lastitem !== null && notification_id > notification_lastitem && Number(navNotif.seen) === 0) { if (getNotificationPermission() === "granted") { var notification = new Notification(document.title, { - body: decodeHtml(e.message.replace('→ ', '').format(e.name)), - icon: e.photo, - }); - notification['url'] = e.href; + body: decodeHtml(navNotif.plaintext), + icon: navNotif.contact.photo, + }); + notification['url'] = navNotif.href; notification.addEventListener("click", function(ev) { window.location = ev.target.url; }); diff --git a/view/templates/nav.tpl b/view/templates/nav.tpl index fbce697eaf..3c1b9f26b2 100644 --- a/view/templates/nav.tpl +++ b/view/templates/nav.tpl @@ -65,7 +65,3 @@ - - diff --git a/view/templates/notifications/nav/notify.tpl b/view/templates/notifications/nav/notify.tpl new file mode 100644 index 0000000000..dfcf9d3346 --- /dev/null +++ b/view/templates/notifications/nav/notify.tpl @@ -0,0 +1,3 @@ +
  • + {{$notify.richtext nofilter}} {{$notify.ago}} +
  • diff --git a/view/theme/duepuntozero/templates/nav.tpl b/view/theme/duepuntozero/templates/nav.tpl index 85c6b047e7..8e386d5e6a 100644 --- a/view/theme/duepuntozero/templates/nav.tpl +++ b/view/theme/duepuntozero/templates/nav.tpl @@ -67,7 +67,3 @@ - - diff --git a/view/theme/frio/templates/nav.tpl b/view/theme/frio/templates/nav.tpl index 53176fe92c..a8a9b935de 100644 --- a/view/theme/frio/templates/nav.tpl +++ b/view/theme/frio/templates/nav.tpl @@ -461,22 +461,6 @@
    -{{*The second part of the notifications dropdown menu. It handles the notifications *}} -{{if $nav.notifications}} - -{{/if}} - {{* This is the mask of the firefox logo. We set the background of #logo-img to the user icon color and apply this mask to it The result is a friendica logo in the user icon color.*}} diff --git a/view/theme/frio/templates/notifications/nav/notify.tpl b/view/theme/frio/templates/notifications/nav/notify.tpl new file mode 100644 index 0000000000..ab1743d1b9 --- /dev/null +++ b/view/theme/frio/templates/notifications/nav/notify.tpl @@ -0,0 +1,11 @@ +
  • +
    + + + {{$notify.richtext nofilter}} +
    +
    +
    +
  • diff --git a/view/theme/quattro/templates/nav.tpl b/view/theme/quattro/templates/nav.tpl index fc757c9a4d..5ad091408e 100644 --- a/view/theme/quattro/templates/nav.tpl +++ b/view/theme/quattro/templates/nav.tpl @@ -108,8 +108,5 @@ -
    {{$langselector}}
    diff --git a/view/theme/smoothly/templates/nav.tpl b/view/theme/smoothly/templates/nav.tpl index 6d8ad1071e..aff22a79ef 100644 --- a/view/theme/smoothly/templates/nav.tpl +++ b/view/theme/smoothly/templates/nav.tpl @@ -58,10 +58,6 @@ - -
    {{$langselector}}