HH/docs/STAFF_USER_ACCOUNT_FEATURE_COMPLETE.md

22 KiB

Staff User Account Feature - Complete Implementation

Overview

The Staff User Account feature enables administrators to create optional user accounts for staff members, allowing them to log into the PX360 system. This implementation provides a complete CRUD interface with user account management capabilities.

Architecture

Model Relationship

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

# apps/organizations/models.py
class Staff(models.Model):
    # ... other fields ...
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='staff_profile'
    )

Key Features:

  • Optional: Staff can exist without a user account
  • SET_NULL: If user is deleted, staff record is preserved
  • Related name: user.staff_profile allows reverse lookup

Core Components

1. StaffService (apps/organizations/services.py)

The StaffService class provides all business logic for user account management:

Methods

create_user_for_staff(staff, role='staff', request=None)

Creates a User account for a Staff member.

Process:

  1. Validates staff doesn't already have a user account
  2. Requires staff to have an email address
  3. Generates unique username (format: firstname.lastname or firstname.lastnameN)
  4. Generates secure 12-character password
  5. Creates User with staff information:
    • Email as primary identifier
    • Username (optional, for backward compatibility)
    • First/last name
    • Employee ID
    • Hospital and Department
    • Active status
  6. Assigns role via group membership
  7. Links user to staff
  8. Logs audit trail

Returns: Created User instance

Raises: ValueError if staff already has user or no email

Links an existing User account to a Staff member.

Process:

  1. Validates staff doesn't have a user account
  2. Retrieves user by ID
  3. Links user to staff
  4. Updates user's organization data if missing
  5. Logs audit trail

Returns: Updated Staff instance

Raises: ValueError if staff has user or user not found

Removes User account association from a Staff member.

Process:

  1. Validates staff has a user account
  2. Sets staff.user to None
  3. Logs audit trail

Returns: Updated Staff instance

Raises: ValueError if staff has no user account

send_credentials_email(staff, password, request)

Sends login credentials email to staff member.

Process:

  1. Validates staff has email and user account
  2. Builds absolute login URL
  3. Renders HTML email template
  4. Sends email via Django's send_mail
  5. Logs audit trail

Raises: ValueError if no email or user account

generate_username(staff)

Generates a unique username from staff name.

Format: firstname.lastname (lowercase) Duplicate Handling: Appends incremental number (e.g., john.smith2)

Returns: Unique username string

generate_password(length=12)

Generates a secure random password.

Characters: ASCII letters + digits + punctuation Length: 12 characters (configurable)

Returns: Secure random password string

get_staff_type_role(staff_type)

Maps staff_type to role name.

Current Mapping: All staff types map to 'staff' role Extensible: Can be enhanced for role-based permissions

Returns: Role name string

2. API ViewSet (apps/organizations/views.py)

The StaffViewSet provides REST API endpoints:

Standard CRUD Operations

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

Custom Actions

POST /api/organizations/staff/{id}/create_user_account/

Creates a user account for staff member.

Permissions: PX Admin or Hospital Admin Body: Optional role parameter (defaults to staff type role) Process:

  1. Validates staff doesn't have user account
  2. Checks user permissions
  3. Creates user via StaffService
  4. Generates password
  5. Sends credentials email
  6. Returns success message with staff data

Response:

{
  "message": "User account created and credentials emailed successfully",
  "staff": { ...staff data... },
  "email": "staff@example.com"
}
POST /api/organizations/staff/{id}/link_user/

Links existing user account to staff member.

Permissions: PX Admin or Hospital Admin Body: Required user_id parameter Process:

  1. Validates staff doesn't have user account
  2. Checks user permissions
  3. Links user via StaffService
  4. Returns success message

Response:

{
  "message": "User account linked successfully",
  "staff": { ...staff data... }
}
POST /api/organizations/staff/{id}/unlink_user/

Removes user account association from staff member.

Permissions: PX Admin or Hospital Admin Process:

  1. Validates staff has user account
  2. Checks user permissions
  3. Unlinks user via StaffService
  4. Returns success message

Response:

{
  "message": "User account unlinked successfully",
  "staff": { ...staff data... }
}
POST /api/organizations/staff/{id}/send_invitation/

Sends credentials email to staff member.

Permissions: PX Admin or Hospital Admin Process:

  1. Validates staff has user account
  2. Checks user permissions
  3. Generates new password
  4. Updates user password
  5. Sends email via StaffService
  6. Returns success message

Response:

{
  "message": "Invitation email sent successfully",
  "staff": { ...staff data... }
}

3. Admin Interface (apps/organizations/admin.py)

The Django admin interface is enhanced with user account management:

StaffAdmin Features

List Display:

  • Staff name, type, job title, employee ID
  • Hospital, department
  • User account status (✓ Yes / ✗ No)
  • Status

