2023-11-26 19:23:43 +00:00
|
|
|
from typing import List
|
|
|
|
from sqlalchemy import and_, select
|
2023-11-26 18:21:14 +00:00
|
|
|
from sqlalchemy.orm import aliased
|
2023-11-26 19:09:03 +00:00
|
|
|
from sqlalchemy.exc import SQLAlchemyError
|
2023-11-26 10:18:57 +00:00
|
|
|
from orm.author import Author
|
2023-11-26 18:21:14 +00:00
|
|
|
from orm.notification import Notification as NotificationMessage, NotificationSeen
|
2023-11-26 10:18:57 +00:00
|
|
|
from services.auth import login_required
|
|
|
|
from services.db import local_session
|
2023-11-26 18:21:14 +00:00
|
|
|
from strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper
|
|
|
|
import strawberry
|
2023-11-26 20:49:05 +00:00
|
|
|
from strawberry.schema.config import StrawberryConfig
|
2023-11-26 10:18:57 +00:00
|
|
|
|
2023-11-26 18:21:14 +00:00
|
|
|
strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
|
2023-11-26 18:21:14 +00:00
|
|
|
@strawberry_sqlalchemy_mapper.type(NotificationMessage)
|
2023-11-26 10:18:57 +00:00
|
|
|
class Notification:
|
|
|
|
id: int
|
|
|
|
action: str # create update delete join follow etc.
|
|
|
|
entity: str # REACTION SHOUT
|
|
|
|
created_at: int
|
2023-11-26 18:21:14 +00:00
|
|
|
payload: str # JSON data
|
|
|
|
seen: List[int]
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
@strawberry.type
|
|
|
|
class NotificationSeenResult:
|
2023-11-26 19:00:00 +00:00
|
|
|
error: str = strawberry.field(default=None, name="error")
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
|
2023-11-26 11:21:32 +00:00
|
|
|
@strawberry.type
|
|
|
|
class NotificationsResult:
|
|
|
|
notifications: List[Notification]
|
|
|
|
unread: int
|
2023-11-26 12:37:22 +00:00
|
|
|
total: int
|
2023-11-26 11:21:32 +00:00
|
|
|
|
2023-11-26 10:18:57 +00:00
|
|
|
|
2023-11-28 16:04:45 +00:00
|
|
|
def get_notifications(author_id, session, limit, offset) -> List[Notification]:
|
2023-11-26 19:23:43 +00:00
|
|
|
NotificationSeenAlias = aliased(NotificationSeen)
|
2023-11-28 16:04:45 +00:00
|
|
|
query = (
|
|
|
|
select(NotificationMessage, NotificationSeenAlias.viewer.label("seen"))
|
|
|
|
.outerjoin(
|
|
|
|
NotificationSeen,
|
|
|
|
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id),
|
|
|
|
)
|
|
|
|
.group_by(NotificationSeen.notification)
|
|
|
|
)
|
2023-11-26 19:23:43 +00:00
|
|
|
if limit:
|
|
|
|
query = query.limit(limit)
|
|
|
|
if offset:
|
|
|
|
query = query.offset(offset)
|
|
|
|
|
|
|
|
notifications = []
|
|
|
|
for n, seen in session.execute(query):
|
|
|
|
ntf = Notification(
|
|
|
|
id=n.id,
|
|
|
|
payload=n.payload,
|
|
|
|
entity=n.entity,
|
|
|
|
action=n.action,
|
|
|
|
created_at=n.created_at,
|
|
|
|
seen=seen,
|
|
|
|
)
|
|
|
|
if ntf:
|
|
|
|
notifications.append(ntf)
|
|
|
|
return notifications
|
|
|
|
|
|
|
|
|
2023-11-26 10:18:57 +00:00
|
|
|
@strawberry.type
|
|
|
|
class Query:
|
|
|
|
@strawberry.field
|
2023-11-26 10:51:06 +00:00
|
|
|
@login_required
|
2023-11-26 11:21:32 +00:00
|
|
|
async def load_notifications(self, info, limit: int = 50, offset: int = 0) -> NotificationsResult:
|
2023-11-28 16:04:45 +00:00
|
|
|
author_id = info.context.get("author_id")
|
2023-11-26 10:18:57 +00:00
|
|
|
with local_session() as session:
|
2023-11-26 19:09:03 +00:00
|
|
|
try:
|
2023-11-28 16:04:45 +00:00
|
|
|
if author_id:
|
|
|
|
notifications = get_notifications(author_id, session, limit, offset)
|
2023-11-26 19:23:43 +00:00
|
|
|
if notifications and len(notifications) > 0:
|
|
|
|
nr = NotificationsResult(
|
|
|
|
notifications=notifications,
|
2023-11-28 16:04:45 +00:00
|
|
|
unread=sum(1 for n in notifications if author_id in n.seen),
|
|
|
|
total=session.query(NotificationMessage).count(),
|
2023-11-26 19:09:03 +00:00
|
|
|
)
|
2023-11-26 19:23:43 +00:00
|
|
|
return nr
|
2023-11-26 19:09:03 +00:00
|
|
|
except Exception as ex:
|
|
|
|
print(f"[resolvers.schema] {ex}")
|
2023-11-28 16:04:45 +00:00
|
|
|
return NotificationsResult(notifications=[], total=0, unread=0)
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
@strawberry.type
|
|
|
|
class Mutation:
|
|
|
|
@strawberry.mutation
|
|
|
|
@login_required
|
|
|
|
async def mark_notification_as_read(self, info, notification_id: int) -> NotificationSeenResult:
|
2023-11-28 16:04:45 +00:00
|
|
|
author_id = info.context.get("author_id")
|
|
|
|
if author_id:
|
|
|
|
with local_session() as session:
|
|
|
|
try:
|
|
|
|
ns = NotificationSeen(notification=notification_id, viewer=author_id)
|
2023-11-26 19:23:43 +00:00
|
|
|
session.add(ns)
|
|
|
|
session.commit()
|
2023-11-28 16:04:45 +00:00
|
|
|
except SQLAlchemyError as e:
|
|
|
|
session.rollback()
|
|
|
|
print(f"[mark_notification_as_read] error: {str(e)}")
|
|
|
|
nsr = NotificationSeenResult(error="cant mark as read")
|
|
|
|
return nsr
|
2023-11-26 11:21:32 +00:00
|
|
|
return NotificationSeenResult()
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
@strawberry.mutation
|
|
|
|
@login_required
|
|
|
|
async def mark_all_notifications_as_read(self, info) -> NotificationSeenResult:
|
2023-11-28 16:04:45 +00:00
|
|
|
author_id = info.context.get("author_id")
|
|
|
|
if author_id:
|
2023-11-26 10:18:57 +00:00
|
|
|
try:
|
2023-11-28 16:04:45 +00:00
|
|
|
with local_session() as session:
|
|
|
|
nslist = get_notifications(author_id, session, None, None)
|
2023-11-26 19:23:43 +00:00
|
|
|
for n in nslist:
|
2023-11-28 16:04:45 +00:00
|
|
|
if author_id not in n.seen:
|
|
|
|
ns = NotificationSeen(viewer=author_id, notification=n.id)
|
2023-11-26 19:23:43 +00:00
|
|
|
session.add(ns)
|
|
|
|
session.commit()
|
2023-11-26 19:09:03 +00:00
|
|
|
except SQLAlchemyError as e:
|
2023-11-26 10:18:57 +00:00
|
|
|
session.rollback()
|
|
|
|
print(f"[mark_all_notifications_as_read] error: {str(e)}")
|
2023-11-26 19:09:03 +00:00
|
|
|
nsr = NotificationSeenResult(error="cant mark as read")
|
2023-11-26 18:21:14 +00:00
|
|
|
return nsr
|
2023-11-26 11:21:32 +00:00
|
|
|
return NotificationSeenResult()
|
2023-11-26 10:18:57 +00:00
|
|
|
|
|
|
|
|
2023-11-26 20:49:05 +00:00
|
|
|
schema = strawberry.Schema(query=Query, mutation=Mutation, config=StrawberryConfig(auto_camel_case=False))
|