Initial commit
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
from django.contrib import admin
|
||||
from .models import Role, UserProfile
|
||||
|
||||
|
||||
@admin.register(Role)
|
||||
class RoleAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = [
|
||||
"name",
|
||||
]
|
||||
|
||||
search_fields = [
|
||||
"name",
|
||||
]
|
||||
|
||||
|
||||
@admin.register(UserProfile)
|
||||
class UserProfileAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = [
|
||||
"user",
|
||||
"role",
|
||||
]
|
||||
|
||||
list_filter = [
|
||||
"role",
|
||||
]
|
||||
|
||||
search_fields = [
|
||||
"user__username",
|
||||
"user__first_name",
|
||||
"user__last_name",
|
||||
"user__email",
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccountsConfig(AppConfig):
|
||||
name = 'accounts'
|
||||
@@ -0,0 +1,50 @@
|
||||
from functools import wraps
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
def permission_required(permission):
|
||||
|
||||
def decorator(view_func):
|
||||
|
||||
@wraps(view_func)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
|
||||
# Superuser haben alles
|
||||
if request.user.is_superuser:
|
||||
return view_func(
|
||||
request,
|
||||
*args,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
profile = getattr(
|
||||
request.user,
|
||||
"profile",
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
if profile and profile.has_permission(permission):
|
||||
|
||||
return view_func(
|
||||
request,
|
||||
*args,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
messages.error(
|
||||
request,
|
||||
"Keine Berechtigung für diese Aktion!"
|
||||
)
|
||||
|
||||
|
||||
return redirect("core:dashboard")
|
||||
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
@@ -0,0 +1,61 @@
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from .models import Role
|
||||
from core.forms.base import BaseForm
|
||||
|
||||
class UserAddForm(BaseForm):
|
||||
|
||||
password = forms.CharField(
|
||||
label="Passwort",
|
||||
widget=forms.PasswordInput
|
||||
)
|
||||
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=Role.objects.order_by("name"),
|
||||
required=False,
|
||||
label="Rolle"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
fields = [
|
||||
"username",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
]
|
||||
|
||||
labels = {
|
||||
"username": "Benutzername",
|
||||
"first_name": "Vorname",
|
||||
"last_name": "Nachname",
|
||||
"email": "E-Mail",
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
"username": "",
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
|
||||
|
||||
class RoleForm(BaseForm):
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
|
||||
labels = {
|
||||
"name": "Rollenname",
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
@@ -0,0 +1,97 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-23 22:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, unique=True, verbose_name='Rolle')),
|
||||
('projects_view', models.BooleanField(default=False, help_text='Benutzer darf Projekte einsehen.', verbose_name='Projekte anzeigen')),
|
||||
('projects_archived_view', models.BooleanField(default=False, help_text='Benutzer darf archivierte Projekte einsehen.', verbose_name='Archivierte Projekte anzeigen')),
|
||||
('projects_detail_view', models.BooleanField(default=False, help_text='Benutzer darf Details des Projekts einsehen.', verbose_name='Projektdetails anzeigen')),
|
||||
('projects_add', models.BooleanField(default=False, help_text='Benutzer darf neue Projekte anlegen.', verbose_name='Projekt erstellen')),
|
||||
('projects_contact_add', models.BooleanField(default=False, help_text='Benutzer darf Kontakte mit dem Projekt verknüpfen.', verbose_name='Projektkontakt verknüpfen')),
|
||||
('projects_contact_delete', models.BooleanField(default=False, help_text='Benutzer darf Kontakte aus dem Projekt entfernen.', verbose_name='Projektkontakt entfernen')),
|
||||
('projects_location_add', models.BooleanField(default=False, help_text='Benutzer darf Standorte mit dem Projekt verknüpfen.', verbose_name='Projektstandort verknüpfen')),
|
||||
('projects_location_delete', models.BooleanField(default=False, help_text='Benutzer darf Standorte aus dem Projekt entfernen.', verbose_name='Projektstandort entfernen')),
|
||||
('projects_edit', models.BooleanField(default=False, help_text='Benutzer darf Projekte ändern.', verbose_name='Projekte bearbeiten')),
|
||||
('projects_user_add', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter im Projekt hinzufügen.', verbose_name='Projektmitarbeiter erstellen')),
|
||||
('projects_user_delete', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter aus dem Projekt entfernen.', verbose_name='Projektmitarbeiter entfernen')),
|
||||
('projects_finance_view', models.BooleanField(default=False, help_text='Benutzer darf Projektfinanzen einsehen.', verbose_name='Projektfinanzen anzeigen')),
|
||||
('projects_finance_income_add', models.BooleanField(default=False, help_text='Benutzer darf Einnahmen hinzufügen.', verbose_name='Projekteinnahmen erfassen')),
|
||||
('projects_finance_expense_add', models.BooleanField(default=False, help_text='Benutzer darf Ausgaben hinzufügen.', verbose_name='Projektausgaben erfassen')),
|
||||
('projects_time_tracking_view', models.BooleanField(default=False, help_text='Benutzer darf Projektzeiten sehen.', verbose_name='Projektzeiten anzeigen')),
|
||||
('projects_time_tracking_edit', models.BooleanField(default=False, help_text='Benutzer darf Projektzeiten ändern.', verbose_name='Projektzeiten bearbeiten')),
|
||||
('projects_time_tracking_delete', models.BooleanField(default=False, help_text='Benutzer darf Projektzeiten löschen.', verbose_name='Projektzeiten löschen')),
|
||||
('projects_documents_view', models.BooleanField(default=False, help_text='Benutzer darf Dokumente sehen.', verbose_name='Projektdokumente anzeigen')),
|
||||
('projects_documents_add', models.BooleanField(default=False, help_text='Benutzer darf Dokumente hochladen.', verbose_name='Projektdokumente hinzufügen')),
|
||||
('projects_documents_delete', models.BooleanField(default=False, help_text='Benutzer darf Dokumente löschen.', verbose_name='Projektdokumente löschen')),
|
||||
('projects_inventory_inventory_view', models.BooleanField(default=False, help_text='Benutzer darf Projektinventar sehen.', verbose_name='Projektinventar anzeigen')),
|
||||
('projects_inventory_inventory_add', models.BooleanField(default=False, help_text='Benutzer darf Inventar hinzufügen.', verbose_name='Projektinventar hinzufügen')),
|
||||
('projects_inventory_inventory_edit', models.BooleanField(default=False, help_text='Benutzer darf Inventar ändern.', verbose_name='Projektinventar bearbeiten')),
|
||||
('projects_inventory_inventory_delete', models.BooleanField(default=False, help_text='Benutzer darf Inventar löschen.', verbose_name='Projektinventar löschen')),
|
||||
('projects_inventory_shopping_add', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen erstellen.', verbose_name='Einkauf hinzufügen')),
|
||||
('projects_inventory_shopping_edit', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen ändern.', verbose_name='Einkauf bearbeiten')),
|
||||
('projects_inventory_shopping_delete', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen löschen.', verbose_name='Einkauf löschen')),
|
||||
('inventory_view', models.BooleanField(default=False, help_text='Benutzer darf Inventar einsehen.', verbose_name='Inventar anzeigen')),
|
||||
('inventory_add', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge erstellen.', verbose_name='Inventar hinzufügen')),
|
||||
('inventory_edit', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge ändern.', verbose_name='Inventar bearbeiten')),
|
||||
('inventory_delete', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge löschen.', verbose_name='Inventar löschen')),
|
||||
('invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen verwalten.', verbose_name='Rechnungsbereich anzeigen')),
|
||||
('invoices_customers_view', models.BooleanField(default=False, help_text='Benutzer darf Kunden sehen.', verbose_name='Kunden anzeigen')),
|
||||
('invoices_customers_detail_view', models.BooleanField(default=False, help_text='Benutzer darf Details des Kunden sehen.', verbose_name='Kundendetails anzeigen')),
|
||||
('invoices_customers_add', models.BooleanField(default=False, help_text='Benutzer darf Kunden anlegen.', verbose_name='Kunden erstellen')),
|
||||
('invoices_customers_edit', models.BooleanField(default=False, help_text='Benutzer darf Kunden ändern.', verbose_name='Kunden bearbeiten')),
|
||||
('invoices_customers_archive', models.BooleanField(default=False, help_text='Benutzer darf Kunden archivieren.', verbose_name='Kunden archivieren')),
|
||||
('invoices_customers_activate', models.BooleanField(default=False, help_text='Benutzer darf Kunden wieder aktivieren.', verbose_name='Kunden reaktivieren')),
|
||||
('invoices_items_view', models.BooleanField(default=False, help_text='Benutzer darf Artikel sehen.', verbose_name='Artikel anzeigen')),
|
||||
('invoices_items_add', models.BooleanField(default=False, help_text='Benutzer darf Artikel erstellen.', verbose_name='Artikel erstellen')),
|
||||
('invoices_items_edit', models.BooleanField(default=False, help_text='Benutzer darf Artikel ändern.', verbose_name='Artikel bearbeiten')),
|
||||
('invoices_items_delete', models.BooleanField(default=False, help_text='Benutzer darf Artikel löschen.', verbose_name='Artikel löschen')),
|
||||
('invoices_invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen sehen.', verbose_name='Rechnungen anzeigen')),
|
||||
('invoices_invoices_project_add', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen aus Projekten erstellen.', verbose_name='Projekt-Rechnung erstellen')),
|
||||
('invoices_invoices_customer_add', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen für Kunden erstellen.', verbose_name='Kunden-Rechnung erstellen')),
|
||||
('invoices_invoices_invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungsdetails sehen.', verbose_name='Rechnungsdetails anzeigen')),
|
||||
('invoices_invoices_invoices_item_add', models.BooleanField(default=False, help_text='Benutzer darf Positionen hinzufügen.', verbose_name='Rechnungsposition hinzufügen')),
|
||||
('invoices_invoices_invoices_item_delete', models.BooleanField(default=False, help_text='Benutzer darf Positionen löschen.', verbose_name='Rechnungsposition löschen')),
|
||||
('invoices_invoices_invoices_preview', models.BooleanField(default=False, help_text='Benutzer darf Vorschauen öffnen.', verbose_name='Rechnungsvorschau anzeigen')),
|
||||
('users_view', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter sehen.', verbose_name='Benutzer anzeigen')),
|
||||
('users_add', models.BooleanField(default=False, help_text='Benutzer darf neue Mitarbeiter anlegen.', verbose_name='Benutzer erstellen')),
|
||||
('users_edit', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter bearbeiten.', verbose_name='Benutzer bearbeiten')),
|
||||
('users_archive', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter deaktivieren.', verbose_name='Benutzer archivieren')),
|
||||
('users_activate', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter aktivieren.', verbose_name='Benutzer aktivieren')),
|
||||
('users_groups_add', models.BooleanField(default=False, help_text='Benutzer darf neue Rollen erstellen.', verbose_name='Rollen erstellen')),
|
||||
('users_groups_edit', models.BooleanField(default=False, help_text='Benutzer darf Rollen und Berechtigungen ändern.', verbose_name='Rollen bearbeiten')),
|
||||
('users_groups_delete', models.BooleanField(default=False, help_text='Benutzer darf Rollen entfernen.', verbose_name='Rollen löschen')),
|
||||
('settings_view', models.BooleanField(default=False, help_text='Benutzer darf Einstellungskategorien sehen.', verbose_name='Einstellungsübersicht anzeigen')),
|
||||
('settings_detail_view', models.BooleanField(default=False, help_text='Benutzer darf Systemeinstellungen sehen.', verbose_name='Einstellungen anzeigen')),
|
||||
('settings_add', models.BooleanField(default=False, help_text='Benutzer darf neue Einstellungen hinzufügen.', verbose_name='Einstellungen erstellen')),
|
||||
('settings_delete', models.BooleanField(default=False, help_text='Benutzer darf Einstellungen entfernen.', verbose_name='Einstellungen löschen')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Rolle',
|
||||
'verbose_name_plural': 'Rollen',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.role')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-23 23:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_invoices_invoices_download',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Rechnungen herunterladen.', verbose_name='Rechnung herunterladen'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-24 08:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0002_role_invoices_invoices_invoices_download'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_invoices_invoices_cancel',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Rechnungen stornieren.', verbose_name='Rechnung stornieren'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-24 09:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0003_role_invoices_invoices_invoices_cancel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_invoices_invoices_cancel_download',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Stornorechnungen herunterladen.', verbose_name='Stornorechnung Download'),
|
||||
),
|
||||
]
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-24 13:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0004_role_invoices_invoices_invoices_cancel_download'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='role',
|
||||
name='invoices_invoices_invoices_cancel_download',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_invoices_invoices_paid',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Rechnungsstatus ändern.', verbose_name='Rechnung auf bezahlt setzen'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,53 @@
|
||||
# Generated by Django 6.0.6 on 2026-06-25 16:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0005_remove_role_invoices_invoices_invoices_cancel_download_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_add',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Angebote für Kunden erstellen.', verbose_name='Angebot erstellen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_download',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Angebote herunterladen.', verbose_name='Angebot herunterladen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_item_add',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Positionen hinzufügen.', verbose_name='Angebotsposition hinzufügen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_item_delete',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Positionen löschen.', verbose_name='Angebotsposition löschen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_preview',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Vorschauen öffnen.', verbose_name='Angebotsvorschau anzeigen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_status',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Angebotsstatus ändern.', verbose_name='Angebotsstatus bearbeiten'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_offers_view',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Angebotsdetails sehen.', verbose_name='Angebotsdetails anzeigen'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='invoices_offers_view',
|
||||
field=models.BooleanField(default=False, help_text='Benutzer darf Angebote sehen.', verbose_name='Angebote anzeigen'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,193 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Role(models.Model):
|
||||
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
unique=True,
|
||||
verbose_name="Rolle"
|
||||
)
|
||||
|
||||
projects_view = models.BooleanField(default=False, verbose_name="Projekte anzeigen", help_text="Benutzer darf Projekte einsehen.")
|
||||
projects_archived_view = models.BooleanField(default=False, verbose_name="Archivierte Projekte anzeigen", help_text="Benutzer darf archivierte Projekte einsehen.")
|
||||
projects_detail_view = models.BooleanField(default=False, verbose_name="Projektdetails anzeigen", help_text="Benutzer darf Details des Projekts einsehen.")
|
||||
projects_add = models.BooleanField(default=False, verbose_name="Projekt erstellen", help_text="Benutzer darf neue Projekte anlegen.")
|
||||
projects_contact_add = models.BooleanField(default=False, verbose_name="Projektkontakt verknüpfen", help_text="Benutzer darf Kontakte mit dem Projekt verknüpfen.")
|
||||
projects_contact_delete = models.BooleanField(default=False, verbose_name="Projektkontakt entfernen", help_text="Benutzer darf Kontakte aus dem Projekt entfernen.")
|
||||
projects_location_add = models.BooleanField(default=False, verbose_name="Projektstandort verknüpfen", help_text="Benutzer darf Standorte mit dem Projekt verknüpfen.")
|
||||
projects_location_delete = models.BooleanField(default=False, verbose_name="Projektstandort entfernen", help_text="Benutzer darf Standorte aus dem Projekt entfernen.")
|
||||
projects_edit = models.BooleanField(default=False, verbose_name="Projekte bearbeiten", help_text="Benutzer darf Projekte ändern.")
|
||||
|
||||
projects_user_add = models.BooleanField(default=False, verbose_name="Projektmitarbeiter erstellen", help_text="Benutzer darf Mitarbeiter im Projekt hinzufügen.")
|
||||
projects_user_delete = models.BooleanField(default=False, verbose_name="Projektmitarbeiter entfernen", help_text="Benutzer darf Mitarbeiter aus dem Projekt entfernen.")
|
||||
|
||||
projects_finance_view = models.BooleanField(default=False, verbose_name="Projektfinanzen anzeigen", help_text="Benutzer darf Projektfinanzen einsehen.")
|
||||
projects_finance_income_add = models.BooleanField(default=False, verbose_name="Projekteinnahmen erfassen", help_text="Benutzer darf Einnahmen hinzufügen.")
|
||||
projects_finance_expense_add = models.BooleanField(default=False, verbose_name="Projektausgaben erfassen", help_text="Benutzer darf Ausgaben hinzufügen.")
|
||||
|
||||
projects_time_tracking_view = models.BooleanField(default=False, verbose_name="Projektzeiten anzeigen", help_text="Benutzer darf Projektzeiten sehen.")
|
||||
projects_time_tracking_edit = models.BooleanField(default=False, verbose_name="Projektzeiten bearbeiten", help_text="Benutzer darf Projektzeiten ändern.")
|
||||
projects_time_tracking_delete = models.BooleanField(default=False, verbose_name="Projektzeiten löschen", help_text="Benutzer darf Projektzeiten löschen.")
|
||||
|
||||
projects_documents_view = models.BooleanField(default=False, verbose_name="Projektdokumente anzeigen", help_text="Benutzer darf Dokumente sehen.")
|
||||
projects_documents_add = models.BooleanField(default=False, verbose_name="Projektdokumente hinzufügen", help_text="Benutzer darf Dokumente hochladen.")
|
||||
projects_documents_delete = models.BooleanField(default=False, verbose_name="Projektdokumente löschen", help_text="Benutzer darf Dokumente löschen.")
|
||||
|
||||
projects_inventory_inventory_view = models.BooleanField(default=False, verbose_name="Projektinventar anzeigen", help_text="Benutzer darf Projektinventar sehen.")
|
||||
projects_inventory_inventory_add = models.BooleanField(default=False, verbose_name="Projektinventar hinzufügen", help_text="Benutzer darf Inventar hinzufügen.")
|
||||
projects_inventory_inventory_edit = models.BooleanField(default=False, verbose_name="Projektinventar bearbeiten", help_text="Benutzer darf Inventar ändern.")
|
||||
projects_inventory_inventory_delete = models.BooleanField(default=False, verbose_name="Projektinventar löschen", help_text="Benutzer darf Inventar löschen.")
|
||||
|
||||
projects_inventory_shopping_add = models.BooleanField(default=False, verbose_name="Einkauf hinzufügen", help_text="Benutzer darf Einkaufspositionen erstellen.")
|
||||
projects_inventory_shopping_edit = models.BooleanField(default=False, verbose_name="Einkauf bearbeiten", help_text="Benutzer darf Einkaufspositionen ändern.")
|
||||
projects_inventory_shopping_delete = models.BooleanField(default=False, verbose_name="Einkauf löschen", help_text="Benutzer darf Einkaufspositionen löschen.")
|
||||
#projects_inventory_shopping_buy = models.BooleanField(default=False, verbose_name="Einkäufe durchführen", help_text="Benutzer darf Einkäufe als erledigt markieren.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Inventar
|
||||
# =====================
|
||||
inventory_view = models.BooleanField(default=False, verbose_name="Inventar anzeigen", help_text="Benutzer darf Inventar einsehen.")
|
||||
inventory_add = models.BooleanField(default=False, verbose_name="Inventar hinzufügen", help_text="Benutzer darf Inventareinträge erstellen.")
|
||||
inventory_edit = models.BooleanField(default=False, verbose_name="Inventar bearbeiten", help_text="Benutzer darf Inventareinträge ändern.")
|
||||
inventory_delete = models.BooleanField(default=False, verbose_name="Inventar löschen", help_text="Benutzer darf Inventareinträge löschen.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Rechnungen
|
||||
# =====================
|
||||
invoices_view = models.BooleanField(default=False, verbose_name="Rechnungsbereich anzeigen", help_text="Benutzer darf Rechnungen verwalten.")
|
||||
|
||||
invoices_customers_view = models.BooleanField(default=False, verbose_name="Kunden anzeigen", help_text="Benutzer darf Kunden sehen.")
|
||||
invoices_customers_detail_view = models.BooleanField(default=False, verbose_name="Kundendetails anzeigen", help_text="Benutzer darf Details des Kunden sehen.")
|
||||
invoices_customers_add = models.BooleanField(default=False, verbose_name="Kunden erstellen", help_text="Benutzer darf Kunden anlegen.")
|
||||
invoices_customers_edit = models.BooleanField(default=False, verbose_name="Kunden bearbeiten", help_text="Benutzer darf Kunden ändern.")
|
||||
invoices_customers_archive = models.BooleanField(default=False, verbose_name="Kunden archivieren", help_text="Benutzer darf Kunden archivieren.")
|
||||
invoices_customers_activate = models.BooleanField(default=False, verbose_name="Kunden reaktivieren", help_text="Benutzer darf Kunden wieder aktivieren.")
|
||||
|
||||
invoices_items_view = models.BooleanField(default=False, verbose_name="Artikel anzeigen", help_text="Benutzer darf Artikel sehen.")
|
||||
invoices_items_add = models.BooleanField(default=False, verbose_name="Artikel erstellen", help_text="Benutzer darf Artikel erstellen.")
|
||||
invoices_items_edit = models.BooleanField(default=False, verbose_name="Artikel bearbeiten", help_text="Benutzer darf Artikel ändern.")
|
||||
invoices_items_delete = models.BooleanField(default=False, verbose_name="Artikel löschen", help_text="Benutzer darf Artikel löschen.")
|
||||
|
||||
invoices_invoices_view = models.BooleanField(default=False, verbose_name="Rechnungen anzeigen", help_text="Benutzer darf Rechnungen sehen.")
|
||||
invoices_invoices_project_add = models.BooleanField(default=False, verbose_name="Projekt-Rechnung erstellen", help_text="Benutzer darf Rechnungen aus Projekten erstellen.")
|
||||
invoices_invoices_customer_add = models.BooleanField(default=False, verbose_name="Kunden-Rechnung erstellen", help_text="Benutzer darf Rechnungen für Kunden erstellen.")
|
||||
invoices_invoices_invoices_view = models.BooleanField(default=False, verbose_name="Rechnungsdetails anzeigen", help_text="Benutzer darf Rechnungsdetails sehen.")
|
||||
invoices_invoices_invoices_item_add = models.BooleanField(default=False, verbose_name="Rechnungsposition hinzufügen", help_text="Benutzer darf Positionen hinzufügen.")
|
||||
invoices_invoices_invoices_item_delete = models.BooleanField(default=False, verbose_name="Rechnungsposition löschen", help_text="Benutzer darf Positionen löschen.")
|
||||
invoices_invoices_invoices_preview = models.BooleanField(default=False, verbose_name="Rechnungsvorschau anzeigen", help_text="Benutzer darf Vorschauen öffnen.")
|
||||
invoices_invoices_invoices_download = models.BooleanField(default=False, verbose_name="Rechnung herunterladen", help_text="Benutzer darf Rechnungen herunterladen.")
|
||||
invoices_invoices_invoices_cancel = models.BooleanField(default=False, verbose_name="Rechnung stornieren", help_text="Benutzer darf Rechnungen stornieren.")
|
||||
invoices_invoices_invoices_paid = models.BooleanField(default=False, verbose_name="Rechnung auf bezahlt setzen", help_text="Benutzer darf Rechnungsstatus ändern.")
|
||||
|
||||
|
||||
invoices_offers_view = models.BooleanField(default=False, verbose_name="Angebote anzeigen", help_text="Benutzer darf Angebote sehen.")
|
||||
invoices_offers_add = models.BooleanField(default=False, verbose_name="Angebot erstellen", help_text="Benutzer darf Angebote für Kunden erstellen.")
|
||||
invoices_offers_offers_view = models.BooleanField(default=False, verbose_name="Angebotsdetails anzeigen", help_text="Benutzer darf Angebotsdetails sehen.")
|
||||
invoices_offers_offers_item_add = models.BooleanField(default=False, verbose_name="Angebotsposition hinzufügen", help_text="Benutzer darf Positionen hinzufügen.")
|
||||
invoices_offers_offers_item_delete = models.BooleanField(default=False, verbose_name="Angebotsposition löschen", help_text="Benutzer darf Positionen löschen.")
|
||||
invoices_offers_offers_preview = models.BooleanField(default=False, verbose_name="Angebotsvorschau anzeigen", help_text="Benutzer darf Vorschauen öffnen.")
|
||||
invoices_offers_offers_download = models.BooleanField(default=False, verbose_name="Angebot herunterladen", help_text="Benutzer darf Angebote herunterladen.")
|
||||
invoices_offers_offers_status = models.BooleanField(default=False, verbose_name="Angebotsstatus bearbeiten", help_text="Benutzer darf Angebotsstatus ändern.")
|
||||
|
||||
|
||||
|
||||
|
||||
# =====================
|
||||
# Benutzerverwaltung
|
||||
# =====================
|
||||
users_view = models.BooleanField(default=False, verbose_name="Benutzer anzeigen", help_text="Benutzer darf Mitarbeiter sehen.")
|
||||
users_add = models.BooleanField(default=False, verbose_name="Benutzer erstellen", help_text="Benutzer darf neue Mitarbeiter anlegen.")
|
||||
users_edit = models.BooleanField(default=False, verbose_name="Benutzer bearbeiten", help_text="Benutzer darf Mitarbeiter bearbeiten.")
|
||||
users_archive = models.BooleanField(default=False, verbose_name="Benutzer archivieren", help_text="Benutzer darf Mitarbeiter deaktivieren.")
|
||||
users_activate = models.BooleanField(default=False, verbose_name="Benutzer aktivieren", help_text="Benutzer darf Mitarbeiter aktivieren.")
|
||||
|
||||
users_groups_add = models.BooleanField(default=False, verbose_name="Rollen erstellen", help_text="Benutzer darf neue Rollen erstellen.")
|
||||
users_groups_edit = models.BooleanField(default=False, verbose_name="Rollen bearbeiten", help_text="Benutzer darf Rollen und Berechtigungen ändern.")
|
||||
users_groups_delete = models.BooleanField(default=False, verbose_name="Rollen löschen", help_text="Benutzer darf Rollen entfernen.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Einstellungen
|
||||
# =====================
|
||||
settings_view = models.BooleanField(default=False, verbose_name="Einstellungsübersicht anzeigen", help_text="Benutzer darf Einstellungskategorien sehen.")
|
||||
settings_detail_view = models.BooleanField(default=False, verbose_name="Einstellungen anzeigen", help_text="Benutzer darf Systemeinstellungen sehen.")
|
||||
settings_add = models.BooleanField(default=False, verbose_name="Einstellungen erstellen", help_text="Benutzer darf neue Einstellungen hinzufügen.")
|
||||
#settings_edit = models.BooleanField(default=False, verbose_name="Einstellungen bearbeiten", help_text="Benutzer darf Einstellungen ändern.")
|
||||
settings_delete = models.BooleanField(default=False, verbose_name="Einstellungen löschen", help_text="Benutzer darf Einstellungen entfernen.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Zeiterfassung
|
||||
# =====================
|
||||
#time_tracking_own_view = models.BooleanField(default=False, verbose_name="Eigene Zeiten anzeigen", help_text="Benutzer darf eigene Arbeitszeiten sehen.")
|
||||
#time_tracking_own_add = models.BooleanField(default=False, verbose_name="Eigene Zeiten erfassen", help_text="Benutzer darf eigene Arbeitszeiten hinzufügen.")
|
||||
#time_tracking_own_edit = models.BooleanField(default=False, verbose_name="Eigene Zeiten bearbeiten", help_text="Benutzer darf eigene Arbeitszeiten ändern.")
|
||||
#time_tracking_own_delete = models.BooleanField(default=False, verbose_name="Eigene Zeiten löschen", help_text="Benutzer darf eigene Arbeitszeiten löschen.")
|
||||
|
||||
#time_tracking_all_view = models.BooleanField(default=False, verbose_name="Alle Zeiten anzeigen", help_text="Benutzer darf Arbeitszeiten aller Benutzer sehen.")
|
||||
#time_tracking_all_add = models.BooleanField(default=False, verbose_name="Alle Zeiten erfassen", help_text="Benutzer darf Arbeitszeiten für andere Benutzer hinzufügen.")
|
||||
#time_tracking_all_edit = models.BooleanField(default=False, verbose_name="Alle Zeiten bearbeiten", help_text="Benutzer darf Arbeitszeiten anderer Benutzer ändern.")
|
||||
#time_tracking_all_delete = models.BooleanField(default=False, verbose_name="Alle Zeiten löschen", help_text="Benutzer darf Arbeitszeiten anderer Benutzer löschen.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Finanzen
|
||||
# =====================
|
||||
#finance_view = models.BooleanField(default=False, verbose_name="Finanzen anzeigen", help_text="Benutzer darf Finanzdaten sehen.")
|
||||
#finance_export = models.BooleanField(default=False, verbose_name="Finanzen exportieren", help_text="Benutzer darf Finanzdaten exportieren.")
|
||||
|
||||
|
||||
# =====================
|
||||
# Investments
|
||||
# =====================
|
||||
#invests_view = models.BooleanField(default=False, verbose_name="Investitionen anzeigen", help_text="Benutzer darf Investitionen sehen.")
|
||||
#invests_add = models.BooleanField(default=False, verbose_name="Investitionen erstellen", help_text="Benutzer darf neue Investitionen anlegen.")
|
||||
#invests_edit = models.BooleanField(default=False, verbose_name="Investitionen bearbeiten", help_text="Benutzer darf Investitionen ändern.")
|
||||
#invests_delete = models.BooleanField(default=False, verbose_name="Investitionen löschen", help_text="Benutzer darf Investitionen entfernen.")
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Rolle"
|
||||
verbose_name_plural = "Rollen"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
|
||||
class UserProfile(models.Model):
|
||||
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="profile"
|
||||
)
|
||||
|
||||
role = models.ForeignKey(
|
||||
Role,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
|
||||
def has_permission(self, permission):
|
||||
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
|
||||
if not self.role:
|
||||
return False
|
||||
|
||||
return getattr(
|
||||
self.role,
|
||||
permission.replace(".", "_"),
|
||||
False
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.user.username
|
||||
@@ -0,0 +1,102 @@
|
||||
import django_tables2 as tables
|
||||
from django.contrib.auth.models import User
|
||||
from .models import Role
|
||||
|
||||
class RoleTable(tables.Table):
|
||||
toggle_prefix = "role"
|
||||
detail_template = "accounts/tables/user/role_edit_form.html"
|
||||
name = tables.Column(
|
||||
verbose_name="Rolle"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
template_name = "django_tables2/table_toggle.html"
|
||||
fields = (
|
||||
"name",
|
||||
)
|
||||
attrs = {
|
||||
"class": "w-full text-sm min-w-[700px]"
|
||||
}
|
||||
|
||||
class ArchivedUserTable(tables.Table):
|
||||
toggle_prefix = "user"
|
||||
detail_template = "accounts/tables/user/archive_edit_form.html"
|
||||
username = tables.Column(
|
||||
verbose_name="Benutzername"
|
||||
)
|
||||
first_name = tables.Column(
|
||||
verbose_name="Vorname"
|
||||
)
|
||||
last_name = tables.Column(
|
||||
verbose_name="Nachname"
|
||||
)
|
||||
email = tables.Column(
|
||||
verbose_name="E-Mail"
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_name="accounts/tables/user/role.html",
|
||||
verbose_name="Rolle",
|
||||
orderable=False
|
||||
)
|
||||
superuser = tables.TemplateColumn(
|
||||
template_name="accounts/tables/user/superuser.html",
|
||||
verbose_name="Superuser",
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
template_name = "django_tables2/table_toggle.html"
|
||||
fields = (
|
||||
"username",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"role",
|
||||
"superuser",
|
||||
)
|
||||
attrs = {
|
||||
"class": "w-full text-sm min-w-[700px]"
|
||||
}
|
||||
|
||||
class UserTable(tables.Table):
|
||||
toggle_prefix = "user"
|
||||
detail_template = "accounts/tables/user/edit_form.html"
|
||||
username = tables.Column(
|
||||
verbose_name="Benutzername"
|
||||
)
|
||||
first_name = tables.Column(
|
||||
verbose_name="Vorname"
|
||||
)
|
||||
last_name = tables.Column(
|
||||
verbose_name="Nachname"
|
||||
)
|
||||
email = tables.Column(
|
||||
verbose_name="E-Mail"
|
||||
)
|
||||
role = tables.TemplateColumn(
|
||||
template_name="accounts/tables/user/role.html",
|
||||
verbose_name="Rolle",
|
||||
orderable=False
|
||||
)
|
||||
superuser = tables.TemplateColumn(
|
||||
template_name="accounts/tables/user/superuser.html",
|
||||
verbose_name="Superuser",
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
template_name = "django_tables2/table_toggle.html"
|
||||
fields = (
|
||||
"username",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"role",
|
||||
"superuser",
|
||||
)
|
||||
attrs = {
|
||||
"class": "w-full text-sm min-w-[700px]"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Mitarbeiter
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Mitarbeiter hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neuen Mitarbeiter anlegen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-4 btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,68 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Login
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
<div class="flex justify-center">
|
||||
{% if company_settings.logo %}
|
||||
<img src="{{ company_settings.logo.url }}" alt="" class="h-32">
|
||||
|
||||
{% elif company_settings.companyname %}
|
||||
{{ company_settings.companyname }}
|
||||
{% else %}
|
||||
Projektverwaltung
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="flex justify-center items-center min-h-[80vh]">
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors w-full max-w-md">
|
||||
|
||||
<h1 class="text-3xl font-bold text-center mb-6">
|
||||
Anmelden
|
||||
</h1>
|
||||
|
||||
<form method="post" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{% for field in form %}
|
||||
<div class="space-y-1">
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300">
|
||||
{{ field.label }}
|
||||
</label>
|
||||
<input
|
||||
type="{{ field.field.widget.input_type }}"
|
||||
name="{{ field.html_name }}"
|
||||
id="{{ field.id_for_label }}"
|
||||
{% if field.value %}value="{{ field.value }}"{% endif %}
|
||||
class="w-full px-4 py-3 rounded-lg border border-slate-300 dark:border-slate-600 bg-slate-50 dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
placeholder="{{ field.label }}"
|
||||
>
|
||||
{% if field.errors %}
|
||||
<p class="text-sm text-red-500">{{ field.errors|join:", " }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn w-full btn-action"
|
||||
>
|
||||
Anmelden
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,100 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Mitarbeiter
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Mitarbeiter
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Mitarbeiter, Rollen und Berechtigungen verwalten
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold">Aktionen</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Mitarbeiter oder Rollen hinzufügen</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'accounts:user_add' %}" class="btn btn-add">+ Mitarbeiter</a>
|
||||
<a href="{% url 'accounts:role_add' %}" class="btn btn-add">+ Rolle</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">
|
||||
Benutzer
|
||||
</h2>
|
||||
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Aktive Benutzer mit Rollen und Berechtigungen
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">
|
||||
Archivierte Benutzer
|
||||
</h2>
|
||||
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Deaktivierte Benutzer
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
|
||||
{% render_table archived_table %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mt-8">
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">
|
||||
Rollen
|
||||
</h2>
|
||||
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Rollen und Berechtigungen verwalten
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
|
||||
{% render_table role_table %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Mitarbeiter
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Rolle hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neue Rolle anlegen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-4 btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,121 @@
|
||||
<form method="post" action="{% url 'accounts:user_edit' item.id %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div>
|
||||
|
||||
<div class="grid md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Benutzername
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
value="{{ item.username }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Vorname
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="first_name"
|
||||
value="{{ item.first_name }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Nachname
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="last_name"
|
||||
value="{{ item.last_name }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
E-Mail
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value="{{ item.email }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Rolle
|
||||
</label>
|
||||
|
||||
<select
|
||||
name="role"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
|
||||
<option value="">
|
||||
---
|
||||
</option>
|
||||
|
||||
{% for role in table.roles %}
|
||||
<option
|
||||
value="{{ role.id }}"
|
||||
{% if item.profile.role_id == role.id %}selected{% endif %}>
|
||||
{{ role.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Letzter Login
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
disabled
|
||||
value="{{ item.last_login|date:'d.m.Y H:i' }}"
|
||||
class="border rounded px-3 py-2 w-full bg-slate-100">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
formaction="{% url 'accounts:user_reactivate' item.id %}"
|
||||
class="btn btn-action">
|
||||
Aktivieren
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,121 @@
|
||||
<form method="post" action="{% url 'accounts:user_edit' item.id %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div>
|
||||
|
||||
<div class="grid md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Benutzername
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
value="{{ item.username }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Vorname
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="first_name"
|
||||
value="{{ item.first_name }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Nachname
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="last_name"
|
||||
value="{{ item.last_name }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
E-Mail
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value="{{ item.email }}"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Rolle
|
||||
</label>
|
||||
|
||||
<select
|
||||
name="role"
|
||||
class="border rounded px-3 py-2 w-full">
|
||||
|
||||
<option value="">
|
||||
---
|
||||
</option>
|
||||
|
||||
{% for role in table.roles %}
|
||||
<option
|
||||
value="{{ role.id }}"
|
||||
{% if item.profile.role_id == role.id %}selected{% endif %}>
|
||||
{{ role.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label class="block text-sm mb-1">
|
||||
Letzter Login
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
disabled
|
||||
value="{{ item.last_login|date:'d.m.Y H:i' }}"
|
||||
class="border rounded px-3 py-2 w-full bg-slate-100">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
formaction="{% url 'accounts:user_archive' item.id %}"
|
||||
class="btn btn-action">
|
||||
Archivieren
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1 @@
|
||||
{{ record.profile.role.name|default:"-" }}
|
||||
@@ -0,0 +1,63 @@
|
||||
<form method="post" action="{% url 'accounts:role_edit' item.id %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-4">
|
||||
Berechtigungen
|
||||
</h3>
|
||||
|
||||
|
||||
<div class="grid md:grid-cols-2 xl-grid-cols-3 gap-4">
|
||||
|
||||
{% for permission in item.permissions %}
|
||||
|
||||
<label class="
|
||||
bg-slate-100 dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
flex
|
||||
items-center
|
||||
gap-3
|
||||
">
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
name="{{ permission.name }}"
|
||||
{% if permission.value %}
|
||||
checked
|
||||
{% endif %}
|
||||
class="w-4 h-4">
|
||||
|
||||
<span>
|
||||
{{ permission.verbose_name }}
|
||||
</span>
|
||||
|
||||
</label>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
formaction="{% url 'accounts:role_delete' item.id %}"
|
||||
class="btn btn-delete">
|
||||
Löschen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,5 @@
|
||||
{% if record.is_superuser %}
|
||||
Ja
|
||||
{% else %}
|
||||
Nein
|
||||
{% endif %}
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,19 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "accounts"
|
||||
|
||||
urlpatterns = [
|
||||
path("login/", views.CustomLoginView.as_view(), name="login"),
|
||||
path("logout/", views.CustomLogoutView.as_view(), name="logout"),
|
||||
path("", views.overview, name="overview"),
|
||||
|
||||
path("add/",views.user_add,name="user_add"),
|
||||
path("<int:user_id>/edit/",views.user_edit,name="user_edit"),
|
||||
path("<int:user_id>/archive/",views.user_archive,name="user_archive"),
|
||||
path("<int:user_id>/reactivate/",views.user_reactivate,name="user_reactivate"),
|
||||
|
||||
path("role/add/",views.role_add,name="role_add"),
|
||||
path("role/<int:role_id>/edit/",views.role_edit,name="role_edit"),
|
||||
path("role/<int:role_id>/delete/",views.role_delete,name="role_delete"),
|
||||
]
|
||||
@@ -0,0 +1,398 @@
|
||||
from django.contrib.auth.views import LoginView, LogoutView
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from accounts.decorators import permission_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from .forms import UserAddForm, RoleForm
|
||||
from .models import Role, UserProfile
|
||||
from .tables import UserTable, ArchivedUserTable, RoleTable
|
||||
from django_tables2 import RequestConfig
|
||||
|
||||
|
||||
class CustomLoginView(LoginView):
|
||||
template_name = "accounts/login.html"
|
||||
redirect_authenticated_user = True
|
||||
|
||||
class CustomLogoutView(LogoutView):
|
||||
pass
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_view")
|
||||
def overview(request):
|
||||
|
||||
users = (
|
||||
User.objects
|
||||
.filter(is_active=True)
|
||||
.select_related(
|
||||
"profile",
|
||||
"profile__role"
|
||||
)
|
||||
.order_by("username")
|
||||
)
|
||||
|
||||
archived_users = (
|
||||
User.objects
|
||||
.filter(is_active=False)
|
||||
.select_related(
|
||||
"profile",
|
||||
"profile__role"
|
||||
)
|
||||
.order_by("username")
|
||||
)
|
||||
|
||||
roles = list(
|
||||
Role.objects.order_by("name")
|
||||
)
|
||||
|
||||
|
||||
# ==================================================
|
||||
# ROLE PERMISSIONS FÜR CHECKBOXEN
|
||||
# ==================================================
|
||||
|
||||
permission_fields = []
|
||||
|
||||
for field in Role._meta.fields:
|
||||
|
||||
if field.get_internal_type() == "BooleanField":
|
||||
|
||||
permission_fields.append({
|
||||
"name": field.name,
|
||||
"verbose_name": field.verbose_name or field.name
|
||||
})
|
||||
|
||||
|
||||
for role in roles:
|
||||
|
||||
role.permissions = []
|
||||
|
||||
for permission in permission_fields:
|
||||
|
||||
role.permissions.append({
|
||||
|
||||
"name": permission["name"],
|
||||
|
||||
"verbose_name": permission["verbose_name"],
|
||||
|
||||
"value": getattr(
|
||||
role,
|
||||
permission["name"]
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
|
||||
# ==================================================
|
||||
# USER ROLLEN-PERMISSIONS
|
||||
# ==================================================
|
||||
|
||||
for user in list(users) + list(archived_users):
|
||||
|
||||
role = getattr(
|
||||
getattr(user, "profile", None),
|
||||
"role",
|
||||
None
|
||||
)
|
||||
|
||||
user.role_permissions = []
|
||||
|
||||
if role:
|
||||
|
||||
for permission in permission_fields:
|
||||
|
||||
if getattr(
|
||||
role,
|
||||
permission["name"]
|
||||
):
|
||||
user.role_permissions.append(
|
||||
permission["verbose_name"]
|
||||
)
|
||||
|
||||
|
||||
# ==================================================
|
||||
# TABLES
|
||||
# ==================================================
|
||||
table = UserTable(users)
|
||||
table.roles = roles
|
||||
RequestConfig(
|
||||
request,
|
||||
paginate=False
|
||||
).configure(table)
|
||||
|
||||
archived_table = ArchivedUserTable(archived_users)
|
||||
archived_table.roles = roles
|
||||
RequestConfig(
|
||||
request,
|
||||
paginate=False
|
||||
).configure(archived_table)
|
||||
|
||||
|
||||
role_table = RoleTable(roles)
|
||||
role_table.roles = roles
|
||||
RequestConfig(
|
||||
request,
|
||||
paginate=False
|
||||
).configure(role_table)
|
||||
|
||||
|
||||
return render(
|
||||
request,
|
||||
"accounts/overview.html",
|
||||
{
|
||||
"table": table,
|
||||
"archived_table": archived_table,
|
||||
"role_table": role_table,
|
||||
}
|
||||
)
|
||||
|
||||
@login_required
|
||||
@permission_required("users_edit")
|
||||
def user_edit(request, user_id):
|
||||
|
||||
user = get_object_or_404(
|
||||
User.objects.select_related(
|
||||
"profile"
|
||||
),
|
||||
id=user_id
|
||||
)
|
||||
|
||||
if user.is_superuser:
|
||||
return redirect("accounts:overview")
|
||||
|
||||
if request.method != "POST":
|
||||
return redirect("accounts:overview")
|
||||
|
||||
# -------------------------
|
||||
# USER
|
||||
# -------------------------
|
||||
user.username = request.POST.get(
|
||||
"username",
|
||||
user.username
|
||||
)
|
||||
|
||||
user.first_name = request.POST.get(
|
||||
"first_name",
|
||||
user.first_name
|
||||
)
|
||||
|
||||
user.last_name = request.POST.get(
|
||||
"last_name",
|
||||
user.last_name
|
||||
)
|
||||
|
||||
user.email = request.POST.get(
|
||||
"email",
|
||||
user.email
|
||||
)
|
||||
|
||||
user.save()
|
||||
|
||||
# -------------------------
|
||||
# PROFILE / ROLE
|
||||
# -------------------------
|
||||
profile, _ = UserProfile.objects.get_or_create(
|
||||
user=user
|
||||
)
|
||||
|
||||
role_id = request.POST.get("role")
|
||||
|
||||
if role_id:
|
||||
profile.role_id = role_id
|
||||
else:
|
||||
profile.role = None
|
||||
|
||||
profile.save()
|
||||
|
||||
return redirect(
|
||||
"accounts:overview"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_archive")
|
||||
def user_archive(request, user_id):
|
||||
|
||||
user = get_object_or_404(
|
||||
User,
|
||||
id=user_id
|
||||
)
|
||||
|
||||
if user.is_superuser:
|
||||
return redirect("accounts:overview")
|
||||
|
||||
if request.method == "POST":
|
||||
user.is_active = False
|
||||
user.save()
|
||||
|
||||
return redirect("accounts:overview")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_activate")
|
||||
def user_reactivate(request, user_id):
|
||||
|
||||
user = get_object_or_404(
|
||||
User,
|
||||
id=user_id
|
||||
)
|
||||
|
||||
if user.is_superuser:
|
||||
return redirect("accounts:overview")
|
||||
|
||||
if request.method == "POST":
|
||||
user.is_active = True
|
||||
user.save()
|
||||
|
||||
return redirect("accounts:overview")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_add")
|
||||
def user_add(request):
|
||||
|
||||
form = UserAddForm(
|
||||
request.POST or None
|
||||
)
|
||||
|
||||
if form.is_valid():
|
||||
|
||||
user = form.save(commit=False)
|
||||
|
||||
password = form.cleaned_data["password"]
|
||||
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
UserProfile.objects.create(
|
||||
user=user,
|
||||
role=form.cleaned_data["role"]
|
||||
)
|
||||
|
||||
return redirect(
|
||||
"accounts:overview"
|
||||
)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"accounts/add.html",
|
||||
{
|
||||
"form": form
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_role_permissions():
|
||||
|
||||
fields = []
|
||||
|
||||
for field in Role._meta.fields:
|
||||
|
||||
if field.get_internal_type() == "BooleanField":
|
||||
|
||||
fields.append({
|
||||
"name": field.name,
|
||||
"label": field.verbose_name or field.name
|
||||
})
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_groups_edit")
|
||||
def role_edit(request, role_id):
|
||||
|
||||
role = get_object_or_404(
|
||||
Role,
|
||||
id=role_id
|
||||
)
|
||||
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
for field in Role._meta.fields:
|
||||
|
||||
if (
|
||||
field.get_internal_type()
|
||||
== "BooleanField"
|
||||
):
|
||||
|
||||
setattr(
|
||||
role,
|
||||
field.name,
|
||||
field.name in request.POST
|
||||
)
|
||||
|
||||
|
||||
role.name = request.POST.get(
|
||||
"name",
|
||||
role.name
|
||||
)
|
||||
|
||||
|
||||
role.save()
|
||||
|
||||
|
||||
return redirect(
|
||||
"accounts:overview"
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_groups_delete")
|
||||
def role_delete(request, role_id):
|
||||
|
||||
role = get_object_or_404(
|
||||
Role,
|
||||
id=role_id
|
||||
)
|
||||
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
role.delete()
|
||||
|
||||
|
||||
return redirect(
|
||||
"accounts:overview"
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("users_groups_add")
|
||||
def role_add(request):
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
form = RoleForm(
|
||||
request.POST
|
||||
)
|
||||
|
||||
if form.is_valid():
|
||||
|
||||
form.save()
|
||||
|
||||
return redirect(
|
||||
"accounts:overview"
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
form = RoleForm()
|
||||
|
||||
|
||||
return render(
|
||||
request,
|
||||
"accounts/role_add.html",
|
||||
{
|
||||
"form": form
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user