Custom Column:

  • has_user_account: Displays user account status with color coding

Bulk Actions:

  1. "Create user accounts for selected staff"

    • Creates user accounts for multiple staff members
    • Sends credentials emails
    • Reports success/failure count
  2. "Send credential emails to selected staff"

    • Resends credentials to staff with existing accounts
    • Generates new passwords
    • Reports success/failure count

Filtering & Search:

  • Filter by status, hospital, staff type, specialization
  • Search by name, Arabic names, employee ID, license, job title

Autocomplete Fields:

  • Hospital, Department, User (for linking)

4. UI Templates

Staff List (templates/organizations/staff_list.html)

Features:

  • Filters: Hospital, status, staff type, search
  • Table displays user account status with badge
  • Quick actions for user account management:
    • Create user account (for staff without accounts)
    • Send invitation email (for staff with accounts)
    • Unlink user account (for staff with accounts)
  • Modals for confirmation dialogs
  • Pagination support

Actions Column:

  • View details (always available)
  • Create user account (if no user and has email)
  • Send invitation (if has user)
  • Unlink user (if has user)
  • Actions restricted to PX Admin and Hospital Admin

Staff Detail (templates/organizations/staff_detail.html)

User Account Card:

  • Displays user account status (alert box)
  • Shows user details (username, email, active status, created date)
  • Action buttons:
    • "Create User Account" (if no account)
    • "Resend Invitation Email" (if account exists)
    • "Unlink User Account" (if account exists)
  • Confirmation modals for each action

Other Cards:

  • Personal Information
  • Organization Information
  • Contact Information
  • Status Information

JavaScript Functions:

  • createUserAccount() - Shows modal and triggers API call
  • confirmCreateUser() - Executes create user account
  • sendInvitation() - Shows modal and triggers API call
  • confirmSendInvitation() - Executes send invitation
  • unlinkUserAccount() - Shows modal and triggers API call
  • confirmUnlinkUser() - Executes unlink user

5. Email Template (templates/organizations/emails/staff_credentials.html)

Design:

  • Professional HTML email with gradient header
  • Clean, readable layout
  • Responsive design

Content:

  • Welcome message
  • Credentials box with:
    • Username
    • Password
    • Email
  • Security notice (change password after first login)
  • Login button (links to system)
  • Footer with copyright

Styling:

  • Purple gradient theme (matches PX360 branding)
  • Color-coded credentials box
  • Warning banner for security notice
  • Mobile-friendly

6. Forms (apps/organizations/forms.py)

StaffForm:

  • All standard staff fields
  • Hospital filtering based on user role
  • Department filtering based on selected hospital
  • Email validation (lowercase, trimmed)
  • Employee ID uniqueness validation

No User Management in Form:

  • User account creation handled via separate actions
  • Keeps form focused on staff data
  • User management in detail view for better UX

Permission Model

Access Control

PX Admin:

  • Can create user accounts for any staff
  • Can link/unlink users for any staff
  • Can send invitations to any staff
  • Full access to all staff management features

Hospital Admin:

  • Can create user accounts for staff in their hospital
  • Can link/unlink users for staff in their hospital
  • Can send invitations to staff in their hospital
  • Cannot manage staff from other hospitals

Department Manager:

  • Can view staff in their department
  • Cannot create/link/unlink user accounts
  • Cannot manage user accounts

Regular Staff:

  • Can view staff in their hospital
  • Cannot create/link/unlink user accounts
  • Cannot manage user accounts

Implementation

Permissions enforced in:

  • API ViewSet actions
  • Admin actions
  • UI templates (buttons hidden for unauthorized users)

Workflow Examples

Example 1: Creating Staff and User Account

Step 1: Create Staff Profile

POST /api/organizations/staff/
{
  "first_name": "Ahmed",
  "last_name": "Al-Saud",
  "email": "ahmed.alsaud@hospital.com",
  "employee_id": "EMP001",
  "hospital": "...",
  "department": "...",
  "staff_type": "physician"
}

Step 2: Create User Account

POST /api/organizations/staff/{id}/create_user_account/
{
  "role": "staff"
}

Result:

  • User created with username: ahmed.alsaud
  • Password generated: Xk9#mP2$vL5!
  • Email sent to ahmed.alsaud@hospital.com
  • Staff.user linked to new user

Example 2: Linking Existing User

Step 1: Create Staff Profile (same as above)

Step 2: Link Existing User

POST /api/organizations/staff/{id}/link_user/
{
  "user_id": "123e4567-e89b-12d3-a456-426614174000"
}

Result:

  • Staff.user linked to existing user
  • User's organization data updated if missing

Example 3: Resending Credentials

Scenario: Staff member forgot their password

