HH/apps/accounts/forms.py

239 lines
9.6 KiB
Python

"""
Accounts forms - User create/edit for config console
"""
from django import forms
from django.contrib.auth.models import Group
from django.utils.translation import gettext_lazy as _
from apps.accounts.models import User
from apps.organizations.models import Hospital, Department
from apps.core.form_mixins import DepartmentFieldMixin
class UserCreateForm(DepartmentFieldMixin, forms.ModelForm):
"""Form for creating a new user in the config console"""
email = forms.EmailField(
label=_("Email"),
widget=forms.EmailInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
"placeholder": "user@example.com",
}),
)
first_name = forms.CharField(
label=_("First Name"),
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
last_name = forms.CharField(
label=_("Last Name"),
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
phone = forms.CharField(
label=_("Phone"),
required=False,
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
"placeholder": "+966501234567",
}),
)
employee_id = forms.CharField(
label=_("Employee ID"),
required=False,
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
hospital = forms.ModelChoiceField(
queryset=Hospital.objects.filter(status="active"),
label=_("Hospital"),
required=False,
widget=forms.Select(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
department = forms.ModelChoiceField(
queryset=Department.objects.none(),
label=_("Department"),
required=False,
widget=forms.Select(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
groups = forms.ModelMultipleChoiceField(
queryset=Group.objects.all(),
label=_("Roles"),
required=False,
widget=forms.CheckboxSelectMultiple(attrs={
"class": "role-checkbox",
}),
)
password = forms.CharField(
label=_("Password"),
required=False,
widget=forms.PasswordInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
"placeholder": _("Leave blank to generate random password"),
}),
)
password_confirm = forms.CharField(
label=_("Confirm Password"),
required=False,
widget=forms.PasswordInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
is_active = forms.BooleanField(
label=_("Active"),
initial=True,
required=False,
widget=forms.CheckboxInput(attrs={
"class": "w-5 h-5 text-navy border-slate-300 rounded focus:ring-navy",
}),
)
class Meta:
model = User
fields = [
"email", "first_name", "last_name", "phone", "employee_id",
"hospital", "department", "groups", "is_active",
]
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request", None)
self.user = kwargs.pop("user", None) or (self.request.user if self.request else None)
super().__init__(*args, **kwargs)
self.fields["groups"].queryset = Group.objects.all().order_by("name")
if self.user and self.user.is_hospital_admin() and self.user.hospital:
self.fields["hospital"].initial = self.user.hospital
self.fields["hospital"].queryset = Hospital.objects.filter(id=self.user.hospital.id)
def clean_email(self):
email = self.cleaned_data.get("email")
if User.objects.filter(email=email).exists():
raise forms.ValidationError(_("A user with this email already exists."))
return email
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get("password")
password_confirm = cleaned_data.get("password_confirm")
if password and password_confirm and password != password_confirm:
self.add_error("password_confirm", _("Passwords do not match."))
return cleaned_data
def save(self, commit=True):
import secrets
import string
user = super().save(commit=False)
password = self.cleaned_data.get("password")
if not password:
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
password = ''.join(secrets.choice(alphabet) for _ in range(16))
self._generated_password = password
user.set_password(password)
if commit:
user.save()
selected_groups = self.cleaned_data.get("groups")
if selected_groups:
user.groups.set(selected_groups)
return user
class UserEditForm(DepartmentFieldMixin, forms.ModelForm):
"""Form for editing an existing user in the config console"""
first_name = forms.CharField(
label=_("First Name"),
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
last_name = forms.CharField(
label=_("Last Name"),
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
phone = forms.CharField(
label=_("Phone"),
required=False,
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
"placeholder": "+966501234567",
}),
)
employee_id = forms.CharField(
label=_("Employee ID"),
required=False,
widget=forms.TextInput(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
hospital = forms.ModelChoiceField(
queryset=Hospital.objects.filter(status="active"),
label=_("Hospital"),
required=False,
widget=forms.Select(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
department = forms.ModelChoiceField(
queryset=Department.objects.none(),
label=_("Department"),
required=False,
widget=forms.Select(attrs={
"class": "w-full px-4 py-3 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-navy focus:border-transparent transition bg-white text-sm",
}),
)
groups = forms.ModelMultipleChoiceField(
queryset=Group.objects.all(),
label=_("Roles"),
required=False,
widget=forms.CheckboxSelectMultiple(attrs={
"class": "role-checkbox",
}),
)
is_active = forms.BooleanField(
label=_("Active"),
initial=True,
required=False,
widget=forms.CheckboxInput(attrs={
"class": "w-5 h-5 text-navy border-slate-300 rounded focus:ring-navy",
}),
)
class Meta:
model = User
fields = [
"first_name", "last_name", "phone", "employee_id",
"hospital", "department", "groups", "is_active",
]
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request", None)
self.user = kwargs.pop("user", None) or (self.request.user if self.request else None)
super().__init__(*args, **kwargs)
self.fields["groups"].queryset = Group.objects.all().order_by("name")
if self.instance and self.instance.pk:
self.fields["groups"].initial = self.instance.groups.all()
if self.instance.hospital:
self.fields["hospital"].initial = self.instance.hospital
self.fields["hospital"].queryset = Hospital.objects.filter(id=self.instance.hospital.id)
def save(self, commit=True):
user = super().save(commit=False)
if commit:
user.save()
selected_groups = self.cleaned_data.get("groups")
if selected_groups is not None:
user.groups.set(selected_groups)
return user