Add login and home page
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
BIN
notes/static/notes/images/icons/post-a-note.png
Normal file
BIN
notes/static/notes/images/icons/post-a-note.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
BIN
notes/static/notes/images/icons/profile.png
Normal file
BIN
notes/static/notes/images/icons/profile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
107
notes/static/notes/stylesheets/style.css
Normal file
107
notes/static/notes/stylesheets/style.css
Normal 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;
|
||||
}
|
||||
|
||||
25
notes/templates/notes/base.html
Normal file
25
notes/templates/notes/base.html
Normal 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>
|
||||
22
notes/templates/notes/home.html
Normal file
22
notes/templates/notes/home.html
Normal 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 %}
|
||||
19
notes/templates/registration/login.html
Normal file
19
notes/templates/registration/login.html
Normal 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 %}
|
||||
@@ -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")),
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user