This commit is contained in:
37
resolvers/listener.py
Normal file
37
resolvers/listener.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import json
|
||||
from typing import List, Dict
|
||||
|
||||
from orm.notification import Notification
|
||||
from services.db import local_session
|
||||
from services.rediscache import redis
|
||||
|
||||
|
||||
def handle_reaction(notification: Dict[str, str | int | List[int]]):
|
||||
"""создаеёт новое хранимое уведомление"""
|
||||
try:
|
||||
with local_session() as session:
|
||||
n = Notification(**notification)
|
||||
session.add(n)
|
||||
session.commit(n)
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f"[listener.handle_reaction] error: {str(e)}")
|
||||
|
||||
|
||||
def stop(pubsub):
|
||||
pubsub.unsubscribe()
|
||||
pubsub.close()
|
||||
|
||||
|
||||
def start():
|
||||
pubsub = redis.pubsub()
|
||||
pubsub.subscribe("reaction")
|
||||
try:
|
||||
# Бесконечный цикл прослушивания
|
||||
while True:
|
||||
msg = pubsub.get_message()
|
||||
handle_reaction(json.loads(msg["data"]))
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
stop(pubsub)
|
@@ -1,82 +0,0 @@
|
||||
from sqlalchemy import and_, desc, select, update
|
||||
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
from services.schema import mutation, query
|
||||
from orm.notification import Notification
|
||||
|
||||
# TODO: occurrencies?
|
||||
|
||||
# TODO: use of Author.id?
|
||||
|
||||
|
||||
@query.field("loadNotifications")
|
||||
@login_required
|
||||
async def load_notifications(_, info, params=None):
|
||||
if params is None:
|
||||
params = {}
|
||||
|
||||
user_id = info.context["user_id"]
|
||||
|
||||
limit = params.get("limit", 50)
|
||||
offset = params.get("offset", 0)
|
||||
q = select(Notification).order_by(desc(Notification.created_at)).limit(limit).offset(offset)
|
||||
|
||||
notifications = []
|
||||
with local_session() as session:
|
||||
total_count = session.query(Notification).where(Notification.user == user_id).count()
|
||||
|
||||
total_unread_count = (
|
||||
session.query(Notification)
|
||||
.where(and_(Notification.user == user_id, Notification.seen == False)) # noqa: E712
|
||||
.count()
|
||||
)
|
||||
|
||||
for [notification] in session.execute(q):
|
||||
notification.type = notification.type.name
|
||||
notifications.append(notification)
|
||||
|
||||
return {
|
||||
"notifications": notifications,
|
||||
"total": total_count,
|
||||
"unread": total_unread_count,
|
||||
}
|
||||
|
||||
|
||||
@mutation.field("markNotificationAsRead")
|
||||
@login_required
|
||||
async def mark_notification_as_read(_, info, notification_id: int):
|
||||
user_id = info.context["user_id"]
|
||||
|
||||
with local_session() as session:
|
||||
notification = (
|
||||
session.query(Notification)
|
||||
.where(and_(Notification.id == notification_id, Notification.user == user_id))
|
||||
.one()
|
||||
)
|
||||
notification.seen = True
|
||||
session.commit()
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
@mutation.field("markAllNotificationsAsRead")
|
||||
@login_required
|
||||
async def mark_all_notifications_as_read(_, info):
|
||||
user_id = info.context["user_id"]
|
||||
|
||||
statement = (
|
||||
update(Notification)
|
||||
.where(and_(Notification.user == user_id, Notification.seen == False)) # noqa: E712
|
||||
.values(seen=True)
|
||||
)
|
||||
|
||||
with local_session() as session:
|
||||
try:
|
||||
session.execute(statement)
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f"[mark_all_notifications_as_read] error: {str(e)}")
|
||||
|
||||
return {}
|
108
resolvers/schema.py
Normal file
108
resolvers/schema.py
Normal file
@@ -0,0 +1,108 @@
|
||||
import strawberry
|
||||
from sqlalchemy import and_
|
||||
from orm.author import Author
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class NotificationSeen:
|
||||
notification: int # notification id
|
||||
viewer: int # author id
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class Notification:
|
||||
id: int
|
||||
action: str # create update delete join follow etc.
|
||||
entity: str # REACTION SHOUT
|
||||
created_at: int
|
||||
seen: list[NotificationSeen]
|
||||
data: str # JSON data
|
||||
occurrences: int
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class NotificationsQueryResult:
|
||||
notifications: list[Notification]
|
||||
unread: int
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class NotificationSeenResult:
|
||||
error: str
|
||||
|
||||
|
||||
def notification_seen_by_viewer(viewer_id, notification_id, session):
|
||||
seen = (
|
||||
session.query(NotificationSeen)
|
||||
.filter(NotificationSeen.viewer == viewer_id, NotificationSeen.notification == notification_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
return seen is not None
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class Query:
|
||||
@login_required
|
||||
@strawberry.field
|
||||
async def load_notifications(self, info, limit: int = 50, offset: int = 0) -> dict:
|
||||
"""непрочитанные уведомления"""
|
||||
user_id = info.context["user_id"]
|
||||
|
||||
with local_session() as session:
|
||||
author = session.query(Author).filter(Author.user == user_id).first()
|
||||
|
||||
nslist = (
|
||||
session.query(Notification)
|
||||
.outerjoin(
|
||||
NotificationSeen,
|
||||
and_(NotificationSeen.viewer == author.id, NotificationSeen.notification == Notification.id),
|
||||
)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all()
|
||||
)
|
||||
|
||||
for notification in nslist:
|
||||
notification.seen_by_viewer = notification_seen_by_viewer(author.id, notification.id, session)
|
||||
|
||||
unread = sum(1 for n in nslist if not n.seen_by_viewer)
|
||||
|
||||
return {"notifications": nslist, "unread": unread}
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class Mutation:
|
||||
@strawberry.mutation
|
||||
@login_required
|
||||
async def mark_notification_as_read(self, info, notification_id: int) -> NotificationSeenResult:
|
||||
user_id = info.context["user_id"]
|
||||
try:
|
||||
with local_session() as session:
|
||||
author = session.query(Author).filter(Author.user == user_id).first()
|
||||
ns = NotificationSeen({"notification": notification_id, "viewer": author.id})
|
||||
session.add(ns)
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f"[mark_notification_as_read] error: {str(e)}")
|
||||
return {}
|
||||
|
||||
@strawberry.mutation
|
||||
@login_required
|
||||
async def mark_all_notifications_as_read(self, info) -> NotificationSeenResult:
|
||||
user_id = info.context["user_id"]
|
||||
|
||||
with local_session() as session:
|
||||
try:
|
||||
author = session.query(Author).filter(Author.user == user_id).first()
|
||||
_nslist = session.quuery(NotificationSeen).filter(NotificationSeen.viewer == author.id).all()
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f"[mark_all_notifications_as_read] error: {str(e)}")
|
||||
return {}
|
||||
|
||||
|
||||
schema = strawberry.Schema(query=Query, mutation=Mutation)
|
Reference in New Issue
Block a user