Action:

POST /api/organizations/staff/{id}/send_invitation/

Result:

  • New password generated: Qw7$rT3!nK9#
  • User password updated in database
  • Email sent with new credentials

Example 4: Removing Login Access

Scenario: Staff member leaves organization

Action:

POST /api/organizations/staff/{id}/unlink_user/

Result:

  • Staff.user set to None
  • User account still exists but no longer linked
  • Staff member cannot log in

Example 5: Bulk User Account Creation

Scenario: Onboarding 10 new staff members

Action:

  1. Go to Django Admin > Staff
  2. Select 10 staff members (all have emails)
  3. Choose "Create user accounts for selected staff"
  4. Click "Go"

Result:

  • 10 user accounts created
  • 10 emails sent with credentials
  • Admin message: "Created 10 user accounts. Failed: 0"

Technical Details

Username Generation Algorithm

base_username = f"{first_name.lower()}.{last_name.lower()}"
username = base_username
counter = 1

while User.objects.filter(username=username).exists():
    username = f"{base_username}{counter}"
    counter += 1

Examples:

  • John Smith → john.smith
  • Duplicate John Smith → john.smith2
  • Another duplicate → john.smith3

Password Generation

alphabet = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(alphabet) for _ in range(12))

Character Set:

  • Uppercase: A-Z
  • Lowercase: a-z
  • Digits: 0-9
  • Punctuation: !"#$%&'()*+,-./:;<=>?@[]^_`{|}~

Strength: Cryptographically secure (uses secrets module)

Email Sending

Configuration Required (settings.py):

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'noreply@px360.com'
EMAIL_HOST_PASSWORD = 'password'
DEFAULT_FROM_EMAIL = 'PX360 <noreply@px360.com>'

Alternative: Use Email Backend services (SendGrid, Mailgun, etc.)

Audit Logging

All user account operations are logged via AuditService.log_from_request():

Logged Events:

  • user_creation - When user account is created
  • other - For link/unlink/send invitation actions

Metadata Includes:

  • Staff ID and name
  • User ID (for link/unlink)
  • Role (for creation)
  • Timestamp
  • User who performed action

Security Considerations

1. Password Security

  • Passwords are hashed using Django's PBKDF2 algorithm
  • Generated passwords are only sent via email (never stored in plain text)
  • Staff should be instructed to change password after first login

2. Email Security

  • Credentials are sent via SMTP with TLS
  • Email templates include security warnings
  • Passwords are not included in any logs

3. Access Control

  • Role-based permissions enforced at all levels
  • Hospital admins can only manage their hospital's staff
  • Actions require proper CSRF tokens

4. Data Integrity

  • Foreign key constraints prevent orphaned records
  • SET_NULL on delete preserves staff if user is deleted
  • Validation prevents duplicate user accounts

5. Audit Trail

  • All user account operations are logged
  • Logs include who, when, and what
  • Metadata stored for analysis

Database Schema

Staff Model Fields

class Staff(models.Model):
    # Personal Information
    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)
    
    # Role Information
    staff_type = models.CharField(max_length=20, choices=STAFF_TYPE_CHOICES)
    job_title = models.CharField(max_length=100)
    license_number = models.CharField(max_length=50, blank=True)
    specialization = models.CharField(max_length=100, blank=True)
    
    # Employee Information
    employee_id = models.CharField(max_length=50, unique=True)
    email = models.EmailField(blank=True, null=True)
    
    # Organization
    hospital = models.ForeignKey(Hospital, on_delete=models.PROTECT)
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
    
    # User Account (Optional)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='staff_profile'
    )
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
    
    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

Indexes

  • employee_id: Unique index
  • user: Unique index (OneToOne)
  • hospital: Foreign key index
  • department: Foreign key index
  • email: Index for lookups

Testing Recommendations

Unit Tests

# Test StaffService methods
def test_create_user_for_staff():
    staff = create_test_staff(email="test@example.com")
    user = StaffService.create_user_for_staff(staff)
    assert staff.user == user
    assert user.email == "test@example.com"

def test_generate_username():
    staff = create_test_staff(first_name="John", last_name="Smith")
    username = StaffService.generate_username(staff)
    assert username == "john.smith"

def test_generate_password():
    password = StaffService.generate_password()
    assert len(password) == 12
    # Verify contains characters from each class

def test_link_user_to_staff():
    staff = create_test_staff()
    user = create_test_user()
    result = StaffService.link_user_to_staff(staff, user.id)
    assert staff.user == user

def test_unlink_user_from_staff():
    staff = create_test_staff_with_user()
    result = StaffService.unlink_user_from_staff(staff)
    assert staff.user is None

Integration Tests

