Initial commit

This commit is contained in:
2025-05-17 00:57:08 +02:00
commit fe69bdbc94
71 changed files with 6585 additions and 0 deletions

View File

@ -0,0 +1 @@
# This file is intentionally left empty to mark the directory as a Python package

View File

@ -0,0 +1,77 @@
# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserChangeForm, CustomUserCreationForm
from .models import Company, CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ("username", "email", "company", "is_company_admin", "is_staff")
list_filter = ("is_staff", "is_active", "company", "is_company_admin")
fieldsets = (
(None, {"fields": ("username", "email", "password")}),
(
"Permissions",
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
)
},
),
("Company", {"fields": ("company", "is_company_admin")}),
("Important dates", {"fields": ("last_login", "date_joined")}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": (
"username",
"email",
"password1",
"password2",
"company",
"is_company_admin",
"is_staff",
"is_active",
),
},
),
)
search_fields = ("username", "email", "company__name")
ordering = ("username",)
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
if obj.is_superuser and not obj.company:
default_company, created = Company.objects.get_or_create(
name="Default Organization",
defaults={"description": "Default company for new superusers."},
)
obj.company = default_company
obj.is_company_admin = True # Optionally make the superuser an admin of this default company
obj.save()
class CompanyAdmin(admin.ModelAdmin):
list_display = ("name", "created_at", "get_employee_count")
search_fields = ("name", "description")
def get_employee_count(self, obj):
return obj.employees.count()
get_employee_count.short_description = "Employees"
admin.site.register(CustomUser, CustomUserAdmin)
admin.site.register(Company, CompanyAdmin)

View File

@ -0,0 +1,8 @@
# accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "accounts"

View File

@ -0,0 +1,45 @@
# accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Company, CustomUser
class CustomUserCreationForm(UserCreationForm):
"""Form for creating new users"""
class Meta:
model = CustomUser
fields = ("username", "email", "password1", "password2")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Add help text for fields
self.fields["email"].required = True
self.fields["email"].help_text = "Required. Enter a valid email address."
class CustomUserChangeForm(forms.ModelForm):
"""Form for updating users"""
class Meta:
model = CustomUser
fields = ("username", "email", "company", "is_company_admin")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Only staff members can change company and admin status
if not kwargs.get("instance") or not kwargs.get("instance").is_staff:
if "company" in self.fields:
self.fields["company"].disabled = True
if "is_company_admin" in self.fields:
self.fields["is_company_admin"].disabled = True
class CompanyForm(forms.ModelForm):
"""Form for creating and updating companies"""
class Meta:
model = Company
fields = ("name", "description")

View File

@ -0,0 +1 @@
# This file is intentionally left empty to mark the directory as a Python package

View File

@ -0,0 +1,34 @@
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
"""Custom user model to extend the default Django user"""
company = models.ForeignKey(
"Company",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="employees",
)
is_company_admin = models.BooleanField(default=False)
def __str__(self):
return self.username
class Company(models.Model):
"""Model for companies that will access the dashboard"""
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Companies"

View File

View File

@ -0,0 +1,28 @@
# accounts/urls.py
from allauth.account import views as allauth_views
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
path(
"login/",
auth_views.LoginView.as_view(template_name="accounts/login.html"),
name="login",
),
path("logout/", allauth_views.LogoutView.as_view(), name="logout"), # Use allauth logout view
path("register/", views.register_view, name="register"),
path("profile/", views.profile_view, name="profile"),
path(
"password_change/",
auth_views.PasswordChangeView.as_view(template_name="accounts/password_change.html"),
name="password_change",
),
path(
"password_change/done/",
auth_views.PasswordChangeDoneView.as_view(template_name="accounts/password_change_done.html"),
name="password_change_done",
),
]

View File

@ -0,0 +1,72 @@
# accounts/views.py
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
from .forms import CompanyForm, CustomUserCreationForm
from .models import Company, CustomUser
def register_view(request):
"""View for user registration"""
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful.")
return redirect("dashboard")
else:
messages.error(request, "Registration failed. Please correct the errors.")
else:
form = CustomUserCreationForm()
return render(request, "accounts/register.html", {"form": form})
@login_required
def profile_view(request):
"""View for user profile"""
user = request.user
company = user.company
context = {
"user": user,
"company": company,
}
return render(request, "accounts/profile.html", context)
@staff_member_required
def company_create_view(request):
"""View for creating companies (admin only)"""
if request.method == "POST":
form = CompanyForm(request.POST)
if form.is_valid():
company = form.save()
messages.success(request, f"Company '{company.name}' created successfully.")
return redirect("admin:accounts_company_changelist")
else:
messages.error(request, "Failed to create company. Please correct the errors.")
else:
form = CompanyForm()
return render(request, "admin/accounts/company/create.html", {"form": form})
@staff_member_required
def company_users_view(request, company_id):
"""View for managing users in a company (admin only)"""
company = Company.objects.get(pk=company_id)
users = CustomUser.objects.filter(company=company)
context = {
"company": company,
"users": users,
}
return render(request, "admin/accounts/company/users.html", context)