Improve topic sorting: add popular sorting by publications and authors count
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import time
|
||||
from typing import List, Tuple
|
||||
from typing import Any
|
||||
|
||||
import orjson
|
||||
from graphql import GraphQLResolveInfo
|
||||
from sqlalchemy import and_, select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import aliased
|
||||
@@ -21,7 +22,7 @@ from services.schema import mutation, query
|
||||
from utils.logger import root_logger as logger
|
||||
|
||||
|
||||
def query_notifications(author_id: int, after: int = 0) -> Tuple[int, int, List[Tuple[Notification, bool]]]:
|
||||
def query_notifications(author_id: int, after: int = 0) -> tuple[int, int, list[tuple[Notification, bool]]]:
|
||||
notification_seen_alias = aliased(NotificationSeen)
|
||||
q = select(Notification, notification_seen_alias.viewer.label("seen")).outerjoin(
|
||||
NotificationSeen,
|
||||
@@ -66,7 +67,14 @@ def query_notifications(author_id: int, after: int = 0) -> Tuple[int, int, List[
|
||||
return total, unread, notifications
|
||||
|
||||
|
||||
def group_notification(thread, authors=None, shout=None, reactions=None, entity="follower", action="follow"):
|
||||
def group_notification(
|
||||
thread: str,
|
||||
authors: list[Any] | None = None,
|
||||
shout: Any | None = None,
|
||||
reactions: list[Any] | None = None,
|
||||
entity: str = "follower",
|
||||
action: str = "follow",
|
||||
) -> dict:
|
||||
reactions = reactions or []
|
||||
authors = authors or []
|
||||
return {
|
||||
@@ -80,7 +88,7 @@ def group_notification(thread, authors=None, shout=None, reactions=None, entity=
|
||||
}
|
||||
|
||||
|
||||
def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, offset: int = 0):
|
||||
def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, offset: int = 0) -> list[dict]:
|
||||
"""
|
||||
Retrieves notifications for a given author.
|
||||
|
||||
@@ -111,7 +119,7 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
groups_by_thread = {}
|
||||
groups_amount = 0
|
||||
|
||||
for notification, seen in notifications:
|
||||
for notification, _seen in notifications:
|
||||
if (groups_amount + offset) >= limit:
|
||||
break
|
||||
|
||||
@@ -126,12 +134,12 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
author = session.query(Author).filter(Author.id == author_id).first()
|
||||
shout = session.query(Shout).filter(Shout.id == shout_id).first()
|
||||
if author and shout:
|
||||
author = author.dict()
|
||||
shout = shout.dict()
|
||||
author_dict = author.dict()
|
||||
shout_dict = shout.dict()
|
||||
group = group_notification(
|
||||
thread_id,
|
||||
shout=shout,
|
||||
authors=[author],
|
||||
shout=shout_dict,
|
||||
authors=[author_dict],
|
||||
action=str(notification.action),
|
||||
entity=str(notification.entity),
|
||||
)
|
||||
@@ -141,7 +149,8 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
elif str(notification.entity) == NotificationEntity.REACTION.value:
|
||||
reaction = payload
|
||||
if not isinstance(reaction, dict):
|
||||
raise ValueError("reaction data is not consistent")
|
||||
msg = "reaction data is not consistent"
|
||||
raise ValueError(msg)
|
||||
shout_id = reaction.get("shout")
|
||||
author_id = reaction.get("created_by", 0)
|
||||
if shout_id and author_id:
|
||||
@@ -149,8 +158,8 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
author = session.query(Author).filter(Author.id == author_id).first()
|
||||
shout = session.query(Shout).filter(Shout.id == shout_id).first()
|
||||
if shout and author:
|
||||
author = author.dict()
|
||||
shout = shout.dict()
|
||||
author_dict = author.dict()
|
||||
shout_dict = shout.dict()
|
||||
reply_id = reaction.get("reply_to")
|
||||
thread_id = f"shout-{shout_id}"
|
||||
if reply_id and reaction.get("kind", "").lower() == "comment":
|
||||
@@ -165,8 +174,8 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
else:
|
||||
group = group_notification(
|
||||
thread_id,
|
||||
authors=[author],
|
||||
shout=shout,
|
||||
authors=[author_dict],
|
||||
shout=shout_dict,
|
||||
reactions=[reaction],
|
||||
entity=str(notification.entity),
|
||||
action=str(notification.action),
|
||||
@@ -178,15 +187,15 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
elif str(notification.entity) == "follower":
|
||||
thread_id = "followers"
|
||||
follower = orjson.loads(payload)
|
||||
group = groups_by_thread.get(thread_id)
|
||||
if group:
|
||||
existing_group = groups_by_thread.get(thread_id)
|
||||
if existing_group:
|
||||
if str(notification.action) == "follow":
|
||||
group["authors"].append(follower)
|
||||
existing_group["authors"].append(follower)
|
||||
elif str(notification.action) == "unfollow":
|
||||
follower_id = follower.get("id")
|
||||
for author in group["authors"]:
|
||||
if author.get("id") == follower_id:
|
||||
group["authors"].remove(author)
|
||||
for author in existing_group["authors"]:
|
||||
if isinstance(author, dict) and author.get("id") == follower_id:
|
||||
existing_group["authors"].remove(author)
|
||||
break
|
||||
else:
|
||||
group = group_notification(
|
||||
@@ -196,13 +205,14 @@ def get_notifications_grouped(author_id: int, after: int = 0, limit: int = 10, o
|
||||
action=str(notification.action),
|
||||
)
|
||||
groups_amount += 1
|
||||
groups_by_thread[thread_id] = group
|
||||
return groups_by_thread, unread, total
|
||||
existing_group = group
|
||||
groups_by_thread[thread_id] = existing_group
|
||||
return list(groups_by_thread.values())
|
||||
|
||||
|
||||
@query.field("load_notifications")
|
||||
@login_required
|
||||
async def load_notifications(_, info, after: int, limit: int = 50, offset=0):
|
||||
async def load_notifications(_: None, info: GraphQLResolveInfo, after: int, limit: int = 50, offset: int = 0) -> dict:
|
||||
author_dict = info.context.get("author") or {}
|
||||
author_id = author_dict.get("id")
|
||||
error = None
|
||||
@@ -211,10 +221,10 @@ async def load_notifications(_, info, after: int, limit: int = 50, offset=0):
|
||||
notifications = []
|
||||
try:
|
||||
if author_id:
|
||||
groups, unread, total = get_notifications_grouped(author_id, after, limit)
|
||||
notifications = sorted(groups.values(), key=lambda group: group.updated_at, reverse=True)
|
||||
groups_list = get_notifications_grouped(author_id, after, limit)
|
||||
notifications = sorted(groups_list, key=lambda group: group.get("updated_at", 0), reverse=True)
|
||||
except Exception as e:
|
||||
error = e
|
||||
error = str(e)
|
||||
logger.error(e)
|
||||
return {
|
||||
"notifications": notifications,
|
||||
@@ -226,7 +236,7 @@ async def load_notifications(_, info, after: int, limit: int = 50, offset=0):
|
||||
|
||||
@mutation.field("notification_mark_seen")
|
||||
@login_required
|
||||
async def notification_mark_seen(_, info, notification_id: int):
|
||||
async def notification_mark_seen(_: None, info: GraphQLResolveInfo, notification_id: int) -> dict:
|
||||
author_id = info.context.get("author", {}).get("id")
|
||||
if author_id:
|
||||
with local_session() as session:
|
||||
@@ -243,7 +253,7 @@ async def notification_mark_seen(_, info, notification_id: int):
|
||||
|
||||
@mutation.field("notifications_seen_after")
|
||||
@login_required
|
||||
async def notifications_seen_after(_, info, after: int):
|
||||
async def notifications_seen_after(_: None, info: GraphQLResolveInfo, after: int) -> dict:
|
||||
# TODO: use latest loaded notification_id as input offset parameter
|
||||
error = None
|
||||
try:
|
||||
@@ -251,13 +261,10 @@ async def notifications_seen_after(_, info, after: int):
|
||||
if author_id:
|
||||
with local_session() as session:
|
||||
nnn = session.query(Notification).filter(and_(Notification.created_at > after)).all()
|
||||
for n in nnn:
|
||||
try:
|
||||
ns = NotificationSeen(notification=n.id, viewer=author_id)
|
||||
session.add(ns)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
for notification in nnn:
|
||||
ns = NotificationSeen(notification=notification.id, author=author_id)
|
||||
session.add(ns)
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error = "cant mark as read"
|
||||
@@ -266,7 +273,7 @@ async def notifications_seen_after(_, info, after: int):
|
||||
|
||||
@mutation.field("notifications_seen_thread")
|
||||
@login_required
|
||||
async def notifications_seen_thread(_, info, thread: str, after: int):
|
||||
async def notifications_seen_thread(_: None, info: GraphQLResolveInfo, thread: str, after: int) -> dict:
|
||||
error = None
|
||||
author_id = info.context.get("author", {}).get("id")
|
||||
if author_id:
|
||||
|
Reference in New Issue
Block a user