notification: add notification history

This commit is contained in:
behruz-dev
2025-10-30 16:17:25 +05:00
parent 22b1d37a1a
commit af8d212b3e
10 changed files with 146 additions and 5 deletions

View File

@@ -1 +1,2 @@
from .notification import * from .notification import *
from .notification_history import *

View File

@@ -0,0 +1,6 @@
from django.contrib import admin
from core.apps.notifications.models.notification_history import NotificationHistory
admin.site.register(NotificationHistory)

View File

@@ -0,0 +1,33 @@
# Generated by Django 5.2.4 on 2025-10-30 16:16
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notifications', '0002_notification_type_alter_notification_unique_together'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='NotificationHistory',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('title', models.CharField(max_length=200)),
('body', models.TextField()),
('is_read', models.BooleanField(default=False)),
('data', models.JSONField(blank=True, null=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_histories', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]

View File

@@ -1 +1,2 @@
from .notification import * from .notification import *
from .notification_history import *

View File

@@ -0,0 +1,17 @@
from django.db import models
from core.apps.shared.models import BaseModel
from core.apps.accounts.models import User
class NotificationHistory(BaseModel):
title = models.CharField(max_length=200)
body = models.TextField()
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='notification_histories'
)
is_read = models.BooleanField(default=False)
data = models.JSONField(null=True, blank=True)
def __str__(self):
return f'Notification to {self.user}: {self.title}'

View File

@@ -0,0 +1,11 @@
from rest_framework import serializers
from core.apps.notifications.models import NotificationHistory
class NotificationHistorySerializer(serializers.ModelSerializer):
class Meta:
model = NotificationHistory
fields = [
'id', 'title', 'body', 'data', 'is_read'
]

View File

@@ -0,0 +1,21 @@
from celery import shared_task
from django.shortcuts import get_object_or_404
from core.apps.notifications.models import NotificationHistory
from core.apps.accounts.models import User
@shared_task
def create_history(users, title, body, data=None):
histories = []
for user in users:
histories.append(NotificationHistory(
title=title,
user=user,
body=body,
data=data,
is_read=False
))
NotificationHistory.objects.bulk_create(histories)

View File

@@ -1,7 +1,11 @@
from django.urls import path from django.urls import path
from core.apps.notifications.views import notification from core.apps.notifications.views import notification
from core.apps.notifications.views import notification_history
urlpatterns = [ urlpatterns = [
path('device/register/', notification.RegisterExpoPushToken.as_view()), path('device/register/', notification.RegisterExpoPushToken.as_view()),
path('history/', notification_history.NotificationHistoryListApiView.as_view()),
path('history/<uuid:id>/read/', notification_history.NotificationHistoryUpdateApiView.as_view()),
] ]

View File

@@ -1,18 +1,20 @@
import requests import requests
from firebase_admin import messaging from firebase_admin import messaging
from django.conf import settings
from core.apps.notifications.models import Notification from core.apps.notifications.models import Notification
from core.apps.notifications.tasks.create_notification_history import create_history
EXPO_API_URL = "https://exp.host/--/api/v2/push/send" EXPO_API_URL = "https://exp.host/--/api/v2/push/send"
def send_notification(token, title, body, data=None): def send_notification(token, title, body, data=None):
tokens = list(Notification.objects.exclude(token=token).values_list("token", flat=True)) tokens = list(Notification.objects.exclude(token=token).values_list("token", flat=True))
users = list(Notification.objects.exclude(token=token).values_list("user", flat=True))
create_history.delay(users, title, body, data)
if not tokens: if not tokens:
return {"error": "No tokens found"} return {"error": "No tokens found"}
messages = [ messages = [
{ {
"to": token, "to": token,
@@ -38,6 +40,8 @@ def send_notification(token, title, body, data=None):
def send_web_notification(token, title, body, data=None): def send_web_notification(token, title, body, data=None):
tokens = list(Notification.objects.exclude(token=token).values_list('token', flat=True)) tokens = list(Notification.objects.exclude(token=token).values_list('token', flat=True))
users = list(Notification.objects.exclude(token=token).values_list("user", flat=True))
create_history.delay(users, title, body, data)
if not tokens: if not tokens:
return return

View File

@@ -0,0 +1,43 @@
from django.shortcuts import get_object_or_404
from rest_framework import generics, views
from rest_framework.response import Response
from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.notifications.models import NotificationHistory
from core.apps.notifications.serializers.notification_history import NotificationHistorySerializer
class NotificationHistoryListApiView(generics.GenericAPIView):
serializer_class = NotificationHistorySerializer
permission_classes = [HasRolePermission]
def get_queryset(self):
return NotificationHistory.objects.filter(user=self.request.user).order_by('-created_at')
def get(self, request):
queryset = self.get_queryset()
is_read = request.query_params.get('is_read')
if is_read:
if is_read.lower() == 'true':
queryset = queryset.filter(is_read=True)
if is_read.lower() == 'false':
queryset = queryset.filter(is_read=False)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
return None
class NotificationHistoryUpdateApiView(views.APIView):
permission_classes = [HasRolePermission]
def post(self, request, id):
obj = get_object_or_404(NotificationHistory, id=id)
if obj.is_read:
return Response({'success': False, "message": 'already readed'}, status=400)
obj.is_read = True
obj.save()
return Response({'success': True, "message": 'readed'}, status=200)