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

View File

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