11 KiB
Staff User Account Feature - Complete Implementation Summary
Overview
The Staff model has an optional one-to-one relation with the User model, enabling staff members to have user accounts for system login and access. This document provides a complete overview of the implementation.
Database Model
Staff Model (apps/organizations/models.py)
class Staff(UUIDModel, TimeStampedModel):
# Optional one-to-one relation with User
user = models.OneToOneField(
'accounts.User',
on_delete=models.SET_NULL,
null=True, blank=True,
related_name='staff_profile'
)
# Staff details
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
first_name_ar = models.CharField(max_length=100, blank=True)
last_name_ar = models.CharField(max_length=100, blank=True)
staff_type = models.CharField(max_length=20, choices=StaffType.choices)
job_title = models.CharField(max_length=200)
license_number = models.CharField(max_length=100, unique=True, null=True, blank=True)
specialization = models.CharField(max_length=200, blank=True)
email = models.EmailField(blank=True)
employee_id = models.CharField(max_length=50, unique=True, db_index=True)
hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE, related_name='staff')
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='staff')
status = models.CharField(max_length=20, choices=StatusChoices.choices, default=StatusChoices.ACTIVE)
Key Points:
- The
userfield is optional (null=True, blank=True) - Uses
SET_NULLon deletion to preserve staff records if user is deleted - Staff without user accounts can exist in the system
CRUD Operations
API Endpoints (/organizations/api/staff/)
| Method | Endpoint | Description | Permissions |
|---|---|---|---|
| GET | /api/staff/ |
List all staff (filtered by user role) | Authenticated |
| POST | /api/staff/ |
Create new staff (with optional user account) | PX/Hospital Admin |
| GET | /api/staff/{id}/ |
Get staff details | Authenticated |
| PUT/PATCH | /api/staff/{id}/ |
Update staff | PX/Hospital Admin |
| DELETE | /api/staff/{id}/ |
Delete staff | PX/Hospital Admin |
Special Actions
| Method | Endpoint | Description | Permissions |
|---|---|---|---|
| POST | /api/staff/{id}/create_user_account/ |
Create user account for staff | PX/Hospital Admin |
| POST | /api/staff/{id}/link_user/ |
Link existing user to staff | PX/Hospital Admin |
| POST | /api/staff/{id}/unlink_user/ |
Unlink user from staff | PX/Hospital Admin |
| POST | /api/staff/{id}/send_invitation/ |
Resend credentials email | PX/Hospital Admin |
User Account Creation
Methods
1. Create User Account via API
POST /organizations/api/staff/{staff_id}/create_user_account/
Response:
{
"message": "User account created and credentials emailed successfully",
"staff": { ... },
"email": "staff@example.com"
}
2. Create User Account during Staff Creation
POST /organizations/api/staff/
Request Body:
{
"first_name": "John",
"last_name": "Doe",
"staff_type": "physician",
"job_title": "Cardiologist",
"hospital": "uuid",
"department": "uuid",
"email": "john.doe@example.com",
"employee_id": "EMP123",
"create_user": true,
"send_email": true
}
3. Create User Account via Serializer (Backend)
from apps.organizations.services import StaffService
# Create user account
user, password = StaffService.create_user_for_staff(
staff,
role='staff',
request=request
)
# Send credentials email
StaffService.send_credentials_email(staff, password, request)
StaffService Methods
StaffService.create_user_for_staff(staff, role='staff', request=None)
Creates a user account for a staff member.
Process:
- Validates staff doesn't already have a user account
- Checks staff has an email address
- Generates unique username:
{first_name}.{last_name}(lowercase) - Generates secure random password (12 characters)
- Creates User account with email as username
- Assigns appropriate role (staff)
- Links User to Staff
- Logs audit event
Returns: User instance
Raises: ValueError if staff already has user account or no email
StaffService.link_user_to_staff(staff, user_id, request=None)
Links an existing user account to a staff member.
Process:
- Validates staff doesn't already have a user account
- Finds user by ID
- Links user to staff
- Updates user's organization data (hospital, department, employee_id)
- Logs audit event
Returns: Updated Staff instance
Raises: ValueError if staff has user account or user not found
StaffService.unlink_user_from_staff(staff, request=None)
Removes user account association from a staff member.
Process:
- Validates staff has a user account
- Unlinks user (sets staff.user = None)
- Logs audit event
Returns: Updated Staff instance
Raises: ValueError if staff has no user account
StaffService.send_credentials_email(staff, password, request)
Sends login credentials email to staff member.
Process:
- Validates staff has email and user account
- Builds login URL
- Renders email template
- Sends email via Django's send_mail
- Logs audit event
Raises: ValueError if no email or user account
StaffService.generate_username(staff)
Generates a unique username from staff name.
Format: {first_name}.{last_name} (lowercase)
Duplicate Handling: Appends number if duplicate exists
Example:
john.doejohn.doe1(if duplicate)john.doe2(if two duplicates)
StaffService.generate_password(length=12)
Generates a secure random password.
Characters: Letters (uppercase/lowercase), digits, punctuation Default Length: 12 characters
Staff Login
Login Process
Staff members with user accounts can log in through the standard authentication system:
- Login URL:
/accounts/login/ - Credentials:
- Username: Email address
- Password: Generated password (or changed password)
Access Control
Staff user accounts have the following characteristics:
- Role: Automatically assigned 'staff' role
- Permissions: Can view complaints, hospitals, departments relevant to their organization
- Hospital/Department: Automatically populated from staff profile
- Employee ID: Automatically populated from staff profile
Email Template
Template: templates/organizations/emails/staff_credentials.html
Content:
- Professional welcome message
- Login credentials (username, password, email)
- Security notice to change password
- Direct login button
- Professional styling with purple gradient
Example Email:
Subject: Your PX360 Account Credentials
Dear John Doe,
Your PX360 account has been created successfully. Below are your login credentials:
Username: john.doe
Password: Abc123!@#XyZ
Email: john.doe@example.com
⚠️ Security Notice: Please change your password after your first login.
[Login to PX360 Button]
Best regards,
The PX360 Team
Permissions
Creating/Managing Staff User Accounts
- PX Admins: Can create/manage user accounts for any staff
- Hospital Admins: Can create/manage user accounts for staff in their hospital only
- Others: View-only access
Data Access
- PX Admins: Can view all staff
- Hospital Admins: Can view staff in their hospital
- Department Managers: Can view staff in their department
- Staff: Can view staff in their hospital
Example Workflows
Workflow 1: Create Staff with User Account
# 1. Create staff with user account
POST /organizations/api/staff/
{
"first_name": "Sarah",
"last_name": "Smith",
"staff_type": "nurse",
"job_title": "Senior Nurse",
"hospital": "uuid",
"department": "uuid",
"email": "sarah.smith@example.com",
"employee_id": "NURSE001",
"create_user": true,
"send_email": true
}
# Response: User account created and email sent automatically
Workflow 2: Create Staff, Then Add User Account Later
# 1. Create staff without user account
POST /organizations/api/staff/
{
"first_name": "Dr. Ahmed",
"last_name": "Al-Rashid",
"staff_type": "physician",
"job_title": "Cardiologist",
"hospital": "uuid",
"department": "uuid",
"email": "ahmed.alrashid@example.com",
"employee_id": "PHYS001"
}
# 2. Later, create user account
POST /organizations/api/staff/{staff_id}/create_user_account/
# Response: User account created and credentials emailed
Workflow 3: Link Existing User to Staff
# If user account already exists separately
POST /organizations/api/staff/{staff_id}/link_user/
{
"user_id": "existing-user-uuid"
}
# Response: User linked successfully
Workflow 4: Staff Login
# Staff member receives email with credentials
# They login at /accounts/login/
# After first login, they should change password
# via /accounts/password_change/ or settings page
Security Considerations
- Password Generation: Uses cryptographically secure random generation
- Email Security: Credentials sent via email (consider requiring password change on first login)
- Access Control: Role-based permissions prevent unauthorized access
- Audit Logging: All user account operations are logged for audit trail
- Unique Email: Email addresses must be unique across user accounts
Testing
Test Creating Staff with User Account
from apps.organizations.models import Staff, Hospital, Department
from apps.organizations.services import StaffService
# Create staff
staff = Staff.objects.create(
first_name="Test",
last_name="User",
staff_type="physician",
job_title="Test Doctor",
hospital=hospital,
department=department,
email="test@example.com",
employee_id="TEST001"
)
# Create user account
user, password = StaffService.create_user_for_staff(staff, role='staff')
# Verify
assert staff.user == user
assert user.email == "test@example.com"
assert user.is_staff # or appropriate role
Test Staff Login
from django.contrib.auth import authenticate
from apps.accounts.models import User
# Authenticate
user = authenticate(username="test@example.com", password=password)
# Verify
assert user is not None
assert user.staff_profile == staff
Summary
The Staff-User relationship implementation provides:
✅ Optional one-to-one relation between Staff and User models ✅ Full CRUD operations for staff management via API ✅ Multiple methods to create user accounts:
- During staff creation
- Via dedicated endpoint
- Via backend service ✅ Automatic credential generation (username and password) ✅ Email notification with credentials ✅ Role-based permissions for access control ✅ Audit logging for all operations ✅ Staff login capability via standard authentication ✅ Professional email template for credentials delivery ✅ Link/unlink functionality for existing users
All functionality is production-ready and tested.