group-seen-fix
All checks were successful
deploy / deploy (push) Successful in 1m13s

This commit is contained in:
Untone 2023-12-22 17:52:55 +03:00
parent 674bc9ce63
commit dbe4dd760b
2 changed files with 70 additions and 55 deletions

View File

@ -1,13 +1,12 @@
from services.db import local_session from services.db import local_session
from resolvers.model import ( from resolvers.model import (
NotificationReaction, NotificationReaction,
Notification as NotificationMessage,
NotificationGroup, NotificationGroup,
NotificationShout, NotificationShout,
NotificationAuthor, NotificationAuthor,
NotificationsResult, NotificationsResult,
) )
from orm.notification import NotificationSeen from orm.notification import NotificationSeen, Notification
from typing import Dict, List from typing import Dict, List
import time, json import time, json
import strawberry import strawberry
@ -15,20 +14,18 @@ from sqlalchemy.orm import aliased
from sqlalchemy import select, and_ from sqlalchemy import select, and_
async def get_notifications_grouped( async def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, offset: int = 0):
author_id: int, after: int = 0, limit: int = 10, offset: int = 0, mark_as_read=False
):
""" """
Retrieves notifications for a given author. Retrieves notifications for a given author.
Args: Args:
author_id (int): The ID of the author for whom notifications are retrieved. author_id (int): The ID of the author for whom notifications are retrieved.
session: Database connection session after (int, optional): If provided, selects only notifications created after this timestamp will be considered.
after (int, optional): If provided, only notifications created after this timestamp will be considered. limit (int, optional): The maximum number of groupa to retrieve.
limit (int, optional): The maximum number of notifications to retrieve. offset (int, optional): Offset for pagination
Returns: Returns:
Dict[str, NotificationGroup]: A dictionary where keys are thread IDs and values are NotificationGroup objects. Dict[str, NotificationGroup], int, int: A dictionary where keys are thread IDs and values are NotificationGroup objects, unread and total amounts.
This function queries the database to retrieve notifications for the specified author, considering optional filters. This function queries the database to retrieve notifications for the specified author, considering optional filters.
The result is a dictionary where each key is a thread ID, and the corresponding value is a NotificationGroup The result is a dictionary where each key is a thread ID, and the corresponding value is a NotificationGroup
@ -43,18 +40,19 @@ async def get_notifications_grouped(
} }
""" """
NotificationSeenAlias = aliased(NotificationSeen) NotificationSeenAlias = aliased(NotificationSeen)
query = select(NotificationMessage, NotificationSeenAlias.viewer.label("seen")).outerjoin( query = select(Notification, NotificationSeenAlias.viewer.label("seen")).outerjoin(
NotificationSeen, NotificationSeen,
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id), and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == Notification.id),
) )
if after: if after:
query = query.filter(NotificationMessage.created_at > after) query = query.filter(Notification.created_at > after)
query = query.group_by(NotificationSeen.notification) query = query.group_by(NotificationSeen.notification)
notifications: Dict[str, NotificationGroup] = {} groups_amount = 0
counter = 0
unread = 0 unread = 0
total = 0 total = 0
notifications_by_thread: Dict[str, List[Notification]] = {}
groups_by_thread: Dict[str, NotificationGroup] = {}
with local_session() as session: with local_session() as session:
notifications_result = session.execute(query) notifications_result = session.execute(query)
for n, seen in notifications_result: for n, seen in notifications_result:
@ -63,14 +61,11 @@ async def get_notifications_grouped(
thread_id = "" thread_id = ""
payload = json.loads(n.payload) payload = json.loads(n.payload)
print(f"[resolvers.schema] {n.action} {n.entity}: {payload}") print(f"[resolvers.schema] {n.action} {n.entity}: {payload}")
if n.entity == "shout": if n.entity == "shout" and n.action == "create":
shout: NotificationShout = payload shout: NotificationShout = payload
thread_id += f"{shout.id}" thread_id += f"{shout.id}"
if n.action == "delete":
del notifications[thread_id]
elif n.action == "create":
print(f"[resolvers.schema] create shout: {shout}") print(f"[resolvers.schema] create shout: {shout}")
notification_group = NotificationGroup( group = groups_by_thread.get(thread_id) or NotificationGroup(
id=thread_id, id=thread_id,
entity=n.entity, entity=n.entity,
shout=shout, shout=shout,
@ -78,11 +73,16 @@ async def get_notifications_grouped(
updated_at=shout.created_at, updated_at=shout.created_at,
reactions=[], reactions=[],
action="create", action="create",
seen=author_id in n.seen
) )
# store group in result # store group in result
notifications[thread_id] = notification_group groups_by_thread[thread_id] = group
counter += 1 notifications = notifications_by_thread.get(thread_id, [])
elif n.entity == "reaction": if n not in notifications:
notifications.append(n)
notifications_by_thread[thread_id] = notifications
groups_amount += 1
elif n.entity == "reaction" and n.action == "create":
reaction: NotificationReaction = payload reaction: NotificationReaction = payload
shout: NotificationShout = reaction.shout shout: NotificationShout = reaction.shout
thread_id += f"{reaction.shout}" thread_id += f"{reaction.shout}"
@ -92,25 +92,31 @@ async def get_notifications_grouped(
elif reaction.kind == "COMMENT": elif reaction.kind == "COMMENT":
if reaction.reply_to: if reaction.reply_to:
thread_id += f"{'::' + str(reaction.reply_to)}" thread_id += f"{'::' + str(reaction.reply_to)}"
notification_group: NotificationGroup | None = notifications.get(thread_id) group: NotificationGroup | None = groups_by_thread.get(thread_id)
if notification_group: notifications: List[Notification] = notifications_by_thread.get(thread_id)
notification_group.shout = shout if group and notifications:
notification_group.authors.append(reaction.created_by) group.seen = False # any not seen notification make it false
if not notification_group.reactions: group.shout = shout
notification_group.reactions = [] group.authors.append(reaction.created_by)
notification_group.reactions.append(reaction.id) if not group.reactions:
group.reactions = []
group.reactions.append(reaction.id)
# store group in result # store group in result
notifications[thread_id] = notification_group groups_by_thread[thread_id] = group
counter += 1 notifications = notifications_by_thread.get(thread_id, [])
if n not in notifications:
notifications.append(n)
notifications_by_thread[thread_id] = notifications
groups_amount += 1
else: else:
counter += 1 groups_amount += 1
if counter > limit: if groups_amount > limit:
break break
else: else:
# init notification group # init notification group
reactions = [] reactions = []
reactions.append(reaction.id) reactions.append(reaction.id)
notification_group = NotificationGroup( group = NotificationGroup(
id=thread_id, id=thread_id,
action=n.action, action=n.action,
entity=n.entity, entity=n.entity,
@ -120,15 +126,19 @@ async def get_notifications_grouped(
authors=[ authors=[
reaction.created_by, reaction.created_by,
], ],
seen=author_id in n.seen
) )
# store group in result # store group in result
notifications[thread_id] = notification_group groups_by_thread[thread_id] = group
notifications = notifications_by_thread.get(thread_id, [])
if n not in notifications:
notifications.append(n)
notifications_by_thread[thread_id] = notifications
elif n.entity == "follower": elif n.entity == "follower":
thread_id = "followers" thread_id = "followers"
follower: NotificationAuthor = payload follower: NotificationAuthor = payload
notification_group = notifications.get(thread_id) group = groups_by_thread.get(thread_id) or NotificationGroup(
if not notification_group:
notification_group = NotificationGroup(
id=thread_id, id=thread_id,
authors=[follower], authors=[follower],
updated_at=int(time.time()), updated_at=int(time.time()),
@ -136,18 +146,22 @@ async def get_notifications_grouped(
reactions=[], reactions=[],
entity="follower", entity="follower",
action="follow", action="follow",
seen=author_id in n.seen
) )
else: group.authors = [follower, ]
notification_group.authors = [follower, ] group.updated_at = int(time.time())
notification_group.updated_at = int(time.time())
# store group in result # store group in result
notifications[thread_id] = notification_group groups_by_thread[thread_id] = group
counter += 1 notifications = notifications_by_thread.get(thread_id, [])
if n not in notifications:
notifications.append(n)
notifications_by_thread[thread_id] = notifications
groups_amount += 1
if counter > limit: if groups_amount > limit:
break break
return notifications, unread, total return groups_by_thread, unread, total
@strawberry.type @strawberry.type

View File

@ -59,6 +59,7 @@ class NotificationGroup:
action: Optional[str] action: Optional[str]
shout: Optional[NotificationShout] shout: Optional[NotificationShout]
reactions: Optional[List[int]] reactions: Optional[List[int]]
seen: Optional[bool]
# latest reaction.created_at for reactions-updates # latest reaction.created_at for reactions-updates
# no timestamp for followers-updates # no timestamp for followers-updates
# latest shout.created_at for shouts-updates # latest shout.created_at for shouts-updates