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/Addons.md b/doc/Addons.md index 7c9b89d342..ce8412547a 100644 --- a/doc/Addons.md +++ b/doc/Addons.md @@ -719,10 +719,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('personal_xrd', $arr); -### mod/ping.php - - Hook::callAll('network_ping', $arr); - ### mod/parse_url.php Hook::callAll("parse_link", $arr); @@ -865,6 +861,10 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('register_account', $uid); Hook::callAll('remove_user', $user); +### src/Module/Notifications/Ping.php + + Hook::callAll('network_ping', $arr); + ### src/Module/PermissionTooltip.php Hook::callAll('lockview_content', $item); 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/doc/de/Addons.md b/doc/de/Addons.md index 3381ef48f1..32e69a2fd7 100644 --- a/doc/de/Addons.md +++ b/doc/de/Addons.md @@ -236,10 +236,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('personal_xrd', $arr); -### mod/ping.php - - Hook::callAll('network_ping', $arr); - ### mod/parse_url.php Hook::callAll("parse_link", $arr); @@ -426,6 +422,10 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('storage_instance', $data); Hook::callAll('storage_config', $data); +### src/Module/Notifications/Ping.php + + Hook::callAll('network_ping', $arr); + ### src/Module/PermissionTooltip.php Hook::callAll('lockview_content', $item); diff --git a/mod/ping.php b/mod/ping.php deleted file mode 100644 index 1afab5f726..0000000000 --- a/mod/ping.php +++ /dev/null @@ -1,531 +0,0 @@ -. - * - */ - -use Friendica\App; -use Friendica\Content\ForumManager; -use Friendica\Content\Text\BBCode; -use Friendica\Core\Cache\Enum\Duration; -use Friendica\Core\Hook; -use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Model\Contact; -use Friendica\Model\Group; -use Friendica\Model\Notification; -use Friendica\Model\Post; -use Friendica\Model\Verb; -use Friendica\Protocol\Activity; -use Friendica\Util\DateTimeFormat; -use Friendica\Util\Proxy; -use Friendica\Util\Temporal; -use Friendica\Util\XML; - -/** - * Outputs the counts and the lists of various notifications - * - * The output format can be controlled via the GET parameter 'format'. It can be - * - xml (deprecated legacy default) - * - json (outputs JSONP with the 'callback' GET parameter) - * - * Expected JSON structure: - * { - * "result": { - * "intro": 0, - * "mail": 0, - * "net": 0, - * "home": 0, - * "register": 0, - * "all-events": 0, - * "all-events-today": 0, - * "events": 0, - * "events-today": 0, - * "birthdays": 0, - * "birthdays-today": 0, - * "groups": [ ], - * "forums": [ ], - * "notification": 0, - * "notifications": [ ], - * "sysmsgs": { - * "notice": [ ], - * "info": [ ] - * } - * } - * } - * - * @param App $a The Friendica App instance - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ -function ping_init(App $a) -{ - $format = 'xml'; - - if (isset($_GET['format']) && $_GET['format'] == 'json') { - $format = 'json'; - } - - $regs = []; - $notifications = []; - - $intro_count = 0; - $mail_count = 0; - $home_count = 0; - $network_count = 0; - $register_count = 0; - $sysnotify_count = 0; - $groups_unseen = []; - $forums_unseen = []; - - $all_events = 0; - $all_events_today = 0; - $events = 0; - $events_today = 0; - $birthdays = 0; - $birthdays_today = 0; - - $data = []; - $data['intro'] = $intro_count; - $data['mail'] = $mail_count; - $data['net'] = $network_count; - $data['home'] = $home_count; - $data['register'] = $register_count; - - $data['all-events'] = $all_events; - $data['all-events-today'] = $all_events_today; - $data['events'] = $events; - $data['events-today'] = $events_today; - $data['birthdays'] = $birthdays; - $data['birthdays-today'] = $birthdays_today; - - if (local_user()) { - // Different login session than the page that is calling us. - if (!empty($_GET['uid']) && intval($_GET['uid']) != local_user()) { - $data = ['result' => ['invalid' => 1]]; - - if ($format == 'json') { - if (isset($_GET['callback'])) { - // JSONP support - header("Content-type: application/javascript"); - echo $_GET['callback'] . '(' . json_encode($data) . ')'; - } else { - header("Content-type: application/json"); - echo json_encode($data); - } - } else { - header("Content-type: text/xml"); - echo XML::fromArray($data, $xml); - } - exit(); - } - - $notifications = ping_get_notifications(local_user()); - - $condition = ["`unseen` AND `uid` = ? AND NOT `origin` AND (`vid` != ? OR `vid` IS NULL)", - local_user(), Verb::getID(Activity::FOLLOW)]; - $items = Post::selectForUser(local_user(), ['wall', 'uid', 'uri-id'], $condition, ['limit' => 1000]); - if (DBA::isResult($items)) { - $items_unseen = Post::toArray($items, false); - $arr = ['items' => $items_unseen]; - Hook::callAll('network_ping', $arr); - - foreach ($items_unseen as $item) { - if ($item['wall']) { - $home_count++; - } else { - $network_count++; - } - } - } - DBA::close($items); - - if ($network_count) { - // Find out how unseen network posts are spread across groups - $group_counts = Group::countUnseen(); - if (DBA::isResult($group_counts)) { - foreach ($group_counts as $group_count) { - if ($group_count['count'] > 0) { - $groups_unseen[] = $group_count; - } - } - } - - $forum_counts = ForumManager::countUnseenItems(); - if (DBA::isResult($forum_counts)) { - foreach ($forum_counts as $forum_count) { - if ($forum_count['count'] > 0) { - $forums_unseen[] = $forum_count; - } - } - } - } - - $intros1 = DBA::toArray(DBA::p( - "SELECT `intro`.`id`, `intro`.`datetime`, - `contact`.`name`, `contact`.`url`, `contact`.`photo` - FROM `intro` INNER JOIN `contact` ON `intro`.`suggest-cid` = `contact`.`id` - WHERE `intro`.`uid` = ? AND NOT `intro`.`blocked` AND NOT `intro`.`ignore` AND `intro`.`suggest-cid` != 0", - local_user() - )); - $intros2 = DBA::toArray(DBA::p( - "SELECT `intro`.`id`, `intro`.`datetime`, - `contact`.`name`, `contact`.`url`, `contact`.`photo` - FROM `intro` INNER JOIN `contact` ON `intro`.`contact-id` = `contact`.`id` - WHERE `intro`.`uid` = ? AND NOT `intro`.`blocked` AND NOT `intro`.`ignore` AND `intro`.`contact-id` != 0 AND (`intro`.`suggest-cid` = 0 OR `intro`.`suggest-cid` IS NULL)", - local_user() - )); - - $intro_count = count($intros1) + count($intros2); - $intros = $intros1 + $intros2; - - $myurl = DI::baseUrl() . '/profile/' . $a->getLoggedInUserNickname(); - $mail_count = DBA::count('mail', ["`uid` = ? AND NOT `seen` AND `from-url` != ?", local_user(), $myurl]); - - if (intval(DI::config()->get('config', 'register_policy')) === \Friendica\Module\Register::APPROVE && $a->isSiteAdmin()) { - $regs = Friendica\Model\Register::getPending(); - - if (DBA::isResult($regs)) { - $register_count = count($regs); - } - } - - $cachekey = "ping_init:".local_user(); - $ev = DI::cache()->get($cachekey); - if (is_null($ev)) { - $ev = DBA::selectToArray('event', ['type', 'start'], - ["`uid` = ? AND `start` < ? AND `finish` > ? AND NOT `ignore`", - local_user(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utcNow()]); - if (DBA::isResult($ev)) { - DI::cache()->set($cachekey, $ev, Duration::HOUR); - } - } - - if (DBA::isResult($ev)) { - $all_events = count($ev); - - if ($all_events) { - $str_now = DateTimeFormat::localNow('Y-m-d'); - foreach ($ev as $x) { - $bd = false; - if ($x['type'] === 'birthday') { - $birthdays ++; - $bd = true; - } else { - $events ++; - } - if (DateTimeFormat::local($x['start'], 'Y-m-d') === $str_now) { - $all_events_today ++; - if ($bd) { - $birthdays_today ++; - } else { - $events_today ++; - } - } - } - } - } - - $data['intro'] = $intro_count; - $data['mail'] = $mail_count; - $data['net'] = ($network_count < 1000) ? $network_count : '999+'; - $data['home'] = ($home_count < 1000) ? $home_count : '999+'; - $data['register'] = $register_count; - - $data['all-events'] = $all_events; - $data['all-events-today'] = $all_events_today; - $data['events'] = $events; - $data['events-today'] = $events_today; - $data['birthdays'] = $birthdays; - $data['birthdays-today'] = $birthdays_today; - - if (DBA::isResult($notifications)) { - foreach ($notifications as $notif) { - if ($notif['seen'] == 0) { - $sysnotify_count ++; - } - } - } - - // merge all notification types in one array - if (DBA::isResult($intros)) { - foreach ($intros as $intro) { - $notif = [ - 'id' => 0, - 'href' => DI::baseUrl() . '/notifications/intros/' . $intro['id'], - 'name' => BBCode::convert($intro['name']), - 'url' => $intro['url'], - 'photo' => $intro['photo'], - '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, - 'href' => DI::baseUrl()->get(true) . '/admin/users/pending', - 'name' => $reg['name'], - 'url' => $reg['url'], - 'photo' => $reg['micro'], - 'date' => $reg['created'], - 'seen' => false, - 'message' => DI::l10n()->t('{0} requested registration'), - ]; - $notifications[] = $notif; - } - } else { - $notif = [ - 'id' => 0, - 'href' => DI::baseUrl()->get(true) . '/admin/users/pending', - 'name' => $regs[0]['name'], - 'url' => $regs[0]['url'], - 'photo' => $regs[0]['micro'], - 'date' => $regs[0]['created'], - 'seen' => false, - 'message' => DI::l10n()->t('{0} and %d others requested registration', count($regs) - 1), - ]; - $notifications[] = $notif; - } - } - - // sort notifications by $[]['date'] - $sort_function = function ($a, $b) { - $adate = strtotime($a['date']); - $bdate = strtotime($b['date']); - - // Unseen messages are kept at the top - // The value 31536000 means one year. This should be enough :-) - if (!$a['seen']) { - $adate += 31536000; - } - if (!$b['seen']) { - $bdate += 31536000; - } - - if ($adate == $bdate) { - return 0; - } - 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 = []; - $sysmsgs_info = []; - - if (!empty($_SESSION['sysmsg'])) { - $sysmsgs = $_SESSION['sysmsg']; - unset($_SESSION['sysmsg']); - } - - if (!empty($_SESSION['sysmsg_info'])) { - $sysmsgs_info = $_SESSION['sysmsg_info']; - unset($_SESSION['sysmsg_info']); - } - - if ($format == 'json') { - $notification_count = $sysnotify_count + $intro_count + $register_count; - - $data['groups'] = $groups_unseen; - $data['forums'] = $forums_unseen; - $data['notification'] = ($notification_count < 50) ? $notification_count : '49+'; - $data['notifications'] = $notifications; - $data['sysmsgs'] = [ - 'notice' => $sysmsgs, - 'info' => $sysmsgs_info - ]; - - $json_payload = json_encode(["result" => $data]); - - if (isset($_GET['callback'])) { - // JSONP support - header("Content-type: application/javascript"); - echo $_GET['callback'] . '(' . $json_payload . ')'; - } else { - header("Content-type: application/json"); - echo $json_payload; - } - } else { - // Legacy slower XML format output - $data = ping_format_xml_data($data, $sysnotify_count, $notifications, $sysmsgs, $sysmsgs_info, $groups_unseen, $forums_unseen); - - header("Content-type: text/xml"); - echo XML::fromArray(["result" => $data], $xml); - } - - exit(); -} - -/** - * Retrieves the notifications array for the given user ID - * - * @param int $uid User id - * @return array Associative array of notifications - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ -function ping_get_notifications($uid) -{ - $result = []; - $offset = 0; - $seen = false; - $seensql = "NOT"; - $order = "DESC"; - $quit = false; - - do { - $r = DBA::toArray(DBA::p( - "SELECT `notify`.*, `post`.`visible`, `post`.`deleted` - 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", - $uid, - Notification\Type::INTRO, - Notification\Type::MAIL, - $offset - )); - - if (!$r && !$seen) { - $seen = true; - $seensql = ""; - $order = "DESC"; - $offset = 0; - } elseif (!$r) { - $quit = true; - } else { - $offset += 50; - } - - foreach ($r as $notification) { - if (is_null($notification["visible"])) { - $notification["visible"] = true; - } - - if (is_null($notification["deleted"])) { - $notification["deleted"] = 0; - } - - if ($notification["msg_cache"]) { - $notification["name"] = $notification["name_cache"]; - $notification["message"] = $notification["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"])); - - // @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"]]); - } - - $notification["href"] = DI::baseUrl() . "/notification/" . $notification["id"]; - - if ($notification["visible"] - && !$notification["deleted"] - && empty($result['p:' . $notification['parent']]) - ) { - // Should we condense the notifications or show them all? - if (($notification['verb'] != Activity::POST) || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { - $result[] = $notification; - } else { - $result['p:' . $notification['parent']] = $notification; - } - } - } - } while ((count($result) < 50) && !$quit); - - return($result); -} - -/** - * Backward-compatible XML formatting for ping.php output - * @deprecated - * - * @param array $data The initial ping data array - * @param int $sysnotify_count Number of unseen system notifications - * @param array $notifs Complete list of notification - * @param array $sysmsgs List of system notice messages - * @param array $sysmsgs_info List of system info messages - * @param array $groups_unseen List of unseen group items - * @param array $forums_unseen List of unseen forum items - * - * @return array XML-transform ready data array - */ -function ping_format_xml_data($data, $sysnotify_count, $notifs, $sysmsgs, $sysmsgs_info, $groups_unseen, $forums_unseen) -{ - $notifications = []; - foreach ($notifs as $key => $notif) { - $notifications[$key . ':note'] = $notif['message']; - - $notifications[$key . ':@attributes'] = [ - 'id' => $notif['id'], - 'href' => $notif['href'], - 'name' => $notif['name'], - 'url' => $notif['url'], - 'photo' => $notif['photo'], - 'date' => $notif['date'], - 'seen' => $notif['seen'], - 'timestamp' => $notif['timestamp'] - ]; - } - - $sysmsg = []; - foreach ($sysmsgs as $key => $m) { - $sysmsg[$key . ':notice'] = $m; - } - foreach ($sysmsgs_info as $key => $m) { - $sysmsg[$key . ':info'] = $m; - } - - $data['notif'] = $notifications; - $data['@attributes'] = ['count' => $sysnotify_count + $data['intro'] + $data['mail'] + $data['register']]; - $data['sysmsgs'] = $sysmsg; - - if ($data['register'] == 0) { - unset($data['register']); - } - - $groups = []; - if (count($groups_unseen)) { - foreach ($groups_unseen as $key => $item) { - $groups[$key . ':group'] = $item['count']; - $groups[$key . ':@attributes'] = ['id' => $item['id']]; - } - $data['groups'] = $groups; - } - - $forums = []; - if (count($forums_unseen)) { - foreach ($forums_unseen as $key => $item) { - $forums[$key . ':forum'] = $item['count']; - $forums[$key . ':@attributes'] = ['id' => $item['id']]; - } - $data['forums'] = $forums; - } - - return $data; -} diff --git a/src/Core/System.php b/src/Core/System.php index de0c80b3de..16bc2360ef 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -334,9 +334,10 @@ class System * and adds an application/json HTTP header to the output. * After finishing the process is getting killed. * - * @param mixed $x The input content. - * @param string $content_type Type of the input (Default: 'application/json'). - * @param integer $options JSON options + * @param mixed $x The input content + * @param string $content_type Type of the input (Default: 'application/json') + * @param integer $options JSON options + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function jsonExit($x, $content_type = 'application/json', int $options = 0) { DI::apiResponse()->setType(Response::TYPE_JSON, $content_type); diff --git a/src/DI.php b/src/DI.php index 708fb7d836..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); @@ -527,9 +532,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/Model/Contact.php b/src/Model/Contact.php index f0be457722..e1152b4081 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -2617,7 +2617,7 @@ class Contact return false; } - $fields = ['url', 'name', 'nick', 'avatar', 'photo', 'network', 'blocked']; + $fields = ['id', 'url', 'name', 'nick', 'avatar', 'photo', 'network', 'blocked']; $pub_contact = DBA::selectFirst('contact', $fields, ['id' => $datarray['author-id']]); if (!DBA::isResult($pub_contact)) { // Should never happen @@ -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, @@ -2764,6 +2762,10 @@ class Contact } else { DI::logger()->info('Couldn\'t remove follower because of invalid contact array', ['contact' => $contact, 'callstack' => System::callstack()]); } + + $cdata = Contact::getPublicAndUserContactID($contact['id'], $contact['uid']); + + DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]); } /** 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/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/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/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/Module/Notifications/Ping.php b/src/Module/Notifications/Ping.php new file mode 100644 index 0000000000..50c8232032 --- /dev/null +++ b/src/Module/Notifications/Ping.php @@ -0,0 +1,287 @@ +. + * + */ + +namespace Friendica\Module\Notifications; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Contact\Introduction\Repository\Introduction; +use Friendica\Content\ForumManager; +use Friendica\Core\Cache\Enum\Duration; +use Friendica\Core\Hook; +use Friendica\Core\L10n; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Group; +use Friendica\Model\Post; +use Friendica\Model\Verb; +use Friendica\Module\Register; +use Friendica\Module\Response; +use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\Factory; +use Friendica\Navigation\Notifications\Repository; +use Friendica\Navigation\Notifications\ValueObject; +use Friendica\Protocol\Activity; +use Friendica\Util\DateTimeFormat; +use Friendica\Util\Profiler; +use GuzzleHttp\Psr7\Uri; +use Psr\Log\LoggerInterface; + +class Ping extends BaseModule +{ + /** @var Repository\Notification */ + private $notificationRepo; + /** @var Introduction */ + private $introductionRepo; + /** @var Factory\FormattedNavNotification */ + private $formattedNavNotification; + + public function __construct(Repository\Notification $notificationRepo, Introduction $introductionRepo, Factory\FormattedNavNotification $formattedNavNotification, 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->notificationRepo = $notificationRepo; + $this->introductionRepo = $introductionRepo; + $this->formattedNavNotification = $formattedNavNotification; + } + + protected function rawContent(array $request = []) + { + $regs = []; + $navNotifications = []; + + $intro_count = 0; + $mail_count = 0; + $home_count = 0; + $network_count = 0; + $register_count = 0; + $sysnotify_count = 0; + $groups_unseen = []; + $forums_unseen = []; + + $event_count = 0; + $today_event_count = 0; + $birthday_count = 0; + $today_birthday_count = 0; + + + if (local_user()) { + if (DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { + $notifications = $this->notificationRepo->selectForUser(local_user(), [], ['limit' => 50]); + } else { + $notifications = $this->notificationRepo->selectDigestForUser(local_user()); + } + + $condition = [ + "`unseen` AND `uid` = ? AND NOT `origin` AND (`vid` != ? OR `vid` IS NULL)", + local_user(), Verb::getID(Activity::FOLLOW) + ]; + $items = Post::selectForUser(local_user(), ['wall', 'uid', 'uri-id'], $condition, ['limit' => 1000]); + if (DBA::isResult($items)) { + $items_unseen = Post::toArray($items, false); + $arr = ['items' => $items_unseen]; + Hook::callAll('network_ping', $arr); + + foreach ($items_unseen as $item) { + if ($item['wall']) { + $home_count++; + } else { + $network_count++; + } + } + } + DBA::close($items); + + if ($network_count) { + // Find out how unseen network posts are spread across groups + $group_counts = Group::countUnseen(); + if (DBA::isResult($group_counts)) { + foreach ($group_counts as $group_count) { + if ($group_count['count'] > 0) { + $groups_unseen[] = $group_count; + } + } + } + + $forum_counts = ForumManager::countUnseenItems(); + if (DBA::isResult($forum_counts)) { + foreach ($forum_counts as $forum_count) { + if ($forum_count['count'] > 0) { + $forums_unseen[] = $forum_count; + } + } + } + } + + $intros = $this->introductionRepo->selectForUser(local_user()); + + $intro_count = $intros->count(); + + $myurl = DI::baseUrl() . '/profile/' . DI::app()->getLoggedInUserNickname(); + $mail_count = DBA::count('mail', ["`uid` = ? AND NOT `seen` AND `from-url` != ?", local_user(), $myurl]); + + if (intval(DI::config()->get('config', 'register_policy')) === Register::APPROVE && DI::app()->isSiteAdmin()) { + $regs = \Friendica\Model\Register::getPending(); + + if (DBA::isResult($regs)) { + $register_count = count($regs); + } + } + + $cachekey = 'ping:events:' . local_user(); + $ev = DI::cache()->get($cachekey); + if (is_null($ev)) { + $ev = DBA::selectToArray('event', ['type', 'start'], + ["`uid` = ? AND `start` < ? AND `finish` > ? AND NOT `ignore`", + local_user(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utcNow()]); + if (DBA::isResult($ev)) { + DI::cache()->set($cachekey, $ev, Duration::HOUR); + } + } + + if (DBA::isResult($ev)) { + $all_events = count($ev); + + if ($all_events) { + $str_now = DateTimeFormat::localNow('Y-m-d'); + foreach ($ev as $x) { + $bd = false; + if ($x['type'] === 'birthday') { + $birthday_count++; + $bd = true; + } else { + $event_count++; + } + if (DateTimeFormat::local($x['start'], 'Y-m-d') === $str_now) { + if ($bd) { + $today_birthday_count++; + } else { + $today_event_count++; + } + } + } + } + } + + $sysnotify_count = $notifications->countUnseen(); + + $navNotifications = array_map(function (Entity\Notification $notification) { + return $this->formattedNavNotification->createFromNotification($notification); + }, $notifications->getArrayCopy()); + + // merge all notification types in one array + foreach ($intros as $intro) { + $navNotifications[] = $this->formattedNavNotification->createFromIntro($intro); + } + + if (DBA::isResult($regs)) { + if (count($regs) <= 1 || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) { + foreach ($regs as $reg) { + $navNotifications[] = $this->formattedNavNotification->createFromParams( + [ + 'name' => $reg['name'], + 'url' => $reg['url'], + ], + DI::l10n()->t('{0} requested registration'), + new \DateTime($reg['created'], new \DateTimeZone('UTC')), + new Uri(DI::baseUrl()->get(true) . '/admin/users/pending') + ); + } + } else { + $navNotifications[] = $this->formattedNavNotification->createFromParams( + [ + 'name' => $regs[0]['name'], + 'url' => $regs[0]['url'], + ], + DI::l10n()->t('{0} and %d others requested registration', count($regs) - 1), + new \DateTime($regs[0]['created'], new \DateTimeZone('UTC')), + new Uri(DI::baseUrl()->get(true) . '/admin/users/pending') + ); + } + } + + // sort notifications by $[]['date'] + $sort_function = function (ValueObject\FormattedNavNotification $a, ValueObject\FormattedNavNotification $b) { + $a = $a->toArray(); + $b = $b->toArray(); + + // Unseen messages are kept at the top + if ($a['seen'] == $b['seen']) { + if ($a['timestamp'] == $b['timestamp']) { + return 0; + } else { + return $a['timestamp'] < $b['timestamp'] ? 1 : -1; + } + } else { + return $a['seen'] ? 1 : -1; + } + }; + usort($navNotifications, $sort_function); + } + + $sysmsgs = []; + $sysmsgs_info = []; + + if (!empty($_SESSION['sysmsg'])) { + $sysmsgs = $_SESSION['sysmsg']; + unset($_SESSION['sysmsg']); + } + + if (!empty($_SESSION['sysmsg_info'])) { + $sysmsgs_info = $_SESSION['sysmsg_info']; + unset($_SESSION['sysmsg_info']); + } + + $notification_count = $sysnotify_count + $intro_count + $register_count; + + $data = []; + $data['intro'] = $intro_count; + $data['mail'] = $mail_count; + $data['net'] = ($network_count < 1000) ? $network_count : '999+'; + $data['home'] = ($home_count < 1000) ? $home_count : '999+'; + $data['register'] = $register_count; + + $data['events'] = $event_count; + $data['events-today'] = $today_event_count; + $data['birthdays'] = $birthday_count; + $data['birthdays-today'] = $today_birthday_count; + $data['groups'] = $groups_unseen; + $data['forums'] = $forums_unseen; + $data['notification'] = ($notification_count < 50) ? $notification_count : '49+'; + + $data['notifications'] = $navNotifications; + + $data['sysmsgs'] = [ + 'notice' => $sysmsgs, + 'info' => $sysmsgs_info + ]; + + if (isset($_GET['callback'])) { + // JSONP support + header("Content-type: application/javascript"); + echo $_GET['callback'] . '(' . json_encode(['result' => $data]) . ')'; + exit; + } else { + System::jsonExit(['result' => $data]); + } + } +} 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/Collection/Notifications.php b/src/Navigation/Notifications/Collection/Notifications.php index 3dd3775d04..c1ad8bbbf7 100644 --- a/src/Navigation/Notifications/Collection/Notifications.php +++ b/src/Navigation/Notifications/Collection/Notifications.php @@ -47,4 +47,11 @@ class Notifications extends BaseCollection $Notification->setDismissed(); }); } + + public function countUnseen(): int + { + return array_reduce($this->getArrayCopy(), function (int $carry, Entity\Notification $Notification) { + return $carry + ($Notification->seen ? 0 : 1); + }, 0); + } } 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/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index bf47bdafc6..1070440073 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 { @@ -132,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/src/Navigation/Notifications/Factory/FormattedNavNotification.php b/src/Navigation/Notifications/Factory/FormattedNavNotification.php new file mode 100644 index 0000000000..a9498eaa58 --- /dev/null +++ b/src/Navigation/Notifications/Factory/FormattedNavNotification.php @@ -0,0 +1,127 @@ +. + * + */ + +namespace Friendica\Navigation\Notifications\Factory; + +use Friendica\BaseFactory; +use Friendica\Core\Renderer; +use Friendica\Model\Contact; +use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\ValueObject; +use Friendica\Util\DateTimeFormat; +use Friendica\Util\Proxy; +use Friendica\Util\Temporal; +use GuzzleHttp\Psr7\Uri; +use Psr\Log\LoggerInterface; + +/** + * Factory for creating notification objects based on items + */ +class FormattedNavNotification extends BaseFactory +{ + private static $contacts = []; + + /** @var Notification */ + private $notification; + /** @var \Friendica\App\BaseURL */ + private $baseUrl; + /** @var \Friendica\Core\L10n */ + private $l10n; + /** @var string */ + private $tpl; + + public function __construct(Notification $notification, \Friendica\App\BaseURL $baseUrl, \Friendica\Core\L10n $l10n, LoggerInterface $logger) + { + parent::__construct($logger); + + $this->notification = $notification; + $this->baseUrl = $baseUrl; + $this->l10n = $l10n; + + $this->tpl = Renderer::getMarkupTemplate('notifications/nav/notify.tpl'); + } + + /** + * @param array $contact A contact array with the following keys: name, url + * @param string $message A notification message with the {0} placeholder for the contact name + * @param \DateTime $date + * @param Uri $href + * @param bool $seen + * @return ValueObject\FormattedNavNotification + * @throws \Friendica\Network\HTTPException\ServiceUnavailableException + */ + public function createFromParams(array $contact, string $message, \DateTime $date, Uri $href, bool $seen = false): ValueObject\FormattedNavNotification + { + $contact['photo'] = Contact::getAvatarUrlForUrl($contact['url'], local_user(), Proxy::SIZE_MICRO); + + $dateMySQL = $date->format(DateTimeFormat::MYSQL); + + $templateNotify = [ + 'contact' => $contact, + 'href' => $href->__toString(), + 'message' => $message, + 'seen' => $seen, + 'localdate' => DateTimeFormat::local($dateMySQL), + 'ago' => Temporal::getRelativeDate($dateMySQL), + 'richtext' => Entity\Notify::formatMessage($contact['name'], $message), + ]; + + return new ValueObject\FormattedNavNotification( + $contact, + $date->getTimestamp(), + strip_tags($templateNotify['richtext']), + Renderer::replaceMacros($this->tpl, ['notify' => $templateNotify]), + $href, + $seen, + ); + } + + public function createFromNotification(Entity\Notification $notification): ValueObject\FormattedNavNotification + { + $message = $this->notification->getMessageFromNotification($notification); + + if (!isset(self::$contacts[$notification->actorId])) { + self::$contacts[$notification->actorId] = Contact::getById($notification->actorId, ['name', 'url']); + } + + return $this->createFromParams( + self::$contacts[$notification->actorId], + $message['notification'], + $notification->created, + new Uri($this->baseUrl->get() . '/notification/' . $notification->id), + $notification->seen, + ); + } + + public function createFromIntro(\Friendica\Contact\Introduction\Entity\Introduction $intro): ValueObject\FormattedNavNotification + { + if (!isset(self::$contacts[$intro->cid])) { + self::$contacts[$intro->cid] = Contact::getById($intro->cid, ['name', 'url']); + } + + return $this->createFromParams( + self::$contacts[$intro->cid], + $this->l10n->t('{0}} wants to follow you'), + new \DateTime($intro->datetime, new \DateTimeZone('UTC')), + new Uri($this->baseUrl->get() . '/notifications/intros/' . $intro->id) + ); + } +} diff --git a/src/Navigation/Notifications/Factory/FormattedNotification.php b/src/Navigation/Notifications/Factory/FormattedNotify.php similarity index 91% rename from src/Navigation/Notifications/Factory/FormattedNotification.php rename to src/Navigation/Notifications/Factory/FormattedNotify.php index f1df3c173b..d4aba639c5 100644 --- a/src/Navigation/Notifications/Factory/FormattedNotification.php +++ b/src/Navigation/Notifications/Factory/FormattedNotify.php @@ -31,7 +31,7 @@ use Friendica\Database\Database; use Friendica\Model\Contact; use Friendica\Model\Post; use Friendica\Module\BaseNotifications; -use Friendica\Navigation\Notifications\Collection\FormattedNotifications; +use Friendica\Navigation\Notifications\Collection\FormattedNotifies; use Friendica\Navigation\Notifications\Repository; use Friendica\Navigation\Notifications\ValueObject; use Friendica\Network\HTTPException\InternalServerErrorException; @@ -49,8 +49,10 @@ use Psr\Log\LoggerInterface; * - system * - home * - personal + * + * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Factory\FormattedNotification instead */ -class FormattedNotification extends BaseFactory +class FormattedNotify extends BaseFactory { /** @var Database */ private $dba; @@ -61,12 +63,12 @@ class FormattedNotification extends BaseFactory /** @var L10n */ private $l10n; - public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notify, BaseURL $baseUrl, L10n $l10n) + public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notification, BaseURL $baseUrl, L10n $l10n) { parent::__construct($logger); $this->dba = $dba; - $this->notify = $notify; + $this->notify = $notification; $this->baseUrl = $baseUrl; $this->l10n = $l10n; } @@ -74,14 +76,14 @@ class FormattedNotification extends BaseFactory /** * @param array $formattedItem The return of $this->formatItem * - * @return ValueObject\FormattedNotification + * @return ValueObject\FormattedNotify */ - private function createFromFormattedItem(array $formattedItem): ValueObject\FormattedNotification + 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\FormattedNotification( + return new ValueObject\FormattedNotify( 'like', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -93,7 +95,7 @@ class FormattedNotification extends BaseFactory ); case Activity::DISLIKE: - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'dislike', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -105,7 +107,7 @@ class FormattedNotification extends BaseFactory ); case Activity::ATTEND: - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'attend', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -117,7 +119,7 @@ class FormattedNotification extends BaseFactory ); case Activity::ATTENDNO: - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'attendno', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -129,7 +131,7 @@ class FormattedNotification extends BaseFactory ); case Activity::ATTENDMAYBE: - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'attendmaybe', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -142,7 +144,7 @@ class FormattedNotification extends BaseFactory case Activity::FRIEND: if (!isset($formattedItem['object'])) { - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'friend', $formattedItem['link'], $formattedItem['image'], @@ -159,7 +161,7 @@ class FormattedNotification extends BaseFactory $formattedItem['fname'] = $obj->title; - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( 'friend', $this->baseUrl->get(true) . '/display/' . $formattedItem['parent-guid'], $formattedItem['author-avatar'], @@ -171,7 +173,7 @@ class FormattedNotification extends BaseFactory ); default: - return new ValueObject\FormattedNotification( + return new ValueObject\FormattedNotify( $formattedItem['label'] ?? '', $formattedItem['link'] ?? '', $formattedItem['image'] ?? '', @@ -192,9 +194,9 @@ class FormattedNotification extends BaseFactory * @param int $start Start the query at this point * @param int $limit Maximum number of query results * - * @return FormattedNotifications + * @return FormattedNotifies */ - public function getSystemList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifications + public function getSystemList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies { $conditions = []; if (!$seen) { @@ -205,14 +207,14 @@ class FormattedNotification extends BaseFactory $params['order'] = ['date' => 'DESC']; $params['limit'] = [$start, $limit]; - $formattedNotifications = new FormattedNotifications(); + $formattedNotifications = new FormattedNotifies(); try { $Notifies = $this->notify->selectForUser(local_user(), $conditions, $params); foreach ($Notifies as $Notify) { - $formattedNotifications[] = new ValueObject\FormattedNotification( + $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)), @@ -236,9 +238,9 @@ class FormattedNotification extends BaseFactory * @param int $start Start the query at this point * @param int $limit Maximum number of query results * - * @return FormattedNotifications + * @return FormattedNotifies */ - public function getNetworkList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifications + public function getNetworkList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies { $condition = ['wall' => false, 'uid' => local_user()]; @@ -250,7 +252,7 @@ class FormattedNotification extends BaseFactory 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; - $formattedNotifications = new FormattedNotifications(); + $formattedNotifications = new FormattedNotifies(); try { $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); @@ -272,9 +274,9 @@ class FormattedNotification extends BaseFactory * @param int $start Start the query at this point * @param int $limit Maximum number of query results * - * @return FormattedNotifications + * @return FormattedNotifies */ - public function getPersonalList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifications + 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()]; @@ -286,7 +288,7 @@ class FormattedNotification extends BaseFactory 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; - $formattedNotifications = new FormattedNotifications(); + $formattedNotifications = new FormattedNotifies(); try { $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); @@ -308,9 +310,9 @@ class FormattedNotification extends BaseFactory * @param int $start Start the query at this point * @param int $limit Maximum number of query results * - * @return FormattedNotifications + * @return FormattedNotifies */ - public function getHomeList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifications + public function getHomeList(bool $seen = false, int $start = 0, int $limit = BaseNotifications::DEFAULT_PAGE_LIMIT): FormattedNotifies { $condition = ['wall' => true, 'uid' => local_user()]; @@ -322,7 +324,7 @@ class FormattedNotification extends BaseFactory 'network', 'created', 'object', 'parent-author-name', 'parent-author-link', 'parent-guid', 'gravity']; $params = ['order' => ['received' => true], 'limit' => [$start, $limit]]; - $formattedNotifications = new FormattedNotifications(); + $formattedNotifications = new FormattedNotifies(); try { $userPosts = Post::selectForUser(local_user(), $fields, $condition, $params); diff --git a/src/Navigation/Notifications/Factory/Notification.php b/src/Navigation/Notifications/Factory/Notification.php index 7cc17f8fe3..b404ad8671 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 has 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/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/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index c4035663b0..290845645a 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); } /** @@ -100,6 +100,36 @@ class Notification extends BaseRepository return $this->select($condition, $params); } + /** + * Returns only the most recent notifications for the same conversation or contact + * + * @param int $uid + * @return Collection\Notifications + * @throws Exception + */ + public function selectDigestForUser(int $uid): Collection\Notifications + { + $rows = $this->db->p(" + SELECT notification.* + FROM notification + WHERE id IN ( + SELECT MAX(`id`) + FROM notification + WHERE uid = ? + GROUP BY IFNULL(`parent-uri-id`, `actor-id`) + ) + ORDER BY `seen`, `id` DESC + LIMIT 50 + ", $uid); + + $Entities = new Collection\Notifications(); + foreach ($rows as $fields) { + $Entities[] = $this->factory->createFromTableRow($fields); + } + + return $Entities; + } + public function selectAllForUser(int $uid): Collection\Notifications { return $this->selectForUser($uid); @@ -165,4 +195,14 @@ class Notification extends BaseRepository return $Notification; } + + public function deleteForUserByVerb(int $uid, string $verb, array $condition = []): bool + { + $condition['uid'] = $uid; + $condition['vid'] = Verb::getID($verb); + + $this->logger->notice('deleteForUserByVerb', ['condition' => $condition]); + + return $this->db->delete(self::$table_name, $condition); + } } diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 6d56258b37..9773b6446a 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 */ @@ -567,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; } @@ -729,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/Navigation/Notifications/ValueObject/FormattedNavNotification.php b/src/Navigation/Notifications/ValueObject/FormattedNavNotification.php new file mode 100644 index 0000000000..4a11fa616f --- /dev/null +++ b/src/Navigation/Notifications/ValueObject/FormattedNavNotification.php @@ -0,0 +1,61 @@ +. + * + */ + +namespace Friendica\Navigation\Notifications\ValueObject; + +use Friendica\BaseDataTransferObject; + +/** + * A view-only object for printing item notifications to the frontend + */ +class FormattedNavNotification extends BaseDataTransferObject +{ + /** @var array */ + protected $contact; + /** @var string */ + protected $timestamp; + /** @var string */ + protected $plaintext; + /** @var string */ + protected $html; + /** @var string */ + protected $href; + /** @var bool */ + protected $seen; + + /** + * @param array $contact Contact array with the following keys: name, url, photo + * @param string $timestamp Unix timestamp + * @param string $plaintext Localized notification message with the placeholder replaced by the contact name + * @param string $html Full HTML string of the notification menu element + * @param string $href Absolute URL this notification should send the user to when interacted with + * @param bool $seen Whether the user interacted with this notification once + */ + public function __construct(array $contact, string $timestamp, string $plaintext, string $html, string $href, bool $seen) + { + $this->contact = $contact; + $this->timestamp = $timestamp; + $this->plaintext = $plaintext; + $this->html = $html; + $this->href = $href; + $this->seen = $seen; + } +} diff --git a/src/Navigation/Notifications/ValueObject/FormattedNotification.php b/src/Navigation/Notifications/ValueObject/FormattedNotify.php similarity index 91% rename from src/Navigation/Notifications/ValueObject/FormattedNotification.php rename to src/Navigation/Notifications/ValueObject/FormattedNotify.php index 09d41fa876..ac0db65ad2 100644 --- a/src/Navigation/Notifications/ValueObject/FormattedNotification.php +++ b/src/Navigation/Notifications/ValueObject/FormattedNotify.php @@ -25,8 +25,10 @@ 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 FormattedNotification extends BaseDataTransferObject +class FormattedNotify extends BaseDataTransferObject { const SYSTEM = 'system'; const PERSONAL = 'personal'; 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([ 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" => ""], diff --git a/static/routes.config.php b/static/routes.config.php index e10ec2aedf..c08319eb73 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]], @@ -487,6 +489,7 @@ return [ '/{type}/{customsize:\d+}/{nickname_ext}' => [Module\Photo::class, [R::GET]], ], + '/ping' => [Module\Notifications\Ping::class, [R::GET]], '/pretheme' => [Module\ThemeDetails::class, [R::GET]], '/probe' => [Module\Debug\Probe::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; diff --git a/view/js/main.js b/view/js/main.js index d029ec13bc..93340dc37f 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; }); @@ -514,7 +499,7 @@ function insertBBCodeInTextarea(BBCode, textarea) { function NavUpdate() { if (!stopped) { - var pingCmd = 'ping?format=json' + ((localUser != 0) ? '&uid=' + localUser : ''); + var pingCmd = 'ping'; $.get(pingCmd, function(data) { if (data.result) { // send nav-update event diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index fb4088c559..bdd6c1efaf 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.05-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-03-11 22:56-0500\n" +"POT-Creation-Date: 2022-03-14 08:01-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -131,8 +131,8 @@ msgstr "" #: src/Module/Delegation.php:119 src/Module/FollowConfirm.php:38 #: src/Module/FriendSuggest.php:56 src/Module/Group.php:42 #: src/Module/Group.php:85 src/Module/Invite.php:41 src/Module/Invite.php:130 -#: src/Module/Notifications/Notification.php:48 -#: src/Module/Notifications/Notification.php:79 +#: src/Module/Notifications/Notification.php:75 +#: src/Module/Notifications/Notification.php:106 #: src/Module/Profile/Common.php:56 src/Module/Profile/Contacts.php:56 #: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56 #: src/Module/Register.php:77 src/Module/Register.php:90 @@ -404,7 +404,7 @@ msgstr "" #: mod/photos.php:1342 mod/photos.php:1398 mod/photos.php:1472 #: src/Module/Admin/Item/Source.php:65 src/Module/Contact/Advanced.php:132 #: src/Module/Contact/Poke.php:177 src/Module/Contact/Profile.php:327 -#: src/Module/Debug/ActivityPubConversion.php:141 +#: src/Module/Debug/ActivityPubConversion.php:145 #: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 #: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 #: src/Module/Delegation.php:148 src/Module/FriendSuggest.php:144 @@ -708,7 +708,7 @@ msgstr "" #: mod/message.php:120 src/Module/Notifications/Introductions.php:133 #: src/Module/Notifications/Introductions.php:168 -#: src/Module/Notifications/Notification.php:57 +#: src/Module/Notifications/Notification.php:84 msgid "Discard" msgstr "" @@ -1109,19 +1109,6 @@ msgstr "" msgid "View Album" msgstr "" -#: mod/ping.php:275 -msgid "{0} wants to be your friend" -msgstr "" - -#: mod/ping.php:292 -msgid "{0} requested registration" -msgstr "" - -#: mod/ping.php:305 -#, php-format -msgid "{0} and %d others requested registration" -msgstr "" - #: mod/redir.php:49 mod/redir.php:102 msgid "Bad Request." msgstr "" @@ -1139,7 +1126,7 @@ msgstr "" msgid "Contact not found." msgstr "" -#: mod/removeme.php:63 src/Navigation/Notifications/Repository/Notify.php:473 +#: mod/removeme.php:63 src/Navigation/Notifications/Repository/Notify.php:476 msgid "[Friendica System Notify]" msgstr "" @@ -1176,7 +1163,7 @@ msgstr "" msgid "Resubscribing to OStatus contacts" msgstr "" -#: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:130 +#: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:134 #: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:97 msgid "Error" msgid_plural "Errors" @@ -2773,7 +2760,7 @@ msgstr "" #: src/Module/Contact/Profile.php:349 src/Module/Contact/Profile.php:457 #: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:204 -#: src/Module/Notifications/Notification.php:61 +#: src/Module/Notifications/Notification.php:88 msgid "Ignore" msgstr "" @@ -6979,7 +6966,7 @@ msgstr "" msgid "Babel" msgstr "" -#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:138 +#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:142 msgid "ActivityPub Conversion" msgstr "" @@ -7669,15 +7656,15 @@ msgstr "" msgid "Activity" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:118 +#: src/Module/Debug/ActivityPubConversion.php:122 msgid "Object data" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:125 +#: src/Module/Debug/ActivityPubConversion.php:129 msgid "Result Item" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:139 +#: src/Module/Debug/ActivityPubConversion.php:143 msgid "Source activity" msgstr "" @@ -8502,7 +8489,7 @@ msgstr "" msgid "No more %s notifications." msgstr "" -#: src/Module/Notifications/Notification.php:107 +#: src/Module/Notifications/Notification.php:134 msgid "You must be logged in to show this page." msgstr "" @@ -8526,6 +8513,15 @@ msgstr "" msgid "Show unread" msgstr "" +#: src/Module/Notifications/Ping.php:204 +msgid "{0} requested registration" +msgstr "" + +#: src/Module/Notifications/Ping.php:215 +#, php-format +msgid "{0} and %d others requested registration" +msgstr "" + #: src/Module/OAuth/Acknowledge.php:50 msgid "Authorize application connection" msgstr "" @@ -8678,19 +8674,19 @@ msgstr "" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 #: src/Module/Profile/Status.php:65 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:990 src/Protocol/OStatus.php:1245 +#: src/Protocol/Feed.php:1015 src/Protocol/OStatus.php:1245 #, php-format msgid "%s's timeline" msgstr "" #: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:66 -#: src/Protocol/Feed.php:994 src/Protocol/OStatus.php:1249 +#: src/Protocol/Feed.php:1019 src/Protocol/OStatus.php:1249 #, php-format msgid "%s's posts" msgstr "" #: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:997 src/Protocol/OStatus.php:1252 +#: src/Protocol/Feed.php:1022 src/Protocol/OStatus.php:1252 #, php-format msgid "%s's comments" msgstr "" @@ -9967,43 +9963,47 @@ msgid "" "features and resources." msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:89 +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:122 +msgid "{0}} wants to follow you" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:91 #, php-format msgid "%s liked %s's post" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:101 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:103 #, php-format msgid "%s disliked %s's post" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:113 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:115 #, php-format msgid "%s is attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:125 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:127 #, php-format msgid "%s is not attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:137 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:139 #, php-format msgid "%s may attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:167 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:169 #, php-format msgid "%s is now friends with %s" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:334 -#: src/Navigation/Notifications/Factory/FormattedNotification.php:372 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:336 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:374 #, php-format msgid "%s commented on %s's post" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:371 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:373 #, php-format msgid "%s created a new post" msgstr "" @@ -10020,329 +10020,329 @@ msgstr "" msgid "New Follower" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:93 +#: src/Navigation/Notifications/Factory/Notification.php:119 #, php-format msgid "%1$s wants to follow you" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:95 +#: src/Navigation/Notifications/Factory/Notification.php:121 #, php-format -msgid "%1$s had started following you" +msgid "%1$s has started following you" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:149 +#: src/Navigation/Notifications/Factory/Notification.php:178 #, php-format msgid "%1$s liked your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:152 +#: src/Navigation/Notifications/Factory/Notification.php:181 #, php-format msgid "%1$s liked your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:159 +#: src/Navigation/Notifications/Factory/Notification.php:188 #, php-format msgid "%1$s disliked your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:162 +#: src/Navigation/Notifications/Factory/Notification.php:191 #, php-format msgid "%1$s disliked your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:169 +#: src/Navigation/Notifications/Factory/Notification.php:198 #, php-format msgid "%1$s shared your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:172 +#: src/Navigation/Notifications/Factory/Notification.php:201 #, php-format msgid "%1$s shared your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:176 -#: src/Navigation/Notifications/Factory/Notification.php:245 +#: src/Navigation/Notifications/Factory/Notification.php:205 +#: src/Navigation/Notifications/Factory/Notification.php:274 #, php-format msgid "%1$s shared the post %2$s from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:178 -#: src/Navigation/Notifications/Factory/Notification.php:247 +#: src/Navigation/Notifications/Factory/Notification.php:207 +#: src/Navigation/Notifications/Factory/Notification.php:276 #, php-format msgid "%1$s shared a post from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:180 -#: src/Navigation/Notifications/Factory/Notification.php:249 +#: src/Navigation/Notifications/Factory/Notification.php:209 +#: src/Navigation/Notifications/Factory/Notification.php:278 #, php-format msgid "%1$s shared the post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:182 -#: src/Navigation/Notifications/Factory/Notification.php:251 +#: src/Navigation/Notifications/Factory/Notification.php:211 +#: src/Navigation/Notifications/Factory/Notification.php:280 #, php-format msgid "%1$s shared a post" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:190 +#: src/Navigation/Notifications/Factory/Notification.php:219 #, php-format msgid "%1$s wants to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:197 +#: src/Navigation/Notifications/Factory/Notification.php:226 #, php-format msgid "%1$s does not want to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:204 +#: src/Navigation/Notifications/Factory/Notification.php:233 #, php-format msgid "%1$s maybe wants to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:211 +#: src/Navigation/Notifications/Factory/Notification.php:240 #, php-format msgid "%1$s tagged you on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:215 +#: src/Navigation/Notifications/Factory/Notification.php:244 #, php-format msgid "%1$s replied to you on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:219 +#: src/Navigation/Notifications/Factory/Notification.php:248 #, php-format msgid "%1$s commented in your thread %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:223 +#: src/Navigation/Notifications/Factory/Notification.php:252 #, php-format msgid "%1$s commented on your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:229 +#: src/Navigation/Notifications/Factory/Notification.php:258 #, php-format msgid "%1$s commented in their thread %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:231 +#: src/Navigation/Notifications/Factory/Notification.php:260 #, php-format msgid "%1$s commented in their thread" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:233 +#: src/Navigation/Notifications/Factory/Notification.php:262 #, php-format msgid "%1$s commented in the thread %2$s from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:235 +#: src/Navigation/Notifications/Factory/Notification.php:264 #, php-format msgid "%1$s commented in the thread from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:240 +#: src/Navigation/Notifications/Factory/Notification.php:269 #, php-format msgid "%1$s commented on your thread %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:211 -#: src/Navigation/Notifications/Repository/Notify.php:694 +#: src/Navigation/Notifications/Repository/Notify.php:214 +#: src/Navigation/Notifications/Repository/Notify.php:697 msgid "[Friendica:Notify]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:275 +#: src/Navigation/Notifications/Repository/Notify.php:278 #, php-format msgid "%s New mail received at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:277 +#: src/Navigation/Notifications/Repository/Notify.php:280 #, php-format msgid "%1$s sent you a new private message at %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:278 +#: src/Navigation/Notifications/Repository/Notify.php:281 msgid "a private message" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:278 +#: src/Navigation/Notifications/Repository/Notify.php:281 #, php-format msgid "%1$s sent you %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:280 +#: src/Navigation/Notifications/Repository/Notify.php:283 #, php-format msgid "Please visit %s to view and/or reply to your private messages." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:311 +#: src/Navigation/Notifications/Repository/Notify.php:314 #, php-format msgid "%1$s commented on %2$s's %3$s %4$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:316 +#: src/Navigation/Notifications/Repository/Notify.php:319 #, php-format msgid "%1$s commented on your %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:320 +#: src/Navigation/Notifications/Repository/Notify.php:323 #, php-format msgid "%1$s commented on their %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:324 -#: src/Navigation/Notifications/Repository/Notify.php:729 +#: src/Navigation/Notifications/Repository/Notify.php:327 +#: src/Navigation/Notifications/Repository/Notify.php:732 #, php-format msgid "%1$s Comment to conversation #%2$d by %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:326 +#: src/Navigation/Notifications/Repository/Notify.php:329 #, php-format msgid "%s commented on an item/conversation you have been following." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:330 -#: src/Navigation/Notifications/Repository/Notify.php:345 -#: src/Navigation/Notifications/Repository/Notify.php:364 -#: src/Navigation/Notifications/Repository/Notify.php:744 +#: src/Navigation/Notifications/Repository/Notify.php:333 +#: src/Navigation/Notifications/Repository/Notify.php:348 +#: src/Navigation/Notifications/Repository/Notify.php:367 +#: src/Navigation/Notifications/Repository/Notify.php:747 #, php-format msgid "Please visit %s to view and/or reply to the conversation." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:337 +#: src/Navigation/Notifications/Repository/Notify.php:340 #, php-format msgid "%s %s posted to your profile wall" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:339 +#: src/Navigation/Notifications/Repository/Notify.php:342 #, php-format msgid "%1$s posted to your profile wall at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:343 #, php-format msgid "%1$s posted to [url=%2$s]your wall[/url]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:352 +#: src/Navigation/Notifications/Repository/Notify.php:355 #, php-format msgid "%1$s %2$s poked you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:354 +#: src/Navigation/Notifications/Repository/Notify.php:357 #, php-format msgid "%1$s poked you at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:358 #, php-format msgid "%1$s [url=%2$s]poked you[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:372 +#: src/Navigation/Notifications/Repository/Notify.php:375 #, php-format msgid "%s Introduction received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:377 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:375 +#: src/Navigation/Notifications/Repository/Notify.php:378 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:380 -#: src/Navigation/Notifications/Repository/Notify.php:426 +#: src/Navigation/Notifications/Repository/Notify.php:383 +#: src/Navigation/Notifications/Repository/Notify.php:429 #, php-format msgid "You may visit their profile at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:382 +#: src/Navigation/Notifications/Repository/Notify.php:385 #, php-format msgid "Please visit %s to approve or reject the introduction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:389 +#: src/Navigation/Notifications/Repository/Notify.php:392 #, php-format msgid "%s A new person is sharing with you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:391 -#: src/Navigation/Notifications/Repository/Notify.php:392 +#: src/Navigation/Notifications/Repository/Notify.php:394 +#: src/Navigation/Notifications/Repository/Notify.php:395 #, php-format msgid "%1$s is sharing with you at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:399 +#: src/Navigation/Notifications/Repository/Notify.php:402 #, php-format msgid "%s You have a new follower" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:401 -#: src/Navigation/Notifications/Repository/Notify.php:402 +#: src/Navigation/Notifications/Repository/Notify.php:404 +#: src/Navigation/Notifications/Repository/Notify.php:405 #, php-format msgid "You have a new follower at %2$s : %1$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:415 +#: src/Navigation/Notifications/Repository/Notify.php:418 #, php-format msgid "%s Friend suggestion received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:417 +#: src/Navigation/Notifications/Repository/Notify.php:420 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:418 +#: src/Navigation/Notifications/Repository/Notify.php:421 #, php-format msgid "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:424 +#: src/Navigation/Notifications/Repository/Notify.php:427 msgid "Name:" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:425 +#: src/Navigation/Notifications/Repository/Notify.php:428 msgid "Photo:" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:428 +#: src/Navigation/Notifications/Repository/Notify.php:431 #, php-format msgid "Please visit %s to approve or reject the suggestion." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:436 -#: src/Navigation/Notifications/Repository/Notify.php:451 -#, php-format -msgid "%s Connection accepted" -msgstr "" - -#: src/Navigation/Notifications/Repository/Notify.php:438 -#: src/Navigation/Notifications/Repository/Notify.php:453 -#, php-format -msgid "'%1$s' has accepted your connection request at %2$s" -msgstr "" - #: src/Navigation/Notifications/Repository/Notify.php:439 #: src/Navigation/Notifications/Repository/Notify.php:454 #, php-format +msgid "%s Connection accepted" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:441 +#: src/Navigation/Notifications/Repository/Notify.php:456 +#, php-format +msgid "'%1$s' has accepted your connection request at %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:442 +#: src/Navigation/Notifications/Repository/Notify.php:457 +#, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:444 +#: src/Navigation/Notifications/Repository/Notify.php:447 msgid "" "You are now mutual friends and may exchange status updates, photos, and " "email without restriction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:449 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:459 +#: src/Navigation/Notifications/Repository/Notify.php:462 #, php-format msgid "" "'%1$s' has chosen to accept you a fan, which restricts some forms of " @@ -10351,33 +10351,33 @@ msgid "" "automatically." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:461 +#: src/Navigation/Notifications/Repository/Notify.php:464 #, php-format msgid "" "'%1$s' may choose to extend this into a two-way or more permissive " "relationship in the future." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:463 +#: src/Navigation/Notifications/Repository/Notify.php:466 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:473 +#: src/Navigation/Notifications/Repository/Notify.php:476 msgid "registration request" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:475 +#: src/Navigation/Notifications/Repository/Notify.php:478 #, php-format msgid "You've received a registration request from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:476 +#: src/Navigation/Notifications/Repository/Notify.php:479 #, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:481 +#: src/Navigation/Notifications/Repository/Notify.php:484 #, php-format msgid "" "Full Name:\t%s\n" @@ -10385,17 +10385,17 @@ msgid "" "Login Name:\t%s (%s)" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:487 +#: src/Navigation/Notifications/Repository/Notify.php:490 #, php-format msgid "Please visit %s to approve or reject the request." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:723 +#: src/Navigation/Notifications/Repository/Notify.php:726 #, php-format msgid "%s %s tagged you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:726 +#: src/Navigation/Notifications/Repository/Notify.php:729 #, php-format msgid "%s %s shared a new post" msgstr "" 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}}