Merge branch '3-user-subject-relations' into 'master'

Added base for user-subject relations

See merge request JustScreaMy/facturio!4
This commit is contained in:
Jakub Kropáček 2024-02-03 20:54:05 +00:00
commit a6bac23b9f
13 changed files with 185 additions and 39 deletions

View file

@ -1,6 +1,13 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext_lazy as _
from .models import User
from . import models
admin.site.register(User, UserAdmin)
@admin.register(models.User)
class UserAdmin(BaseUserAdmin):
fieldsets = (
*BaseUserAdmin.fieldsets,
(_("Subjects"), {"fields": ("subjects",)})
)

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.1 on 2024-01-29 21:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0002_alter_user_email_alter_user_first_name_and_more"),
("subjects", "0003_alter_subject_options"),
]
operations = [
migrations.AddField(
model_name="user",
name="subjects",
field=models.ManyToManyField(to="subjects.subject"),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.1 on 2024-01-29 21:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0003_user_subjects"),
("subjects", "0003_alter_subject_options"),
]
operations = [
migrations.AlterField(
model_name="user",
name="subjects",
field=models.ManyToManyField(blank=True, to="subjects.subject"),
),
]

View file

@ -2,6 +2,8 @@ from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from subjects.models import Subject
class User(AbstractUser):
REQUIRED_FIELDS = ["email", "first_name", "last_name"]
@ -10,5 +12,7 @@ class User(AbstractUser):
last_name = models.CharField(_("last name"), max_length=150)
email = models.EmailField(_("email address"))
subjects = models.ManyToManyField(Subject, blank=True)
class Meta(AbstractUser.Meta):
pass
...

View file

@ -4,8 +4,8 @@
{% block title %}{% trans "About Me" %}{% endblock %}
{% block content %}
<h2 class="mb-4">{% trans "About Me" %}</h2>
<div class="card">
<h2 class="mb-2">{% trans "About Me" %}</h2>
<div class="card mb-2">
<h5 class="card-header">
{% blocktrans trimmed with firstname=request.user.first_name lastname=request.user.last_name %}Welcome,
{{ firstname }} {{ lastname }}!{% endblocktrans %}
@ -19,4 +19,14 @@
</li>
</ul>
</div>
{% if request.user.subjects.exists %}
<div class="card mb-2">
<h5 class="card-header">{% trans "Linked subjects" %}</h5>
<ul class="list-group list-group-flush">
{% for subject in request.user.subjects.all %}
<li class="list-group-item">{{ subject.name }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endblock %}

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-29 20:46+0000\n"
"POT-Creation-Date: 2024-02-01 20:43+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,25 +18,31 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
#: accounts/admin.py:12 subjects/models.py:9
#: subjects/templates/subjects/index.html:4 templates/facturio/base.html:20
msgid "Subjects"
msgstr "Subjekty"
#: accounts/forms.py:17 accounts/templates/account/login.html:6
#: templates/facturio/base.html:39
#: templates/facturio/base.html:42
msgid "Login"
msgstr "Přihlásit se"
#: accounts/forms.py:30 accounts/templates/account/register.html:6
#: templates/facturio/base.html:42
#: templates/facturio/base.html:45
msgid "Register"
msgstr "Registrovat se"
#: accounts/models.py:9
#: accounts/models.py:11
msgid "first name"
msgstr "křestní jméno"
#: accounts/models.py:10
#: accounts/models.py:12
msgid "last name"
msgstr "přijmení"
#: accounts/models.py:11
#: accounts/models.py:13
msgid "email address"
msgstr "emailová adresa"
@ -59,6 +65,10 @@ msgstr "Uživatelské jméno: %(username)s"
msgid "Email: %(email)s"
msgstr "Email: %(email)s"
#: accounts/templates/account/me.html:24
msgid "Linked subjects"
msgstr "Propojené Subjekty"
#: facturio/settings.py:109
msgid "English"
msgstr "Angličtina"
@ -92,11 +102,6 @@ msgstr "Vytvořit"
msgid "Subject"
msgstr "Subjekt"
#: subjects/models.py:9 subjects/templates/subjects/index.html:4
#: templates/facturio/base.html:19
msgid "Subjects"
msgstr "Subjekty"
#: subjects/models.py:18 subjects/templates/subjects/index.html:12
msgid "Name"
msgstr "Jméno"
@ -129,14 +134,26 @@ msgstr "Vytvořit Subjekty"
msgid "Add new"
msgstr "Přidat nový"
#: subjects/templates/subjects/index.html:18
msgid "Connect"
msgstr "Propojit"
#: subjects/templates/subjects/index.html:35
msgid "Link"
msgstr "Propojit"
#: subjects/templates/subjects/index.html:38
msgid "Unlink"
msgstr "Odpojit"
#: templates/facturio/base.html:8 templates/facturio/index.html:4
msgid "App"
msgstr "Aplikace"
#: templates/facturio/base.html:31
#: templates/facturio/base.html:34
msgid "Profile"
msgstr "Profil"
#: templates/facturio/base.html:34
#: templates/facturio/base.html:37
msgid "Logout"
msgstr "Odhlásit se"

View file

@ -0,0 +1,16 @@
# Generated by Django 5.0.1 on 2024-01-29 21:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("subjects", "0002_alter_subject_city_alter_subject_city_part_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="subject",
options={"verbose_name": "Subject", "verbose_name_plural": "Subjects"},
),
]

