Add sent-notes and archive

This commit is contained in:
2025-12-22 13:29:00 +05:30
parent c84866210a
commit 9724f834c0
6 changed files with 139 additions and 6 deletions

View File

@@ -11,10 +11,34 @@ class User(AbstractUser):
) )
expiry_seconds = models.PositiveIntegerField(default=86400) expiry_seconds = models.PositiveIntegerField(default=86400)
@property
def alive_created_notes(self) -> models.QuerySet["Note"]:
return (
self.created_notes.filter(expiry__gt=timezone.now())
.select_related("from_user", "to_user")
.order_by("-created_at")
)
@property
def all_created_notes(self) -> models.QuerySet["Note"]:
return self.created_notes.select_related("from_user", "to_user").order_by(
"-created_at"
)
@property @property
def alive_received_notes(self) -> models.QuerySet["Note"]: def alive_received_notes(self) -> models.QuerySet["Note"]:
return self.received_notes.filter(expiry__gt=timezone.now()).select_related( return (
"from_user", "to_user" self.received_notes.filter(expiry__gt=timezone.now())
.select_related("from_user", "to_user")
.order_by("-created_at")
)
@property
def expired_received_notes(self) -> models.QuerySet["Note"]:
return (
self.received_notes.filter(expiry__lte=timezone.now())
.select_related("from_user", "to_user")
.order_by("-created_at")
) )
@property @property

View File

@@ -119,8 +119,9 @@ select:nth-child(3n + 2), textarea:nth-child(3n + 2), button:nth-child(3n + 2),
background-color: #a4d6f7; background-color: #a4d6f7;
} }
.note-from, .note-at { .note-from, .note-to, .note-at {
text-align: right; text-align: right;
color: #333;
} }
@@ -137,3 +138,9 @@ select:nth-child(3n + 2), textarea:nth-child(3n + 2), button:nth-child(3n + 2),
border-radius: 25px 155px 15px 25px / 115px 25px 225px 150px; border-radius: 25px 155px 15px 25px / 115px 25px 225px 150px;
background-color: #fac9dc; background-color: #fac9dc;
} }
.title-and-link {
display: flex;
justify-content: space-between;
align-items: center;
}

View File

@@ -20,4 +20,40 @@
{% else %} {% else %}
<div class="card">No Notes found</div> <div class="card">No Notes found</div>
{% endif %} {% endif %}
<div class="title-and-link">
<h2>Active Sent Notes</h2>
<a href="{% url "sent-notes" %}">View All including expired</a>
</div>
{% if alive_created %}
<div class="notes">
{% for note in alive_created %}
<div class="note">
<p>{{ note.note }}</p>
<p class="note-from">From {{ note.from_user.visible_name }}</p>
<p class="note-at">{{ note.created_at|date:"j M Y, H:i"}}</p>
</div>
{% endfor %}
</div>
{% else %}
<div class="card">No Notes found</div>
{% endif %}
<div class="title-and-link">
<h2>Archived Notes</h2>
<a href="{% url "archive" %}">View All</a>
</div>
{% if archive %}
<div class="notes">
{% for note in archive %}
<div class="note">
<p>{{ note.note }}</p>
<p class="note-from">From {{ note.from_user.visible_name }}</p>
<p class="note-at">{{ note.created_at|date:"j M Y, H:i"}}</p>
</div>
{% endfor %}
</div>
{% else %}
<div class="card">No Notes found</div>
{% endif %}
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,24 @@
{% extends "notes/base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block body %}
<h1>{{ title }}</h1>
{% include "notes/messages.html" %}
{% if object_list %}
<div class="notes">
{% for note in object_list %}
<div class="note">
<p>{{ note.note }}</p>
{% if show_from %}<p class="note-from">From {{ note.from_user.visible_name }}</p>{% endif %}
{% if show_to %}<p class="note-to">To {{ note.to_user.visible_name }}</p>{% endif %}
<p class="note-at">{{ note.created_at|date:"j M Y, H:i"}}</p>
</div>
{% endfor %}
</div>
{% else %}
<div class="card">No Notes found</div>
{% endif %}
{% endblock %}

View File

@@ -5,11 +5,13 @@ from notes import views, api_views
urlpatterns = [ urlpatterns = [
path("", views.HomePage.as_view(), name="home"), path("", views.HomePageView.as_view(), name="home"),
path("post-a-note/", views.PostNoteView.as_view(), name="post-a-note"), path("post-a-note/", views.PostNoteView.as_view(), name="post-a-note"),
path("profile/", views.ProfileView.as_view(), name="profile"), path("profile/", views.ProfileView.as_view(), name="profile"),
path("login/", LoginView.as_view(), name="login"), path("login/", LoginView.as_view(), name="login"),
path("logout/", LogoutView.as_view(), name="logout"), path("logout/", LogoutView.as_view(), name="logout"),
path("archive/", views.ArchiveView.as_view(), name="archive"),
path("sent-notes/", views.SentNotesView.as_view(), name="sent-notes"),
path("api/notes/", api_views.NoteListView.as_view(), name="api-notes-list"), path("api/notes/", api_views.NoteListView.as_view(), name="api-notes-list"),
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
] ]

View File

@@ -2,23 +2,63 @@ from datetime import timedelta
from typing import Any from typing import Any
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.views.generic import CreateView, TemplateView, UpdateView from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.edit import FormMixin from django.views.generic.edit import FormMixin
from notes.models import Note, User from notes.models import Note, User
# Create your views here. # Create your views here.
class HomePage(LoginRequiredMixin, TemplateView): class HomePageView(LoginRequiredMixin, TemplateView):
template_name = "notes/home.html" template_name = "notes/home.html"
def get_context_data(self, **kwargs: Any) -> dict[str, Any]: def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
ctx["notes"] = self.request.user.alive_received_notes ctx["notes"] = self.request.user.alive_received_notes
ctx["archive"] = self.request.user.expired_received_notes[:5]
ctx["alive_created"] = self.request.user.alive_created_notes
return ctx return ctx
class NoteView(LoginRequiredMixin, ListView):
# TODO: Add pagination to the template
template_name = "notes/note_list.html"
show_from = True
show_to = True
def get_title(self):
if not hasattr(self, "title"):
raise ImproperlyConfigured(
"Set a `title` attribute on subclass or override `get_title(self)`"
)
return self.title
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
ctx = super().get_context_data(**kwargs)
ctx["title"] = self.get_title()
ctx["show_from"] = self.show_from
ctx["show_to"] = self.show_to
return ctx
class ArchiveView(NoteView):
title = "Archive"
show_to = False
def get_queryset(self):
return self.request.user.expired_received_notes
class SentNotesView(NoteView):
title = "Sent Notes"
show_from = False
def get_queryset(self):
return self.request.user.all_created_notes
class PostNoteView(LoginRequiredMixin, CreateView): class PostNoteView(LoginRequiredMixin, CreateView):
model = Note model = Note
fields = ["to_user", "note"] fields = ["to_user", "note"]