base setup

This commit is contained in:
2026-01-07 12:09:20 +05:30
commit 0c275efea1
278 changed files with 11228 additions and 0 deletions

View File

View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View 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'

View 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

View File

@@ -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'],
},
),
]

View 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()

View 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 %}

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View 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"),
]

View 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
)

View 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")