X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FPost%2FUserNotification.php;h=dd0bbbe1ecf0249379cfe585cbe089311e7e0978;hb=5f6503a73fabbd65b9ddb1de430b73f472c53dfe;hp=ad7b9c4904b4cb616175e9562b3baedfb9d61d1d;hpb=b6aeb6e903fa14f1345b508224278143ce0d81ea;p=friendica.git diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index ad7b9c4904..dd0bbbe1ec 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -1,6 +1,6 @@ truncateFieldsForTable('post-user-notification', $data); $fields['uri-id'] = $uri_id; $fields['uid'] = $uid; @@ -90,7 +92,7 @@ class UserNotification throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-user-notification', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-user-notification', $data); // Remove the key fields unset($fields['uri-id']); @@ -131,12 +133,18 @@ class UserNotification public static function setNotification(int $uri_id, int $uid) { $fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'vid', 'gravity', - 'private', 'contact-id', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'author-id', 'verb']; + 'contact-id', 'author-id', 'owner-id', 'causer-id', + 'private', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'verb']; $item = Post::selectFirst($fields, ['uri-id' => $uri_id, 'uid' => $uid, 'origin' => false]); if (!DBA::isResult($item)) { return; } + $parent = Post::selectFirstPost(['author-id', 'owner-id', 'causer-id'], ['uri-id' => $item['parent-uri-id']]); + if (!DBA::isResult($parent)) { + return; + } + // "Activity::FOLLOW" is an automated activity, so we ignore it here if ($item['verb'] == Activity::FOLLOW) { return; @@ -159,29 +167,56 @@ class UserNotification DBA::close($users); foreach (array_unique($uids) as $uid) { - self::setNotificationForUser($item, $uid); + self::setNotificationForUser($item, $parent, $uid); } } /** * Checks an item for notifications for the given user and sets the "notification-type" field * - * @param array $item Item array - * @param int $uid User ID + * @param array $item Item array + * @param array $parent Parent item array + * @param int $uid User ID * @throws HTTPException\InternalServerErrorException */ - private static function setNotificationForUser(array $item, int $uid) + private static function setNotificationForUser(array $item, array $parent, int $uid) { if (Post\ThreadUser::getIgnored($item['parent-uri-id'], $uid)) { return; } + foreach (array_unique([$parent['author-id'], $parent['owner-id'], $parent['causer-id'], $item['author-id'], $item['owner-id'], $item['causer-id']]) as $author_id) { + if (empty($author_id)) { + continue; + } + if (Contact\User::isBlocked($author_id, $uid) || Contact\User::isIgnored($author_id, $uid) || Contact\User::isCollapsed($author_id, $uid)) { + Logger::debug('Author is blocked/ignored/collapsed by user', ['uid' => $uid, 'author' => $author_id, 'uri-id' => $item['uri-id']]); + return; + } + } + + $user = User::getById($uid, ['account-type', 'account_removed', 'account_expired']); + if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) { + return; + } + + if ($user['account_removed'] || $user['account_expired']) { + return; + } + + $author = Contact::getById($item['author-id'], ['contact-type']); + if (empty($author)) { + return; + } + $notification_type = self::TYPE_NONE; if (self::checkShared($item, $uid)) { $notification_type = $notification_type | self::TYPE_SHARED; self::insertNotificationByItem(self::TYPE_SHARED, $uid, $item); $notified = true; + } elseif ($author['contact-type'] == Contact::TYPE_COMMUNITY) { + return; } else { $notified = false; } @@ -189,11 +224,16 @@ class UserNotification $profiles = self::getProfileForUser($uid); // Fetch all contacts for the given profiles - $contacts = []; + $contacts = []; + $iscommunity = false; - $ret = DBA::select('contact', ['id'], ['uid' => 0, 'nurl' => $profiles]); + $ret = DBA::select('contact', ['id', 'contact-type'], ['uid' => 0, 'nurl' => $profiles]); while ($contact = DBA::fetch($ret)) { $contacts[] = $contact['id']; + + if ($contact['contact-type'] == Contact::TYPE_COMMUNITY) { + $iscommunity = true; + } } DBA::close($ret); @@ -202,7 +242,7 @@ class UserNotification return; } - if (self::checkExplicitMention($item, $profiles)) { + if (($item['verb'] != Activity::ANNOUNCE) && self::checkExplicitMention($item, $profiles)) { $notification_type = $notification_type | self::TYPE_EXPLICIT_TAGGED; if (!$notified) { self::insertNotificationByItem(self::TYPE_EXPLICIT_TAGGED, $uid, $item); @@ -210,7 +250,7 @@ class UserNotification } } - if (self::checkImplicitMention($item, $profiles)) { + if (($item['verb'] != Activity::ANNOUNCE) && self::checkImplicitMention($item, $profiles)) { $notification_type = $notification_type | self::TYPE_IMPLICIT_TAGGED; if (!$notified) { self::insertNotificationByItem(self::TYPE_IMPLICIT_TAGGED, $uid, $item); @@ -226,7 +266,7 @@ class UserNotification } } - if (self::checkDirectCommentedThread($item, $contacts)) { + if (!$iscommunity && self::checkDirectCommentedThread($item, $contacts)) { $notification_type = $notification_type | self::TYPE_DIRECT_THREAD_COMMENT; if (!$notified) { self::insertNotificationByItem(self::TYPE_DIRECT_THREAD_COMMENT, $uid, $item); @@ -234,7 +274,7 @@ class UserNotification } } - if (self::checkCommentedThread($item, $contacts)) { + if (($item['verb'] != Activity::ANNOUNCE) && self::checkCommentedThread($item, $contacts)) { $notification_type = $notification_type | self::TYPE_THREAD_COMMENT; if (!$notified) { self::insertNotificationByItem(self::TYPE_THREAD_COMMENT, $uid, $item); @@ -242,7 +282,7 @@ class UserNotification } } - if (self::checkCommentedParticipation($item, $contacts)) { + if (($item['verb'] != Activity::ANNOUNCE) && self::checkCommentedParticipation($item, $contacts)) { $notification_type = $notification_type | self::TYPE_COMMENT_PARTICIPATION; if (!$notified) { self::insertNotificationByItem(self::TYPE_COMMENT_PARTICIPATION, $uid, $item); @@ -250,7 +290,23 @@ class UserNotification } } - if (self::checkActivityParticipation($item, $contacts)) { + if (($item['verb'] != Activity::ANNOUNCE) && self::checkQuoted($item, $contacts)) { + $notification_type = $notification_type | self::TYPE_QUOTED; + if (!$notified) { + self::insertNotificationByItem(self::TYPE_QUOTED, $uid, $item); + $notified = true; + } + } + + if (($item['verb'] != Activity::ANNOUNCE) && self::checkFollowParticipation($item, $contacts)) { + $notification_type = $notification_type | self::TYPE_FOLLOW; + if (!$notified) { + self::insertNotificationByItem(self::TYPE_FOLLOW, $uid, $item); + $notified = true; + } + } + + if (($item['verb'] != Activity::ANNOUNCE) && self::checkActivityParticipation($item, $contacts)) { $notification_type = $notification_type | self::TYPE_ACTIVITY_PARTICIPATION; if (!$notified) { self::insertNotificationByItem(self::TYPE_ACTIVITY_PARTICIPATION, $uid, $item); @@ -262,7 +318,7 @@ class UserNotification } // Only create notifications for posts and comments, not for activities - if (($item['gravity'] == GRAVITY_ACTIVITY) && ($item['verb'] != Activity::ANNOUNCE)) { + if (($item['gravity'] == Item::GRAVITY_ACTIVITY) && ($item['verb'] != Activity::ANNOUNCE)) { return; } @@ -284,18 +340,18 @@ class UserNotification */ private static function insertNotificationByItem(int $type, int $uid, array $item): void { - if (($item['verb'] != Activity::ANNOUNCE) && ($item['gravity'] == GRAVITY_ACTIVITY) && + if (($item['verb'] != Activity::ANNOUNCE) && ($item['gravity'] == Item::GRAVITY_ACTIVITY) && !in_array($type, [self::TYPE_DIRECT_COMMENT, self::TYPE_DIRECT_THREAD_COMMENT])) { // Activities are only stored when performed on the user's post or comment return; } - $notification = (new Notifications\Factory\Notification(DI::logger()))->createForUser( + $notification = DI::notificationFactory()->createForUser( $uid, $item['vid'], $type, $item['author-id'], - $item['gravity'] == GRAVITY_ACTIVITY ? $item['thr-parent-id'] : $item['uri-id'], + $item['gravity'] == Item::GRAVITY_ACTIVITY ? $item['thr-parent-id'] : $item['uri-id'], $item['parent-uri-id'] ); @@ -310,7 +366,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 @@ -318,7 +374,7 @@ class UserNotification */ public static function insertNotification(int $actor, string $verb, int $uid): bool { - $notification = (new Notifications\Factory\Notification(DI::logger()))->createForRelationship( + $notification = DI::notificationFactory()->createForRelationship( $uid, $actor, $verb @@ -397,7 +453,21 @@ class UserNotification private static function checkShared(array $item, int $uid): bool { // Only check on original posts and reshare ("announce") activities, otherwise return - if (($item['gravity'] != GRAVITY_PARENT) && ($item['verb'] != Activity::ANNOUNCE)) { + if (($item['gravity'] != Item::GRAVITY_PARENT) && ($item['verb'] != Activity::ANNOUNCE)) { + return false; + } + + // Don't notify about reshares by communities of our own posts or each time someone comments + if (($item['verb'] == Activity::ANNOUNCE) && DBA::exists('contact', ['id' => $item['contact-id'], 'contact-type' => Contact::TYPE_COMMUNITY])) { + $post = Post::selectFirst(['origin', 'gravity'], ['uri-id' => $item['thr-parent-id'], 'uid' => $uid]); + if (!$post || $post['origin'] || ($post['gravity'] != Item::GRAVITY_PARENT)) { + return false; + } + } + + // Only check on posts by the user itself + $cdata = Contact::getPublicAndUserContactID($item['contact-id'], $item['uid']); + if (empty($cdata['user']) || ($item['author-id'] != $cdata['public'])) { return false; } @@ -463,7 +533,7 @@ class UserNotification */ private static function checkCommentedThread(array $item, array $contacts): bool { - $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_PARENT]; + $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_PARENT]; return Post::exists($condition); } @@ -477,7 +547,7 @@ class UserNotification */ private static function checkDirectComment(array $item, array $contacts): bool { - $condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_COMMENT]; + $condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]; return Post::exists($condition); } @@ -491,7 +561,7 @@ class UserNotification */ private static function checkDirectCommentedThread(array $item, array $contacts): bool { - $condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_PARENT]; + $condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_PARENT]; return Post::exists($condition); } @@ -505,7 +575,21 @@ class UserNotification */ private static function checkCommentedParticipation(array $item, array $contacts): bool { - $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_COMMENT]; + $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]; + return Post::exists($condition); + } + + /** + * Check if the user follows this thread + * + * @param array $item + * @param array $contacts Array of contact IDs + * @return bool The user follows the thread + * @throws Exception + */ + private static function checkFollowParticipation(array $item, array $contacts): bool + { + $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::FOLLOW]; return Post::exists($condition); } @@ -519,7 +603,26 @@ class UserNotification */ private static function checkActivityParticipation(array $item, array $contacts): bool { - $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY]; + $condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_ACTIVITY]; return Post::exists($condition); } + + /** + * Check for a quoted post of a post of the given user + * + * @param array $item + * @param array $contacts Array of contact IDs + * @return bool The item is a quoted post of a user's post or comment + * @throws Exception + */ + private static function checkQuoted(array $item, array $contacts): bool + { + if (empty($item['quote-uri-id'])) { + return false; + } + $condition = ['uri-id' => $item['quote-uri-id'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => [item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]]; + return Post::exists($condition); + } + + }