diff --git a/apps/account/migrations/0007_notification.py b/apps/account/migrations/0007_notification.py new file mode 100644 index 0000000..b67ec2a --- /dev/null +++ b/apps/account/migrations/0007_notification.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.7 on 2025-02-12 16:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0006_user_country'), + ] + + operations = [ + migrations.CreateModel( + name='Notification', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('message', models.TextField(max_length=512, verbose_name='message')), + ('is_read', models.BooleanField(default=False, verbose_name='is read')), + ('created_at', models.DateTimeField(auto_now_add=True, null=True, verbose_name='created at')), + ('updated_at', models.DateTimeField(auto_now=True, null=True, verbose_name='updated at')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + ), + ] diff --git a/apps/account/models/__init__.py b/apps/account/models/__init__.py index 6876ad1..c9f6b41 100644 --- a/apps/account/models/__init__.py +++ b/apps/account/models/__init__.py @@ -1,4 +1,3 @@ - - from .user import * -from .groups import * \ No newline at end of file +from .groups import * +from .notification import * \ No newline at end of file diff --git a/apps/account/models/notification.py b/apps/account/models/notification.py new file mode 100644 index 0000000..ea8c95e --- /dev/null +++ b/apps/account/models/notification.py @@ -0,0 +1,18 @@ +from django.db import models +from django.utils.translation import gettext as _ + + + + +class Notification(models.Model): + title = models.CharField(max_length=255, verbose_name=_('title')) + message = models.TextField(max_length=512, verbose_name=_('message')) + user = models.ForeignKey("account.User", on_delete=models.CASCADE, verbose_name=_('user'), related_name='notifications') + is_read = models.BooleanField(default=False, verbose_name=_('is read')) + created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'), null=True) + updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'), null=True) + + def __str__(self): + return self.title + + diff --git a/apps/account/serializers/__init__.py b/apps/account/serializers/__init__.py index 7e669dd..8c6bf0d 100644 --- a/apps/account/serializers/__init__.py +++ b/apps/account/serializers/__init__.py @@ -1,2 +1,2 @@ - from .user import * +from .notification import * diff --git a/apps/account/serializers/notification.py b/apps/account/serializers/notification.py new file mode 100644 index 0000000..4a8ecb0 --- /dev/null +++ b/apps/account/serializers/notification.py @@ -0,0 +1,24 @@ + + +from rest_framework import serializers +from apps.account.models import Notification +from apps.account.models import User + + + + +class NotificationSerializer(serializers.ModelSerializer): + user_type = serializers.ChoiceField(choices=[('user', 'User'), ('merchant', 'Merchant')], default='user') + + class Meta: + model = Notification + fields = ['id', 'title', 'message', 'is_read', 'user_type', 'created_at', 'updated_at'] + + + +class NotificationSendSerializer(serializers.Serializer): + title = serializers.CharField() + body = serializers.CharField() + data = serializers.DictField(required=False) + account_id = serializers.CharField(required=True) + user_type = serializers.CharField(required=True) \ No newline at end of file diff --git a/apps/account/urls.py b/apps/account/urls.py index 9f3229d..390c183 100644 --- a/apps/account/urls.py +++ b/apps/account/urls.py @@ -25,6 +25,8 @@ urlpatterns = [ path('recover/', views.UserRecoverPassword.as_view(), name='user-recover'), path('reset/', views.UserResetPassword.as_view(), name='user-reset'), + path('notif/', views.NotificationListView.as_view(), name='user-notif'), + path('notif/read', views.NotificationReadAllView.as_view(), name='user-notif-read-all'), # # URL to update user details, supports PUT to update user fields like phone or email given a token. path('profile/update/', views.UserUpdateView.as_view(), name='user-update'), diff --git a/apps/account/views/__init__.py b/apps/account/views/__init__.py index f4a2da0..1668457 100644 --- a/apps/account/views/__init__.py +++ b/apps/account/views/__init__.py @@ -1 +1,3 @@ from .user import * +from .notification import * + diff --git a/apps/account/views/notification.py b/apps/account/views/notification.py new file mode 100644 index 0000000..67258cd --- /dev/null +++ b/apps/account/views/notification.py @@ -0,0 +1,63 @@ + +from rest_framework import generics, status +from rest_framework.response import Response +from drf_yasg.utils import swagger_auto_schema +from drf_yasg import openapi +from rest_framework.permissions import IsAuthenticated +from apps.account.serializers import NotificationSerializer, NotificationSendSerializer +from apps.account.models import Notification +# from apps.account.fcm_notification import send_notification + + + +class NotificationListView(generics.ListAPIView): + queryset = Notification.objects.all() + serializer_class = NotificationSerializer + permission_classes = [IsAuthenticated,] + + @swagger_auto_schema( + operation_description="Retrieve a list of notifications for the authenticated user or merchant account.", + tags=['Notifications'] + ) + def get(self, request, *args, **kwargs): + """ + This API allows you to retrieve a list of notifications based on the authenticated user's type. + If the user is a regular user, their notifications will be fetched from the `Notification` model. + If the user is a merchant, their notifications will be fetched from the `MerchantAccountNotification` model. + + - **Method**: GET + - **URL**: /api/notifications/ + - **Response**: Includes details of notifications such as title, message, is read status, creation date, and update date. + - **Headers**: `Authorization: Bearer ` for authentication. + """ + return super().get(request, *args, **kwargs) + + def get_queryset(self): + user = self.request.user + return Notification.objects.filter(user=user).order_by('-created_at') + + +class NotificationReadAllView(generics.GenericAPIView): + permission_classes = [IsAuthenticated,] + queryset = Notification.objects.all() + + + @swagger_auto_schema( + operation_description="Mark all notifications as read for the authenticated user or merchant account.", + tags=['Notifications'], + responses={ + 200: "All notifications marked as read", + 403: "Forbidden", + } + ) + def get(self, request, *args, **kwargs): + user = request.user + + notifications = Notification.objects.filter(user=user) + + notifications.update(is_read=True) + return Response({'status': 'all notifications marked as read'}, status=status.HTTP_200_OK) + + + + diff --git a/errors.json b/errors.json new file mode 100644 index 0000000..8955889 --- /dev/null +++ b/errors.json @@ -0,0 +1,14 @@ +{ + "This email is already registered.": "Этот адрес электронной почты уже зарегистрирован.", + "Passwords do not match.": "Пароли не совпадают.", + "Password must be at least 8 characters long.": "Пароль должен содержать не менее 8 символов.", + "Verification data not found or expired.": "Данные верификации не найдены или устарели.", + "The verification code has expired.": "Срок действия кода подтверждения истек.", + "code notfound": "код не найден", + "Unable to log in with provided credentials.": "Невозможно войти в систему с предоставленными учетными данными.", + "User does not exist.": "Пользователь не существует.", + "Course not found": "Курс не найден.", + "course not found": "курс не найден", + "you have already participated in the quiz": "вы уже участвовали в викторине", + "The email must be for the requesting user": "Электронная почта должна быть для запрашивающего пользователя" +} diff --git a/sshs b/sshs new file mode 100644 index 0000000..dc0a152 --- /dev/null +++ b/sshs @@ -0,0 +1,4 @@ +Host 88.99.212.243 + HostName 88.99.212.243 + User nwhco + Port 1782