View file

@ -50,3 +50,6 @@ class Subject(models.Model):
def __str__(self):
return self.name
def get_linked_users(self) -> list[int]:
return list(self.user_set.values_list("id", flat=True))

View file

@ -15,19 +15,32 @@
<th>{% trans "Zip Code" %}</th>
<th>{% trans "City" %}</th>
<th>{% trans "City part" %}</th>
<th>{% trans "Connect" %}</th>
</tr>
</thead>
<tbody>
{% for subject in subjects %}
<tr>
<td>{{ subject.id }}</td>
<td>{{ subject.name }}</td>
<td>{{ subject.vat_id }}</td>
<td>{{ subject.street }}</td>
<td>{{ subject.zip_code }}</td>
<td>{{ subject.city }}</td>
<td>{{ subject.city_part }}</td>
</tr>
{# FIXME: in the future, or when this create problems, find a better way#}
{% with linked_users=subject.get_linked_users %}
<tr>
<td>{{ subject.id }}</td>
<td>{{ subject.name }}</td>
<td>{{ subject.vat_id }}</td>
<td>{{ subject.street }}</td>
<td>{{ subject.zip_code }}</td>
<td>{{ subject.city }}</td>
<td>{{ subject.city_part }}</td>
<td>
{% if request.user.id not in linked_users %}
<a href="{% url "subjects:link" subject_id=subject.id %}" class="btn btn-primary"
role="button">{% trans "Link" %}</a>
{% else %}
<a href="{% url "subjects:unlink" subject_id=subject.id %}" class="btn btn-danger"
role="button">{% trans "Unlink" %}</a>
{% endif %}
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>

View file

@ -6,5 +6,7 @@ app_name = "subjects"
urlpatterns = [
path("", views.main_page, name="list"),
path("new/", views.create_subject, name="create")
path("new/", views.create_subject, name="create"),
path("link/<int:subject_id>", views.link_subject, name="link"),
path("unlink/<int:subject_id>", views.unlink_subject, name="unlink")
]

View file

@ -1,4 +1,5 @@
from ares_util.ares import call_ares
from django.contrib.auth.decorators import login_required
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render, redirect
from django.urls import reverse
@ -10,11 +11,13 @@ def build_address(street: str, zip_code: int | str, city: str, city_part: str) -
return f"{street}, {zip_code}, {city} - {city_part}"
@login_required
def main_page(req: HttpRequest) -> HttpResponse:
subjects = models.Subject.objects.all()
return render(req, "subjects/index.html", dict(subjects=subjects))
@login_required
def create_subject(req: HttpRequest) -> HttpResponse:
if req.method == "POST":
form = forms.CreateSubjectForm(data=req.POST)
@ -45,3 +48,17 @@ def create_subject(req: HttpRequest) -> HttpResponse:
return render(req, "subjects/create.html", dict(form=form))
return HttpResponse(status=405)
@login_required
def link_subject(request: HttpRequest, subject_id: int) -> HttpResponse:
subject = models.Subject.objects.get(pk=subject_id)
subject.user_set.add(request.user)
return redirect(reverse("subjects:list"))
@login_required
def unlink_subject(request: HttpRequest, subject_id: int) -> HttpResponse:
subject = models.Subject.objects.get(pk=subject_id)
subject.user_set.remove(request.user)
return redirect(reverse("subjects:list"))

View file

@ -13,16 +13,19 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="{% url "main-page" %}">Facturio</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{% url "subjects:list" %}">{% trans "Subjects" %}</a>
</li>
{#<li class="nav-item">#}
{# <a class="nav-link" href="#">Item 2</a>#}
{#</li>#}
</ul>
</div>
{% if request.user.is_authenticated %}
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{% url "subjects:list" %}">{% trans "Subjects" %}</a>
</li>
{#<li class="nav-item">#}
{# <a class="nav-link" href="#">Item 2</a>#}
{#</li>#}
</ul>
</div>
{% endif %}
<div class="collapse navbar-collapse justify-content-end">
<ul class="navbar-nav">

18
utils/start.sh Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
#set -x
if [[ ! -f "manage.py" ]]; then
echo 'Control `manage.py` is not in current directory!'
echo 'Please, launch this script from the root directory'
echo 'Example: `./utils/start.sh`'
exit 1
fi
echo "Compiling messages!"
./manage.py compilemessages >/dev/null
echo "Migrating"
./manage.py migrate >/dev/null