HH/docs/STAFF_USER_ACCOUNT_FEATURE_SUMMARY.md
2026-01-12 12:19:19 +03:00

14 KiB

Staff User Account Feature - Implementation Summary

Overview

This document provides a comprehensive summary of the Staff User Account feature implementation, including the optional one-to-one relation with the User model, CRUD operations, and login functionality for staff members.

Feature Components

1. Staff-User One-to-One Relation

File: apps/organizations/models.py

The Staff model has an optional one-to-one relation with the User model:

class Staff(UUIDModel, TimeStampedModel):
    # Link to User (Keep it optional for external/temp staff)
    user = models.OneToOneField(
        'accounts.User',
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='staff_profile'
    )

Key Features:

  • Optional relation (allows external/temp staff without user accounts)
  • Uses SET_NULL on delete (staff profile remains if user is deleted)
  • Provides reverse relation via user.staff_profile

2. Custom UserManager

File: apps/accounts/models.py

Implemented a custom UserManager to support email-based authentication:

class UserManager(BaseUserManager):
    """Custom user manager for email-based authentication."""
    
    def create_user(self, email, password=None, **extra_fields):
        """Create and save a regular user with the given email and password."""
        if not email:
            raise ValueError('The Email field must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        """Create and save a superuser with the given email and password."""
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self.create_user(email, password, **extra_fields)

3. StaffService

File: apps/organizations/services.py

Provides comprehensive staff user account management:

Key Methods:

  1. create_user_for_staff()

    • Creates a user account for a staff member
    • Generates username and password
    • Assigns appropriate role
    • Links user to staff profile
    • Logs the action for audit trail
  2. link_user_to_staff()

    • Links an existing user account to a staff member
    • Updates user's organization data
  3. unlink_user_from_staff()

    • Removes user account association from staff member
  4. send_credentials_email()

    • Sends login credentials email to staff member
    • Includes generated password and login URL
  5. generate_username()

    • Generates unique username from staff name
    • Format: first.last (lowercase)
    • Appends number if duplicate exists
  6. generate_password()

    • Generates secure random password (12 characters)
    • Includes letters, numbers, and special characters
  7. get_staff_type_role()

    • Maps staff type to role name
    • Currently all staff get 'staff' role

4. API Endpoints

File: apps/organizations/views.py

StaffViewSet - CRUD Operations

Base CRUD:

  • GET /api/staff/ - List all staff (filtered by user role)
  • POST /api/staff/ - Create new staff member
  • GET /api/staff/{id}/ - Retrieve staff details
  • PUT /api/staff/{id}/ - Update staff member
  • PATCH /api/staff/{id}/ - Partially update staff member
  • DELETE /api/staff/{id}/ - Delete staff member

User Account Actions:

  1. Create User Account

    • POST /api/staff/{id}/create_user_account/
    • Creates a user account for staff member
    • Auto-generates username and password
    • Sends credentials email
    • Body: { "role": "staff" } (optional)
  2. Link Existing User

    • POST /api/staff/{id}/link_user/
    • Links an existing user account to staff
    • Body: { "user_id": "uuid" }
  3. Unlink User

    • POST /api/staff/{id}/unlink_user/
    • Removes user account association
  4. Send Invitation

    • POST /api/staff/{id}/send_invitation/
    • Generates new password
    • Sends credentials email

Filtering & Search:

  • Filter by: status, hospital, department, staff_type, specialization, job_title, hospital__organization
  • Search by: first_name, last_name, first_name_ar, last_name_ar, employee_id, license_number, job_title
  • Order by: last_name, created_at

Permissions:

  • PX Admins: Full access to all staff
  • Hospital Admins: Full access to staff in their hospital
  • Department Managers: Read-only access to staff in their department
  • Others: Read-only access to staff in their hospital

5. Management Commands

File: apps/organizations/management/commands/seed_staff.py

Command Options:

python manage.py seed_staff [options]

Options:

  • --hospital-code: Target hospital code (default: all hospitals)
  • --count: Number of staff to create per type (default: 10)
  • --physicians: Number of physicians to create (default: 10)
  • --nurses: Number of nurses to create (default: 15)
  • --admin-staff: Number of admin staff to create (default: 5)
  • --create-users: Create user accounts for staff
  • --send-emails: Send credential emails to newly created users
  • --clear: Clear existing staff first
  • --dry-run: Preview without making changes

Examples:

# Create staff without users
python manage.py seed_staff --physicians 5 --nurses 10

# Create staff with user accounts
python manage.py seed_staff --physicians 5 --nurses 10 --create-users

# Create staff with user accounts and send emails
python manage.py seed_staff --physicians 5 --nurses 10 --create-users --send-emails

# Dry run to preview
python manage.py seed_staff --physicians 5 --dry-run

# Clear and recreate staff
python manage.py seed_staff --clear --physicians 5

6. Email Templates

File: templates/organizations/emails/staff_credentials.html

Professional HTML email template for sending staff credentials.

Template Variables:

  • staff: Staff instance
  • user: User instance
  • password: Generated password
  • login_url: Absolute login URL

7. Database Migrations

Migration: apps/accounts/migrations/0004_alter_user_managers_and_more.py

Changes applied:

  1. Changed manager on User model to custom UserManager
  2. Made username field optional and non-unique
  3. Updated acknowledgement_completed_at field

User Authentication Flow

Staff Login Process

  1. Account Creation:

    • Staff member is created in the system
    • Admin creates user account via API or management command
    • Password is generated and sent via email
  2. Login:

    • Staff member logs in using their email address
    • Password is verified against hashed password in database
    • Session is established
  3. Access:

    • User's role determines permissions
    • Staff profile is accessible via request.user.staff_profile
    • Organization context is available via request.user.hospital

Permission Model

Staff User Roles

All staff members are assigned to the 'staff' role by default. The role system is flexible and can be extended to support:

  • Physicians
  • Nurses
  • Administrative staff
  • Department managers
  • Hospital administrators

Role-Based Access Control

PX Admin:

  • Can manage all organizations, hospitals, departments, and staff
  • Can create user accounts for any staff member

Hospital Admin:

  • Can manage their hospital, departments, and staff
  • Can create user accounts for staff in their hospital

Department Manager:

  • Can view staff in their department
  • Cannot create user accounts

Staff:

  • Can view other staff in their hospital
  • Cannot create user accounts

Usage Examples

Creating Staff and User Account

Via API:

# 1. Create staff member
curl -X POST http://localhost:8000/api/staff/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "John",
    "last_name": "Doe",
    "first_name_ar": "جون",
    "last_name_ar": "دو",
    "staff_type": "physician",
    "job_title": "Cardiologist",
    "specialization": "Cardiology",
    "license_number": "MOH-LIC-1234567",
    "employee_id": "DR-HOSP-12345",
    "email": "john.doe@hospital.sa",
    "hospital": "<hospital_id>",
    "department": "<department_id>",
    "status": "active"
  }'

