notifier/resolvers/load.py

160 lines
7.0 KiB
Python
Raw Normal View History

2023-12-22 09:09:03 +00:00
from services.db import local_session
from resolvers.model import (
NotificationReaction,
Notification as NotificationMessage,
NotificationGroup,
NotificationShout,
NotificationAuthor,
NotificationsResult,
)
from orm.notification import NotificationSeen
from typing import Dict
import time, json
import strawberry
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
) -> Dict[str, NotificationGroup]:
"""
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.
Returns:
Dict[str, NotificationGroup]: A dictionary where keys are thread IDs and values are NotificationGroup objects.
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
containing information about the notifications within that thread.
NotificationGroup structure:
{
entity: str, # Type of entity (e.g., 'reaction', 'shout', 'follower').
updated_at: int, # Timestamp of the latest update in the thread.
reactions: List[Reaction], # List of reactions within the thread.
authors: List[Author], # List of authors involved in the thread.
}
"""
NotificationSeenAlias = aliased(NotificationSeen)
query = select(NotificationMessage, NotificationSeenAlias.viewer.label("seen")).outerjoin(
NotificationSeen,
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id),
)
if after:
query = query.filter(NotificationMessage.created_at > after)
query = query.group_by(NotificationSeen.notification)
notifications: Dict[str, NotificationGroup] = {}
counter = 0
with local_session() as session:
for n, seen in session.execute(query):
thread_id = ""
payload = json.loads(n.payload)
print(f"[resolvers.schema] {n.action} {n.entity}: {payload}")
if n.entity == "shout":
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(
2023-12-22 10:08:35 +00:00
id=thread_id,
2023-12-22 09:09:03 +00:00
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":
reaction: NotificationReaction = payload
shout: NotificationShout = reaction.shout
thread_id += f"{reaction.shout}"
if reaction.kind == "LIKE" or reaction.kind == "DISLIKE":
# TODO: making published reaction vote announce
pass
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)
# store group in result
notifications[thread_id] = notification_group
counter += 1
else:
counter += 1
if counter > limit:
break
else:
# init notification group
reactions = []
reactions.append(reaction.id)
notification_group = NotificationGroup(
2023-12-22 10:08:35 +00:00
id=thread_id,
2023-12-22 09:09:03 +00:00
action=n.action,
entity=n.entity,
updated_at=reaction.created_at,
reactions=reactions,
shout=shout,
authors=[
reaction.created_by,
],
)
# store group in result
notifications[thread_id] = notification_group
elif n.entity == "follower":
thread_id = "followers"
follower: NotificationAuthor = payload
notification_group = notifications.get(thread_id)
if not notification_group:
notification_group = NotificationGroup(
2023-12-22 10:08:35 +00:00
id=thread_id,
2023-12-22 09:09:03 +00:00
authors=[follower],
updated_at=int(time.time()),
shout=None,
reactions=[],
entity="follower",
action="follow",
)
2023-12-22 10:08:35 +00:00
else:
notification_group.authors = [follower, ]
notification_group.updated_at = int(time.time())
2023-12-22 09:09:03 +00:00
# store group in result
notifications[thread_id] = notification_group
counter += 1
if counter > limit:
break
return notifications
@strawberry.type
class Query:
@strawberry.field
async def load_notifications(self, info, after: int, limit: int = 50, offset: int = 0) -> NotificationsResult:
author_id = info.context.get("author_id")
notification_groups: Dict[str, NotificationGroup] = {}
if author_id:
# TODO: add total counter calculation
# TODO: add unread counter calculation
notification_groups = await get_notifications_grouped(author_id, after, limit, offset)
notifications = sorted(notification_groups.values(), key=lambda group: group.updated_at, reverse=True)
return NotificationsResult(notifications=notifications, total=0, unread=0, error=None)