85 lines
3.3 KiB
Python
85 lines
3.3 KiB
Python
from snek.system.markdown import strip_markdown
|
|
from snek.system.model import now
|
|
from snek.system.service import BaseService
|
|
|
|
|
|
class NotificationService(BaseService):
|
|
mapper_name = "notification"
|
|
|
|
async def mark_as_read(self, user_uid, channel_message_uid):
|
|
model = await self.get(user_uid, object_uid=channel_message_uid)
|
|
if not model:
|
|
return False
|
|
model["read_at"] = now()
|
|
await self.save(model)
|
|
return True
|
|
|
|
async def get_unread_stats(self, user_uid):
|
|
await self.query(
|
|
"SELECT object_type, COUNT(*) as count FROM notification WHERE user_uid=:user_uid AND read_at IS NULL GROUP BY object_type",
|
|
{"user_uid": user_uid},
|
|
)
|
|
|
|
async def create(self, object_uid, object_type, user_uid, message):
|
|
model = await self.new()
|
|
model["object_uid"] = object_uid
|
|
model["object_type"] = object_type
|
|
model["user_uid"] = user_uid
|
|
model["message"] = message
|
|
if await self.save(model):
|
|
return model
|
|
raise Exception(f"Failed to create notification: {model.errors}.")
|
|
|
|
async def create_channel_message(self, channel_message_uid):
|
|
channel_message = await self.services.channel_message.get(
|
|
uid=channel_message_uid
|
|
)
|
|
if not channel_message["is_final"]:
|
|
return
|
|
user = await self.services.user.get(uid=channel_message["user_uid"])
|
|
self.app.db.begin()
|
|
async for channel_member in self.services.channel_member.find(
|
|
channel_uid=channel_message["channel_uid"],
|
|
is_banned=False,
|
|
is_muted=False,
|
|
deleted_at=None,
|
|
):
|
|
if not channel_member["new_count"]:
|
|
channel_member["new_count"] = 0
|
|
channel_member["new_count"] += 1
|
|
|
|
usr = await self.services.user.get(uid=channel_member["user_uid"])
|
|
if not usr:
|
|
continue
|
|
await self.services.channel_member.save(channel_member)
|
|
|
|
model = await self.new()
|
|
model["object_uid"] = channel_message_uid
|
|
model["object_type"] = "channel_message"
|
|
model["user_uid"] = channel_member["user_uid"]
|
|
model["message"] = (
|
|
f"New message from {user['nick']} in {channel_member['label']}."
|
|
)
|
|
try:
|
|
await self.save(model)
|
|
except Exception:
|
|
raise Exception(f"Failed to create notification: {model.errors}.")
|
|
|
|
if channel_member["user_uid"] != user["uid"]:
|
|
try:
|
|
stripped_message = strip_markdown(channel_message["message"])
|
|
channel_name = await channel_member.get_name()
|
|
await self.app.services.push.notify_user(
|
|
user_uid=channel_member["user_uid"],
|
|
payload={
|
|
"title": f"New message in {channel_name}",
|
|
"message": f"{user['nick']}: {stripped_message}",
|
|
"icon": "/image/snek192.png",
|
|
"url": f"/channel/{channel_message['channel_uid']}.html",
|
|
},
|
|
)
|
|
except Exception as e:
|
|
print(f"Failed to send push notification:", e)
|
|
|
|
self.app.db.commit()
|