Move the server code inside server dir
This commit is contained in:
0
server/notes/__init__.py
Normal file
0
server/notes/__init__.py
Normal file
28
server/notes/admin.py
Normal file
28
server/notes/admin.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
|
||||
from notes.models import Note, User
|
||||
|
||||
# Register your models here.
|
||||
#
|
||||
|
||||
|
||||
@admin.register(User)
|
||||
class UserAdmin(BaseUserAdmin):
|
||||
fieldsets = [
|
||||
*BaseUserAdmin.fieldsets,
|
||||
("Notes", {"fields": ("allow_notes_from", "expiry_seconds")}),
|
||||
]
|
||||
add_fieldsets = [
|
||||
*BaseUserAdmin.add_fieldsets,
|
||||
("Notes", {"fields": ("allow_notes_from", "expiry_seconds")}),
|
||||
]
|
||||
filter_horizontal = (
|
||||
*BaseUserAdmin.filter_horizontal,
|
||||
"allow_notes_from",
|
||||
)
|
||||
|
||||
|
||||
@admin.register(Note)
|
||||
class NoteAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
10
server/notes/api_views.py
Normal file
10
server/notes/api_views.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from rest_framework import generics
|
||||
|
||||
from notes.serializers import NoteSerializer
|
||||
|
||||
|
||||
class NoteListView(generics.ListCreateAPIView):
|
||||
serializer_class = NoteSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.user.alive_received_notes
|
||||
6
server/notes/apps.py
Normal file
6
server/notes/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NotesConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "notes"
|
||||
9
server/notes/forms.py
Normal file
9
server/notes/forms.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django import forms
|
||||
|
||||
from notes.models import Note
|
||||
|
||||
|
||||
class PostNoteForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Note
|
||||
fields = ["to_user", "note"]
|
||||
176
server/notes/migrations/0001_initial.py
Normal file
176
server/notes/migrations/0001_initial.py
Normal file
@@ -0,0 +1,176 @@
|
||||
# Generated by Django 5.2.8 on 2025-12-07 08:46
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="User",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||
verbose_name="superuser status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"username",
|
||||
models.CharField(
|
||||
error_messages={
|
||||
"unique": "A user with that username already exists."
|
||||
},
|
||||
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
||||
max_length=150,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.contrib.auth.validators.UnicodeUsernameValidator()
|
||||
],
|
||||
verbose_name="username",
|
||||
),
|
||||
),
|
||||
(
|
||||
"first_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="first name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="last name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"email",
|
||||
models.EmailField(
|
||||
blank=True, max_length=254, verbose_name="email address"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_staff",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates whether the user can log into this admin site.",
|
||||
verbose_name="staff status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
verbose_name="active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_joined",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, verbose_name="date joined"
|
||||
),
|
||||
),
|
||||
("expiry_seconds", models.PositiveIntegerField(default=86400)),
|
||||
(
|
||||
"allow_notes_from",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name="allowed_notes_to",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"groups",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.group",
|
||||
verbose_name="groups",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user_permissions",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Specific permissions for this user.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.permission",
|
||||
verbose_name="user permissions",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "user",
|
||||
"verbose_name_plural": "users",
|
||||
"abstract": False,
|
||||
},
|
||||
managers=[
|
||||
("objects", django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Note",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("note", models.TextField()),
|
||||
("expiry", models.DateTimeField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"from_user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="created_notes",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"to_user",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="received_notes",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
server/notes/migrations/__init__.py
Normal file
0
server/notes/migrations/__init__.py
Normal file
39
server/notes/models.py
Normal file
39
server/notes/models.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
|
||||
|
||||
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"
|
||||
)
|
||||
to_user = models.ForeignKey(
|
||||
User, on_delete=models.SET_NULL, null=True, related_name="received_notes"
|
||||
)
|
||||
note = models.TextField()
|
||||
expiry = models.DateTimeField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.from_user.username} -> {self.to_user.username}: {self.note[:30]}"
|
||||
56
server/notes/serializers.py
Normal file
56
server/notes/serializers.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
from rest_framework import serializers
|
||||
|
||||
from notes.models import Note, User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
username = serializers.CharField(max_length=150)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["id", "username", "first_name", "last_name", "visible_name"]
|
||||
read_only_fields = ["id", "first_name", "last_name", "visible_name"]
|
||||
|
||||
|
||||
class NoteSerializer(serializers.ModelSerializer):
|
||||
from_user = UserSerializer(read_only=True)
|
||||
to_user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Note
|
||||
fields = [
|
||||
"from_user",
|
||||
"to_user",
|
||||
"note",
|
||||
"expiry",
|
||||
"created_at",
|
||||
]
|
||||
read_only_fields = [
|
||||
"from_user",
|
||||
"created_at",
|
||||
"expiry",
|
||||
]
|
||||
|
||||
def validate_to_user(self, value):
|
||||
try:
|
||||
user = User.objects.get(username=value["username"])
|
||||
except User.DoesNotExist:
|
||||
raise serializers.ValidationError("User not found")
|
||||
|
||||
current_user = self.context["request"].user
|
||||
if not current_user.allowed_notes_to.filter(pk=user.pk).exists():
|
||||
raise serializers.ValidationError(
|
||||
f"User not allowed to post notes to {user!r}"
|
||||
)
|
||||
return user
|
||||
|
||||
def save(self, **kwargs):
|
||||
to_user = self.validated_data["to_user"]
|
||||
return Note.objects.create(
|
||||
from_user=self.context["request"].user,
|
||||
to_user=to_user,
|
||||
note=self.validated_data["note"],
|
||||
expiry=timezone.now() + timedelta(seconds=to_user.expiry_seconds),
|
||||
)
|
||||
BIN
server/notes/static/notes/images/icons/logout.png
Normal file
BIN
server/notes/static/notes/images/icons/logout.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
server/notes/static/notes/images/icons/paw.png
Normal file
BIN
server/notes/static/notes/images/icons/paw.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
server/notes/static/notes/images/icons/post-a-note.png
Normal file
BIN
server/notes/static/notes/images/icons/post-a-note.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
BIN
server/notes/static/notes/images/icons/profile.png
Normal file
BIN
server/notes/static/notes/images/icons/profile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
139
server/notes/static/notes/stylesheets/style.css
Normal file
139
server/notes/static/notes/stylesheets/style.css
Normal file
@@ -0,0 +1,139 @@
|
||||
* {
|
||||
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;
|
||||
margin-left: 20px;
|
||||
@media (max-width: 500px) {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
header img {
|
||||
height: 40px;
|
||||
margin: 20px;
|
||||
@media (max-width: 500px) {
|
||||
height: 25px;
|
||||
margin: 10px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.logout {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
padding: 5px;
|
||||
min-width: 200px;
|
||||
display: block;
|
||||
box-shadow: 15px 28px 25px -18px rgba(0, 0, 0, 0.1);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
select:nth-child(3n), textarea:nth-child(3n), button:nth-child(3n), input:nth-child(3n), .note:nth-child(3n) {
|
||||
border-radius: 155px 25px 15px 25px / 15px 225px 230px 150px;
|
||||
}
|
||||
|
||||
select:nth-child(3n + 1), textarea:nth-child(3n + 1), button:nth-child(3n + 1), input:nth-child(3n + 1), .note:nth-child(3n + 1) {
|
||||
border-radius: 25px 155px 15px 25px / 115px 25px 225px 150px;
|
||||
}
|
||||
|
||||
select:nth-child(3n + 2), textarea:nth-child(3n + 2), button:nth-child(3n + 2), input:nth-child(3n + 2), .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;
|
||||
}
|
||||
29
server/notes/templates/notes/base.html
Normal file
29
server/notes/templates/notes/base.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{% 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="{% url "post-a-note" %}">
|
||||
<img src="{% static "notes/images/icons/post-a-note.png" %}" alt="Post a note" title="Post a note" />
|
||||
</a>
|
||||
<a href="{% url "profile" %}">
|
||||
<img src="{% static "notes/images/icons/profile.png" %}" alt="Profile" title="Profile" />
|
||||
</a>
|
||||
<form method="post" action="{% url "logout" %}">
|
||||
{% csrf_token %}
|
||||
<button class="logout"><img src="{% static "notes/images/icons/logout.png" %}" alt="Logout" title="Logout" /></button>
|
||||
</form>
|
||||
</header>
|
||||
<main>
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
23
server/notes/templates/notes/home.html
Normal file
23
server/notes/templates/notes/home.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "notes/base.html" %}
|
||||
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Dashboard</h1>
|
||||
{% include "notes/messages.html" %}
|
||||
|
||||
<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 %}
|
||||
7
server/notes/templates/notes/messages.html
Normal file
7
server/notes/templates/notes/messages.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% if messages %}
|
||||
<div class="messages">
|
||||
{% for message in messages %}
|
||||
<div class="card">{{ message }}</li>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
12
server/notes/templates/notes/note_form.html
Normal file
12
server/notes/templates/notes/note_form.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{% extends "notes/base.html" %}
|
||||
|
||||
{% block title %}Post a Note{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Post a Note</h1>
|
||||
{% include "notes/messages.html" %}
|
||||
<form method="post">{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Post!</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
13
server/notes/templates/notes/user_form.html
Normal file
13
server/notes/templates/notes/user_form.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "notes/base.html" %}
|
||||
|
||||
{% block title %}Profile{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Profile</h1>
|
||||
{% include "notes/messages.html" %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
18
server/notes/templates/registration/login.html
Normal file
18
server/notes/templates/registration/login.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "notes/base.html" %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block body %}
|
||||
<div id="header">
|
||||
<h1>Appunti Login Screen</h1>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
{% include "notes/messages.html" %}
|
||||
<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>
|
||||
{% endblock %}
|
||||
0
server/notes/tests.py
Normal file
0
server/notes/tests.py
Normal file
15
server/notes/urls.py
Normal file
15
server/notes/urls.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.contrib.auth.views import LoginView, LogoutView
|
||||
from django.urls import include, path
|
||||
|
||||
from notes import views, api_views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.HomePage.as_view(), name="home"),
|
||||
path("post-a-note/", views.PostNoteView.as_view(), name="post-a-note"),
|
||||
path("profile/", views.ProfileView.as_view(), name="profile"),
|
||||
path("login/", LoginView.as_view(), name="login"),
|
||||
path("logout/", LogoutView.as_view(), name="logout"),
|
||||
path("api/notes/", api_views.NoteListView.as_view(), name="api-notes-list"),
|
||||
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
|
||||
]
|
||||
52
server/notes/views.py
Normal file
52
server/notes/views.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.views.generic import CreateView, TemplateView, UpdateView
|
||||
from django.views.generic.edit import FormMixin
|
||||
from notes.models import Note, User
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
class PostNoteView(LoginRequiredMixin, CreateView):
|
||||
model = Note
|
||||
fields = ["to_user", "note"]
|
||||
success_url = reverse_lazy("post-a-note")
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
form.fields["to_user"].queryset = self.request.user.allowed_notes_to.all()
|
||||
return form
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object = note = form.save(commit=False)
|
||||
note.expiry = timezone.now() + timedelta(seconds=note.to_user.expiry_seconds)
|
||||
note.from_user = self.request.user
|
||||
note.save()
|
||||
messages.success(self.request, "Note has been posted!")
|
||||
return FormMixin.form_valid(self, form)
|
||||
|
||||
|
||||
class ProfileView(LoginRequiredMixin, UpdateView):
|
||||
model = User
|
||||
fields = ["first_name", "last_name", "allow_notes_from", "expiry_seconds"]
|
||||
success_url = reverse_lazy("profile")
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
||||
def form_valid(self, form):
|
||||
ret = super().form_valid(form)
|
||||
messages.success(self.request, "Profile has been updated!")
|
||||
return ret
|
||||
Reference in New Issue
Block a user