# Test API endpoints
def test_create_user_account_api():
    client = authenticate_as_admin()
    staff = create_test_staff()
    response = client.post(f'/api/organizations/staff/{staff.id}/create_user_account/')
    assert response.status_code == 201
    assert staff.user is not None

def test_send_invitation_api():
    client = authenticate_as_admin()
    staff = create_test_staff_with_user()
    response = client.post(f'/api/organizations/staff/{staff.id}/send_invitation/')
    assert response.status_code == 200
    # Verify email was sent

def test_permissions():
    # Test that non-admins cannot create user accounts
    client = authenticate_as_staff()
    staff = create_test_staff()
    response = client.post(f'/api/organizations/staff/{staff.id}/create_user_account/')
    assert response.status_code == 403

UI Tests

# Test UI interactions
def test_create_user_button_visible_for_admins():
    staff = create_test_staff()
    admin_user = create_admin_user()
    response = client.get(f'/staff/{staff.id}/')
    assert 'Create User Account' in response.content

def test_create_user_button_hidden_for_staff():
    staff = create_test_staff()
    regular_user = create_regular_user()
    response = client.get(f'/staff/{staff.id}/')
    assert 'Create User Account' not in response.content

Future Enhancements

Potential Improvements

  1. Role-Based Permissions

    • Different roles for different staff types
    • More granular permissions per role
  2. Bulk Import

    • Import staff from CSV/Excel
    • Auto-create user accounts during import
  3. Self-Service

    • Allow staff to request user account
    • Approval workflow for requests
  4. Password Reset

    • Integration with Django's password reset
    • Self-service password reset
  5. 2FA Support

    • Two-factor authentication for staff
    • Enhanced security options
  6. Session Management

    • Track active sessions
    • Force logout from all devices
  7. Audit Reports

    • Generate audit reports
    • Export to PDF/Excel
  8. Email Customization

    • Customizable email templates
    • Multi-language support

Troubleshooting

Common Issues

Issue: "Staff member already has a user account"

  • Cause: Attempting to create duplicate user account
  • Solution: Check staff.user before creating, or unlink first

Issue: "Staff member must have an email address"

  • Cause: Creating user account without email
  • Solution: Add email to staff profile first

Issue: Email not sent

  • Cause: Email configuration issue
  • Solution: Check EMAIL_* settings, verify SMTP credentials

Issue: Username already exists

  • Cause: Non-unique username generation
  • Solution: The service handles this automatically by appending numbers

Issue: Permission denied

  • Cause: User lacks required role
  • Solution: Ensure user is PX Admin or Hospital Admin

Issue: User account creation failed

  • Cause: Invalid data, constraints, or service error
  • Solution: Check error message, validate staff data

API Reference

StaffViewSet Endpoints

Method Endpoint Description Auth
GET /api/organizations/staff/ List staff Required
POST /api/organizations/staff/ Create staff PX Admin / Hospital Admin
GET /api/organizations/staff/{id}/ Get staff details Required
PUT /api/organizations/staff/{id}/ Update staff PX Admin / Hospital Admin
PATCH /api/organizations/staff/{id}/ Partial update PX Admin / Hospital Admin
DELETE /api/organizations/staff/{id}/ Delete staff PX Admin / Hospital Admin
POST /api/organizations/staff/{id}/create_user_account/ Create user account PX Admin / Hospital Admin
POST /api/organizations/staff/{id}/link_user/ Link existing user PX Admin / Hospital Admin
POST /api/organizations/staff/{id}/unlink_user/ Unlink user PX Admin / Hospital Admin
POST /api/organizations/staff/{id}/send_invitation/ Send invitation PX Admin / Hospital Admin

Response Formats

Success (201 Created):

{
  "message": "User account created and credentials emailed successfully",
  "staff": {
    "id": "...",
    "first_name": "Ahmed",
    "last_name": "Al-Saud",
    "user": {
      "id": "...",
      "email": "ahmed.alsaud@hospital.com",
      "username": "ahmed.alsaud"
    }
  },
  "email": "ahmed.alsaud@hospital.com"
}

Error (400 Bad Request):

{
  "error": "Staff member already has a user account"
}

Error (403 Forbidden):

{
  "error": "You do not have permission to create user accounts"
}

Conclusion

The Staff User Account feature provides a complete, production-ready solution for managing staff access to the PX360 system. With robust security, comprehensive audit logging, and a user-friendly interface, administrators can efficiently manage staff user accounts from creation to termination.

Key Features Summary

Optional one-to-one relationship with User model Automatic username and password generation Secure credential delivery via email Link/unlink existing user accounts Bulk operations in admin interface Role-based access control Complete audit trail RESTful API with comprehensive endpoints User-friendly web interface Internationalization support Professional email templates

The implementation follows Django best practices and is ready for production use.