base setup
This commit is contained in:
0
at_django_boilerplate/notification/__init__.py
Executable file
0
at_django_boilerplate/notification/__init__.py
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
at_django_boilerplate/notification/admin.py
Executable file
3
at_django_boilerplate/notification/admin.py
Executable file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
at_django_boilerplate/notification/apps.py
Executable file
6
at_django_boilerplate/notification/apps.py
Executable file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NotificationConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'at_django_boilerplate.notification'
|
||||
10
at_django_boilerplate/notification/context_processors.py
Executable file
10
at_django_boilerplate/notification/context_processors.py
Executable file
@@ -0,0 +1,10 @@
|
||||
from at_django_boilerplate.notification.models import Notification
|
||||
|
||||
|
||||
def get_unread_messages(request):
|
||||
data = {'unread_count':0}
|
||||
if request.user.is_authenticated:
|
||||
x = Notification.objects.filter(recipient=request.user,
|
||||
is_read=False)
|
||||
data['unread_count'] = x.count()
|
||||
return data
|
||||
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.6 on 2025-12-29 05:20
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('message', models.TextField()),
|
||||
('is_read', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('is_archived', models.BooleanField(default=False)),
|
||||
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
at_django_boilerplate/notification/migrations/__init__.py
Executable file
0
at_django_boilerplate/notification/migrations/__init__.py
Executable file
Binary file not shown.
Binary file not shown.
22
at_django_boilerplate/notification/models.py
Executable file
22
at_django_boilerplate/notification/models.py
Executable file
@@ -0,0 +1,22 @@
|
||||
# notifications_app/models.py
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
class Notification(models.Model):
|
||||
recipient = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="notifications"
|
||||
)
|
||||
message = models.TextField()
|
||||
is_read = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
is_archived = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ["-created_at"]
|
||||
|
||||
def __str__(self):
|
||||
return f"To {self.recipient} - {self.message[:30]}"
|
||||
|
||||
def soft_delete(self):
|
||||
self.is_archived = True
|
||||
self.save()
|
||||
58
at_django_boilerplate/notification/templates/notifications_list.html
Executable file
58
at_django_boilerplate/notification/templates/notifications_list.html
Executable file
@@ -0,0 +1,58 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h4 d-flex align-items-center gap-2">
|
||||
<i class="fas fa-bell text-warning me-2"></i> Notifications
|
||||
</h1>
|
||||
{% if notifications %}
|
||||
<a href="{% url 'notification_mark_all_read' %}" class="btn btn-sm btn-primary">
|
||||
Mark all as read
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Notifications List -->
|
||||
<div class="list-group" style="max-height: 600px; overflow-y: auto;">
|
||||
{% for n in notifications %}
|
||||
<div class="list-group-item list-group-item-action d-flex justify-content-between align-items-start
|
||||
{% if not n.is_read %}bg-warning bg-opacity-25{% endif %}">
|
||||
|
||||
<!-- Icon + Content -->
|
||||
<div class="d-flex align-items-start gap-3">
|
||||
<div class="mt-1">
|
||||
{% if not n.is_read %}
|
||||
<i class="fas fa-circle text-warning small"></i>
|
||||
{% else %}
|
||||
<i class="fas fa-circle text-secondary small"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1">{{ n.message }}</p>
|
||||
<small class="text-muted">{{ n.created_at|date:"M d, Y H:i" }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="d-flex gap-2 ms-3">
|
||||
{% if not n.is_read %}
|
||||
<a href="{% url 'notification_mark_read' n.id %}" class="btn btn-sm btn-success d-flex align-items-center gap-1">
|
||||
<i class="fas fa-check"></i> Mark
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'notification_delete' n.id %}" class="btn btn-sm btn-danger d-flex align-items-center gap-1">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="text-center text-muted py-5">
|
||||
<i class="fas fa-inbox fa-3x mb-3"></i>
|
||||
<p class="mb-0">No notifications yet.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
3
at_django_boilerplate/notification/tests.py
Executable file
3
at_django_boilerplate/notification/tests.py
Executable file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
10
at_django_boilerplate/notification/urls.py
Executable file
10
at_django_boilerplate/notification/urls.py
Executable file
@@ -0,0 +1,10 @@
|
||||
# notifications_app/urls.py
|
||||
from django.urls import path
|
||||
from at_django_boilerplate.notification import views
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.notification_list, name="notification_list"),
|
||||
path("<int:pk>/read/", views.notification_mark_read, name="notification_mark_read"),
|
||||
path("<int:pk>/delete/", views.notification_delete, name="notification_delete"),
|
||||
path("mark-all-read/", views.notification_mark_all_read, name="notification_mark_all_read"),
|
||||
]
|
||||
8
at_django_boilerplate/notification/utils.py
Executable file
8
at_django_boilerplate/notification/utils.py
Executable file
@@ -0,0 +1,8 @@
|
||||
from at_django_boilerplate.notification.models import Notification
|
||||
|
||||
|
||||
def send_notification(recipient=None,message=None):
|
||||
Notification.objects.create(
|
||||
recipient=recipient,
|
||||
message=message
|
||||
)
|
||||
27
at_django_boilerplate/notification/views.py
Executable file
27
at_django_boilerplate/notification/views.py
Executable file
@@ -0,0 +1,27 @@
|
||||
# notifications_app/views.py
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from .models import Notification
|
||||
|
||||
@login_required
|
||||
def notification_list(request):
|
||||
notifications = request.user.notifications.filter(is_archived=False)
|
||||
return render(request, "notifications_list.html", {"notifications": notifications})
|
||||
|
||||
@login_required
|
||||
def notification_mark_read(request, pk):
|
||||
notification = get_object_or_404(Notification, pk=pk, recipient=request.user)
|
||||
notification.is_read = True
|
||||
notification.save()
|
||||
return redirect("notification_list")
|
||||
|
||||
@login_required
|
||||
def notification_delete(request, pk):
|
||||
notification = get_object_or_404(Notification, pk=pk, recipient=request.user)
|
||||
notification.soft_delete()
|
||||
return redirect("notification_list")
|
||||
|
||||
@login_required
|
||||
def notification_mark_all_read(request):
|
||||
request.user.notifications.update(is_read=True)
|
||||
return redirect("notification_list")
|
||||
Reference in New Issue
Block a user