Compare commits

...

6 Commits

Author SHA1 Message Date
80577d89de Refactoring table into partial file 2025-07-19 11:32:33 +02:00
b4305aa7fa Adding bootstrap to project 2025-07-19 11:32:12 +02:00
f05116e01b Fixing wrong field names 2025-07-19 11:29:44 +02:00
1e720228be Reworking account handling
* allowing role management
* allowing user change without the need to update the password
2025-07-19 09:08:40 +02:00
69941166a1 Moving ALLOWED_HOSTS to env file 2025-07-18 17:33:49 +02:00
15750517f2 Adding .vs/* 2025-07-18 17:24:44 +02:00
11 changed files with 102 additions and 34 deletions

1
.gitignore vendored
View File

@ -136,3 +136,4 @@ GitHub.sublime-settings
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
.history .history
.vs/*

View File

@ -12,7 +12,8 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
import pymysql import pymysql
pymysql.install_as_MySQLdb() pymysql.install_as_MySQLdb()
from pathlib import Path from pathlib import Path
from decouple import config from decouple import config, Csv
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -27,7 +28,7 @@ SECRET_KEY = 'django-insecure-tulz*odc=l1x(g^-=ne!y7^@lg1uce)=ha^!0wi5qkifq&#^sg
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [ "albani.sternbauer.de" ] ALLOWED_HOSTS = config("DJANGO_ALLOWED_HOSTS", default="localhost", cast=Csv())
# Application definition # Application definition
@ -125,6 +126,10 @@ USE_TZ = True
STATIC_URL = 'static/' STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASEDIR / "static"
]
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

View File

@ -13,12 +13,19 @@ class PersonForm(forms.ModelForm):
class AccountForm(forms.ModelForm): class AccountForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput()) password=forms.CharField(widget=forms.PasswordInput(), required=False)
confirm_password=forms.CharField(widget=forms.PasswordInput()) confirm_password=forms.CharField(widget=forms.PasswordInput(), required=False)
class Meta: class Meta:
model = UserAccount model = UserAccount
fields = ['username', 'password'] fields = ['username', 'password', 'role']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk is None:
self.fields['password'].required=True
self.fields['confirm_password'].required=True
def clean(self): def clean(self):
cleaned_data = super(AccountForm, self).clean() cleaned_data = super(AccountForm, self).clean()
@ -27,4 +34,14 @@ class AccountForm(forms.ModelForm):
if passwordStr != confirm_passwordStr: if passwordStr != confirm_passwordStr:
raise forms.ValidateError("password and confirm_password does not match") raise forms.ValidateError("password and confirm_password does not match")
def save(self, commit=True):
user = super().save(commit=False)
pw = self.cleaned_data.get("password")
if pw:
user.set_password(pw)
if commit:
user.save()
return user

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.1 on 2025-07-18 15:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('member', '0002_alter_useraccount_options_alter_useraccount_managers_and_more'),
]
operations = [
migrations.AlterField(
model_name='useraccount',
name='role',
field=models.CharField(choices=[('mitglied', 'Mitglied'), ('geraetewart', 'Gerätewart'), ('kommandant', 'Kommandant'), ('admin', 'Administrator'), ('superadmin', 'Superadministrator')], default='mitglied', max_length=50),
),
]

View File

@ -11,7 +11,9 @@ class UserAccount(AbstractUser):
('geraetewart', 'Gerätewart'), ('geraetewart', 'Gerätewart'),
('kommandant', 'Kommandant'), ('kommandant', 'Kommandant'),
('admin', 'Administrator'), ('admin', 'Administrator'),
]) ('superadmin', 'Superadministrator'),
], default='mitglied')
def __str__(self): def __str__(self):
return f"{self.benutzername} ({self.rolle})" return f"{self.benutzername} ({self.rolle})"

View File

@ -16,6 +16,10 @@
<label for="{{form.password.id_for_label}}">Password (confirmation)</label> <label for="{{form.password.id_for_label}}">Password (confirmation)</label>
{{form.confirm_password}} {{form.confirm_password}}
</div> </div>
<div class="form-group">
<label for="{{form.role.id_for_label}}">Rolle</label>
{{form.role}}
</div>
<button class="button" type="submit">Speichern</button> <button class="button" type="submit">Speichern</button>
<a href="{% url 'details' id %}" class="button" style="background:#444;">Abbrechen</a> <a href="{% url 'details' id %}" class="button" style="background:#444;">Abbrechen</a>
</form> </form>

View File

@ -1,43 +1,22 @@
{% extends "master.html" %} {% extends "master.html" %}
{% load static %} {% load static %}
{% load svg %}
{% block title %} {% block title %}
Details zu {{ mymember.firstname }} {{ mymember.lastname }} Details zu {{ mymember.vorname }} {{ mymember.nachname }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="member-table"> <div class="member-table">
<h1>{{ mymember.vorname }} {{ mymember.nachname }}</h1> <h1>{{ mymember.vorname }} {{ mymember.nachname }}</h1>
<p>Geburtsdatum: {{ mymember.geburtsdatum }}</p> <p>Geburtsdatum: {{ mymember.geburtsdatum }}</p>
<table> <div class="mb-4">
<thead> <h2 class="h5">Accounts</h2>
<tr> {% include "partials/account_table.html" %}
<th>Name</th> </div>
<th>Rolle</th>
<th>Aktiv</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for x in accounts %}
<tr>
<td>{{ x.username }}</td>
<td>{{ x.rolle }}</td>
<td>{% if x.aktiv %}{% inline_svg 'icons/uxwing/check.svg' 'icon' %}{% endif %}</td>
<td><a href="{% url 'edit_account' x.id %}" title="Bearbeiten"><img src="{% static 'icons/heroicons/pencil.svg'%}" class="icon"></a> <a href="{% url 'delete_account' x.id %}" title="Löschen"><img src="{% static 'icons/heroicons/trash.svg'%}" class="icon"></a></td>
</tr>
{% endfor %}
<tr>
<td colspan="4">
<a href="{% url 'create_account' mymember.id %}" class="button"><img src="{% static 'icons/heroicons/plus.svg'%}" class="icon"> Konto hinzufügen</a>
</td>
</tr>
</tbody>
</table>
<p>Back to <a href="/members">Members</a></p> <p>Back to <a href="/members">Members</a></p>

View File

@ -3,6 +3,7 @@
<html> <html>
<head> <head>
<title>{% block title %}{% endblock %}</title> <title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'member/css/styles.css' %}"> <link rel="stylesheet" href="{% static 'member/css/styles.css' %}">
</head> </head>
<body> <body>

View File

@ -0,0 +1,28 @@
{% load static %}
{% load svg %}
<table>
<thead>
<tr>
<th>Name</th>
<th>Rolle</th>
<th>Aktiv</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for x in accounts %}
<tr>
<td>{{ x.username }}</td>
<td>{{ x.rolle }}</td>
<td>{% if x.aktiv %}{% inline_svg 'icons/uxwing/check.svg' 'icon' %}{% endif %}</td>
<td><a href="{% url 'edit_account' x.id %}" title="Bearbeiten"><img src="{% static 'icons/heroicons/pencil.svg'%}" class="icon"></a> <a href="{% url 'delete_account' x.id %}" title="Löschen"><img src="{% static 'icons/heroicons/trash.svg'%}" class="icon"></a></td>
</tr>
{% endfor %}
<tr>
<td colspan="4">
<a href="{% url 'create_account' mymember.id %}" class="button"><img src="{% static 'icons/heroicons/plus.svg'%}" class="icon"> Konto hinzufügen</a>
</td>
</tr>
</tbody>
</table>

6
static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
static/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long