Add login and home page

This commit is contained in:
2025-12-10 18:28:07 +05:30
parent df595e4f19
commit 27aac4da8c
13 changed files with 239 additions and 3 deletions

View File

@@ -9,4 +9,4 @@ class NoteListView(generics.ListCreateAPIView):
serializer_class = NoteSerializer
def get_queryset(self):
return Note.objects.filter(to_user=self.request.user, expiry__gt=timezone.now()).select_related("from_user", "to_user")
return self.request.user.alive_received_notes

View File

@@ -1,5 +1,6 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
# Create your models here.
@@ -7,6 +8,16 @@ class User(AbstractUser):
allow_notes_from = models.ManyToManyField('User', related_name='allowed_notes_to', blank=True)
expiry_seconds = models.PositiveIntegerField(default=86400)
@property
def alive_received_notes(self) -> models.QuerySet["Note"]:
return self.received_notes.filter(expiry__gt=timezone.now()).select_related("from_user", "to_user")
@property
def visible_name(self) -> str:
if self.first_name or self.last_name:
return self.get_full_name()
return self.username
class Note(models.Model):
from_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_notes')

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,107 @@
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background-color: #f4f0f0;
font-family: cursive;
}
header {
width: 100%;
display: flex;
background-color: #e7bbe0;
}
header > .home {
flex-grow: 1;
font-size: 3em;
text-decoration: none;
color: #000;
}
header img {
height: 40px;
margin: 20px;
}
main {
padding: 0 30px;
}
.notes {
width: 100%;
columns: auto 300px;
column-gap: 80px;
justify-content: center;
align-content: center;
align-items: center;
margin: auto;
}
.notes.notes-grid {
display: grid;
}
.note {
display: inline-block;
width: 100%;
max-width: 300px;
padding: 30px;
border: 2px solid rgba(30, 30, 30, 0.4);
font-weight: 400;
font-style: normal;
box-shadow: 15px 28px 25px -18px rgba(0, 0, 0, 0.2);
text-align: center;
margin-bottom: 40px;
}
.note:nth-child(3n) {
border-radius: 155px 25px 15px 25px / 15px 225px 230px 150px;
}
.note:nth-child(3n + 1) {
border-radius: 25px 155px 15px 25px / 115px 25px 225px 150px;
}
.note:nth-child(3n + 2) {
border-radius: 25px 150px 25px 155px / 115px 25px 225px 50px;
}
.note:nth-child(4n) {
background-color: #d4f2d8;
}
.note:nth-child(4n + 1) {
background-color: #fac9dc;
}
.note:nth-child(4n + 2) {
background-color: #fff372;
}
.note:nth-child(4n + 3) {
background-color: #a4d6f7;
}
.note-from, .note-at {
text-align: right;
}
.card {
display: inline-block;
width: 100%;
padding: 30px;
border: 2px solid rgba(30, 30, 30, 0.4);
font-weight: 400;
font-style: normal;
box-shadow: 15px 28px 25px -18px rgba(0, 0, 0, 0.2);
text-align: center;
margin-bottom: 40px;
border-radius: 25px 155px 15px 25px / 115px 25px 225px 150px;
background-color: #fac9dc;
}

View File

@@ -0,0 +1,25 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="{% static "notes/stylesheets/style.css" %}" type="text/css">
<title>{% block title %}{% endblock %} | Appunti</title>
</head>
<body>
<header>
<a href="{% url "home" %}" class="home">Appunti</a>
<a href="#">
<img src="{% static "notes/images/icons/post-a-note.png" %}" alt="Post a note" title="Post a note" />
</a>
<a href="#">
<img src="{% static "notes/images/icons/profile.png" %}" alt="Profile" title="Profile" />
</a>
</header>
<main>
{% block body %}
{% endblock %}
</main>
</body>
</html>

View File

@@ -0,0 +1,22 @@
{% extends "notes/base.html" %}
{% block title %}Dashboard{% endblock %}
{% block body %}
<h1>Dashboard</h1>
<h2>Notes for you</h2>
{% if notes %}
<div class="notes">
{% for note in notes %}
<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, H:i"}}</p>
</div>
{% endfor %}
</div>
{% else %}
<div class="card">No Notes found</div>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,19 @@
{% extends "notes/base.html" %}
{% block title %}Login{% endblock %}
{% block body %}
<div id="header">
<h1>Appunti Login Screen</h1>
</div>
<div class="body">
<div class="login">
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<h2>Welcome!</h2>
<p>Please login to continue</p>
{{ form.as_p }}
<button type="submit">Login</button>
</form>
</div>
</div>
{% endblock %}

View File

@@ -1,9 +1,12 @@
from django.contrib.auth.views import LoginView
from django.urls import include, path
from notes import api_views
from notes import views, api_views
urlpatterns = [
path("", views.HomePage.as_view(), name="home"),
path("login/", LoginView.as_view(), name='login'),
path("api/notes/", api_views.NoteListView.as_view(), name="api-notes-list"),
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
]

View File

@@ -1,3 +1,12 @@
from django.shortcuts import render
from typing import Any
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
# Create your views here.
class HomePage(LoginRequiredMixin, TemplateView):
template_name = "notes/home.html"
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
ctx = super().get_context_data(**kwargs)
ctx['notes'] = self.request.user.alive_received_notes
return ctx