# 2. Create user account for staff
curl -X POST http://localhost:8000/api/staff/<staff_id>/create_user_account/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "staff"
  }'

Via Management Command:

python manage.py seed_staff --physicians 1 --create-users --send-emails

Via Python Code:

from apps.organizations.models import Staff, Hospital
from apps.organizations.services import StaffService

# Create staff
hospital = Hospital.objects.get(code="HOSPITAL001")
staff = Staff.objects.create(
    first_name="John",
    last_name="Doe",
    staff_type=Staff.StaffType.PHYSICIAN,
    job_title="Cardiologist",
    specialization="Cardiology",
    license_number="MOH-LIC-1234567",
    employee_id="DR-HOSP-12345",
    email="john.doe@hospital.sa",
    hospital=hospital,
    status="active"
)

# Create user account
user = StaffService.create_user_for_staff(staff, role='staff')

# Send credentials email
password = StaffService.generate_password()
user.set_password(password)
user.save()
StaffService.send_credentials_email(staff, password, request)

Linking Existing User

from apps.accounts.models import User
from apps.organizations.services import StaffService

# Get existing user and staff
user = User.objects.get(email="existing.user@hospital.sa")
staff = Staff.objects.get(employee_id="DR-HOSP-12345")

# Link user to staff
StaffService.link_user_to_staff(staff, user.id, request)

Staff Login

Staff members can log in using:

  • Email: Their email address (required field)
  • Password: The password sent via email or set via password reset

The login URL is: /accounts/login/

Testing

Test Superuser Creation

python manage.py createsuperuser

Prompts for:

  • Email (required)
  • First name (required)
  • Last name (required)
  • Password (required)

Test Staff Seeding

# Dry run
python manage.py seed_staff --physicians 3 --nurses 5 --dry-run

# Create staff
python manage.py seed_staff --physicians 3 --nurses 5

# Create staff with users
python manage.py seed_staff --physicians 3 --nurses 5 --create-users

# Create staff with users and send emails
python manage.py seed_staff --physicians 3 --nurses 5 --create-users --send-emails

Test API Endpoints

# Create staff
curl -X POST http://localhost:8000/api/staff/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"first_name": "Test", "last_name": "User", ...}'

# List staff
curl http://localhost:8000/api/staff/ \
  -H "Authorization: Bearer <token>"

# Create user account
curl -X POST http://localhost:8000/api/staff/<id>/create_user_account/ \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"role": "staff"}'

# Send invitation
curl -X POST http://localhost:8000/api/staff/<id>/send_invitation/ \
  -H "Authorization: Bearer <token>"

Security Considerations

  1. Password Generation:

    • Secure random passwords (12 characters)
    • Includes letters, numbers, and special characters
    • Sent via email (should be changed on first login)
  2. Email Security:

    • Credentials sent only to staff email
    • Email is required for user creation
    • Unique email constraint enforced
  3. Permissions:

    • Only PX Admins and Hospital Admins can create user accounts
    • Hospital Admins can only create accounts for staff in their hospital
    • Staff can only view other staff in their hospital
  4. Audit Trail:

    • All user creation/linking/unlinking actions logged
    • Email sending logged
    • Request context captured

Troubleshooting

Issue: "The Email field must be set"

Solution: Ensure staff member has an email address before creating user account.

Issue: "Staff member already has a user account"

Solution: Staff already has a user linked. Use link_user to link a different user or unlink_user first.

Issue: "You do not have permission to create user accounts"

Solution: User must be a PX Admin or Hospital Admin.

Issue: "You can only create accounts for staff in your hospital"

Solution: Hospital Admins can only create accounts for staff in their hospital.

Issue: Email not sending

Solution: Check email configuration in settings and ensure SMTP server is configured correctly.

Summary

The Staff User Account feature provides:

  1. Optional one-to-one relation between Staff and User models
  2. Custom UserManager for email-based authentication
  3. Complete CRUD operations for staff management
  4. User account creation, linking, and unlinking
  5. Credential email sending
  6. Role-based access control
  7. Audit logging
  8. Bilingual support (English/Arabic)
  9. Management command for bulk staff creation
  10. RESTful API endpoints with filtering and search

The implementation follows Django best practices, maintains backward compatibility, and provides a secure, scalable solution for staff user account management.