Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

3116 lines
103 KiB
Python

"""
Accounts app views for hospital management system with comprehensive CRUD operations.
"""
import os
from allauth.account.views import LoginView
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import (
TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.http import JsonResponse
from django.contrib import messages
from django.db.models import Q, Count
from django.utils import timezone
from django.urls import reverse_lazy, reverse
from django.core.paginator import Paginator
from datetime import timedelta
from hr.models import Employee
from .models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory
from .forms import (
UserForm, UserCreateForm, TwoFactorDeviceForm, SocialAccountForm,
AccountsSearchForm, PasswordChangeForm
)
from core.utils import AuditLogger
# ============================================================================
# USER VIEWS (FULL CRUD - Master Data)
# ============================================================================
class UserListView(LoginRequiredMixin, ListView):
"""
User listing view.
"""
model = User
template_name = 'account/user_list.html'
context_object_name = 'users'
paginate_by = 25
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return User.objects.none()
queryset = User.objects.filter(tenant=tenant)
# Apply filters
role = self.request.GET.get('role')
if role:
queryset = queryset.filter(role=role)
department = self.request.GET.get('department')
if department:
queryset = queryset.filter(department=department)
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'inactive':
queryset = queryset.filter(is_active=False)
elif status == 'pending':
queryset = queryset.filter(is_approved=False)
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(username__icontains=search) |
Q(email__icontains=search) |
Q(first_name__icontains=search) |
Q(last_name__icontains=search) |
Q(employee_id__icontains=search)
)
return queryset.order_by('last_name', 'first_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
# Get filter options
context.update({
'roles': User.objects.filter(tenant=tenant).values_list('role', flat=True).distinct(),
'departments': User.objects.filter(tenant=tenant).values_list('department', flat=True).distinct(),
'search_form': AccountsSearchForm(self.request.GET),
})
return context
class UserDetailView(LoginRequiredMixin, DetailView):
"""
User detail view.
"""
model = User
template_name = 'account/user_detail.html'
context_object_name = 'user_profile'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return User.objects.none()
return User.objects.filter(tenant=tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_profile = self.get_object()
# Get user's sessions
context['active_sessions'] = UserSession.objects.filter(
user=user_profile,
is_active=True
).order_by('-created_at')
# Get user's two-factor devices
context['two_factor_devices'] = TwoFactorDevice.objects.filter(
user=user_profile,
is_active=True
).order_by('-created_at')
# Get user's social accounts
context['social_accounts'] = SocialAccount.objects.filter(
user=user_profile,
is_active=True
).order_by('-created_at')
# Get password history
context['password_history'] = PasswordHistory.objects.filter(
user=user_profile
).order_by('-created_at')[:5]
# Get recent audit logs
from core.models import AuditLogEntry
context['recent_activity'] = AuditLogEntry.objects.filter(
tenant=user_profile.tenant,
user=user_profile
).order_by('-timestamp')[:10]
return context
class UserCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new user.
"""
model = User
form_class = UserCreateForm
template_name = 'account/user_create.html'
permission_required = 'accounts.add_user'
success_url = reverse_lazy('accounts:user_list')
def form_valid(self, form):
# Set tenant
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log user creation
AuditLogger.log_event(
tenant=form.instance.tenant,
event_type='CREATE',
event_category='USER_MANAGEMENT',
action='Create User',
description=f'Created new user: {self.object.username}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'User "{self.object.username}" created successfully.')
return response
class UserUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update user information.
"""
model = User
form_class = UserForm
template_name = 'account/user_form.html'
permission_required = 'accounts.change_user'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return User.objects.none()
return User.objects.filter(tenant=tenant)
def get_success_url(self):
return reverse('accounts:user_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log user update
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='UPDATE',
event_category='USER_MANAGEMENT',
action='Update User',
description=f'Updated user: {self.object.username}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'User "{self.object.username}" updated successfully.')
return response
class UserDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete user (soft delete to inactive).
"""
model = User
template_name = 'account/user_confirm_delete.html'
permission_required = 'accounts.delete_user'
success_url = reverse_lazy('accounts:user_list')
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return User.objects.none()
return User.objects.filter(tenant=tenant)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Soft delete - set to inactive
self.object.is_active = False
self.object.save()
# Log user deletion
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='DELETE',
event_category='USER_MANAGEMENT',
action='Deactivate User',
description=f'Deactivated user: {self.object.username}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'User "{self.object.username}" deactivated successfully.')
return redirect(self.success_url)
# ============================================================================
# TWO FACTOR DEVICE VIEWS (FULL CRUD - Security Data)
# ============================================================================
class TwoFactorDeviceListView(LoginRequiredMixin, ListView):
"""
List two-factor devices.
"""
model = TwoFactorDevice
template_name = 'account/two_factor_device_list.html'
context_object_name = 'devices'
paginate_by = 20
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return TwoFactorDevice.objects.none()
queryset = TwoFactorDevice.objects.filter(user__tenant=tenant)
# Apply filters
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
device_type = self.request.GET.get('device_type')
if device_type:
queryset = queryset.filter(device_type=device_type)
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'inactive':
queryset = queryset.filter(is_active=False)
return queryset.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
context.update({
'device_types': TwoFactorDevice.DEVICE_TYPE_CHOICES,
'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
})
return context
class TwoFactorDeviceDetailView(LoginRequiredMixin, DetailView):
"""
Display two-factor device details.
"""
model = TwoFactorDevice
template_name = 'account/two_factor_device_detail.html'
context_object_name = 'device'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return TwoFactorDevice.objects.none()
return TwoFactorDevice.objects.filter(user__tenant=tenant)
class TwoFactorDeviceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new two-factor device.
"""
model = TwoFactorDevice
form_class = TwoFactorDeviceForm
template_name = 'account/two_factor_device_form.html'
permission_required = 'accounts.add_twofactordevice'
success_url = reverse_lazy('accounts:two_factor_device_list')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
response = super().form_valid(form)
# Generate secret key for TOTP devices
if form.instance.device_type == 'TOTP':
import secrets
form.instance.secret_key = secrets.token_urlsafe(32)
form.instance.save()
# Log device creation
AuditLogger.log_event(
tenant=self.request.user.tenant,
event_type='CREATE',
event_category='SECURITY',
action='Create Two-Factor Device',
description=f'Created two-factor device: {self.object.name}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Two-factor device "{self.object.name}" created successfully.')
return response
class TwoFactorDeviceUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update two-factor device.
"""
model = TwoFactorDevice
form_class = TwoFactorDeviceForm
template_name = 'account/two_factor_device_form.html'
permission_required = 'accounts.change_twofactordevice'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return TwoFactorDevice.objects.none()
return TwoFactorDevice.objects.filter(user__tenant=tenant)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_success_url(self):
return reverse('accounts:two_factor_device_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log device update
AuditLogger.log_event(
tenant=self.request.user.tenant,
event_type='UPDATE',
event_category='SECURITY',
action='Update Two-Factor Device',
description=f'Updated two-factor device: {self.object.name}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Two-factor device "{self.object.name}" updated successfully.')
return response
class TwoFactorDeviceDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete two-factor device.
"""
model = TwoFactorDevice
template_name = 'account/two_factor_device_confirm_delete.html'
permission_required = 'accounts.delete_twofactordevice'
success_url = reverse_lazy('accounts:two_factor_device_list')
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return TwoFactorDevice.objects.none()
return TwoFactorDevice.objects.filter(user__tenant=tenant)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
device_name = self.object.name
# Log device deletion
AuditLogger.log_event(
tenant=getattr(request, 'tenant', None),
event_type='DELETE',
event_category='SECURITY',
action='Delete Two-Factor Device',
description=f'Deleted two-factor device: {device_name}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'Two-factor device "{device_name}" deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# SOCIAL ACCOUNT VIEWS (FULL CRUD - Integration Data)
# ============================================================================
class SocialAccountListView(LoginRequiredMixin, ListView):
"""
List social accounts.
"""
model = SocialAccount
template_name = 'account/social_account_list.html'
context_object_name = 'social_accounts'
paginate_by = 20
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return SocialAccount.objects.none()
queryset = SocialAccount.objects.filter(user__tenant=tenant)
# Apply filters
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
provider = self.request.GET.get('provider')
if provider:
queryset = queryset.filter(provider=provider)
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'inactive':
queryset = queryset.filter(is_active=False)
return queryset.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
context.update({
'providers': SocialAccount.objects.filter(
user__tenant=tenant
).values_list('provider', flat=True).distinct(),
'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
})
return context
class SocialAccountDetailView(LoginRequiredMixin, DetailView):
"""
Display social account details.
"""
model = SocialAccount
template_name = 'account/social_account_detail.html'
context_object_name = 'social_account'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return SocialAccount.objects.none()
return SocialAccount.objects.filter(user__tenant=tenant)
class SocialAccountCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new social account.
"""
model = SocialAccount
form_class = SocialAccountForm
template_name = 'account/social_account_form.html'
permission_required = 'accounts.add_socialaccount'
success_url = reverse_lazy('accounts:social_account_list')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
response = super().form_valid(form)
# Log social account creation
AuditLogger.log_event(
tenant=self.request.user.tenant,
event_type='CREATE',
event_category='INTEGRATION',
action='Create Social Account',
description=f'Created social account: {self.object.provider}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Social account "{self.object.provider}" created successfully.')
return response
class SocialAccountUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update social account.
"""
model = SocialAccount
form_class = SocialAccountForm
template_name = 'account/social_account_form.html'
permission_required = 'accounts.change_socialaccount'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return SocialAccount.objects.none()
return SocialAccount.objects.filter(user__tenant=tenant)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_success_url(self):
return reverse('accounts:social_account_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log social account update
AuditLogger.log_event(
tenant=self.request.user.tenant,
event_type='UPDATE',
event_category='INTEGRATION',
action='Update Social Account',
description=f'Updated social account: {self.object.provider}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Social account "{self.object.provider}" updated successfully.')
return response
class SocialAccountDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete social account.
"""
model = SocialAccount
template_name = 'account/social_account_confirm_delete.html'
permission_required = 'accounts.delete_socialaccount'
success_url = reverse_lazy('accounts:social_account_list')
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return SocialAccount.objects.none()
return SocialAccount.objects.filter(user__tenant=tenant)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
provider = self.object.provider
# Log social account deletion
AuditLogger.log_event(
tenant=getattr(request, 'tenant', None),
event_type='DELETE',
event_category='INTEGRATION',
action='Delete Social Account',
description=f'Deleted social account: {provider}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'Social account "{provider}" deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# USER SESSION VIEWS (READ-ONLY - System Generated)
# ============================================================================
class UserSessionListView(LoginRequiredMixin, ListView):
"""
List user sessions.
"""
model = UserSession
template_name = 'account/user_session_list.html'
context_object_name = 'sessions'
paginate_by = 50
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return UserSession.objects.none()
queryset = UserSession.objects.filter(user__tenant=tenant)
# Apply filters
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'expired':
queryset = queryset.filter(expires_at__lt=timezone.now())
device_type = self.request.GET.get('device_type')
if device_type:
queryset = queryset.filter(device_type=device_type)
date_from = self.request.GET.get('date_from')
if date_from:
queryset = queryset.filter(created_at__gte=date_from)
date_to = self.request.GET.get('date_to')
if date_to:
queryset = queryset.filter(created_at__lte=date_to)
return queryset.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
context.update({
'device_types': UserSession.objects.filter(
user__tenant=tenant
).values_list('device_type', flat=True).distinct(),
'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
})
return context
class UserSessionDetailView(LoginRequiredMixin, DetailView):
"""
Display user session details.
"""
model = UserSession
template_name = 'account/user_session_detail.html'
context_object_name = 'session'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return UserSession.objects.none()
return UserSession.objects.filter(user__tenant=tenant)
# ============================================================================
# PASSWORD HISTORY VIEWS (READ-ONLY - System Generated)
# ============================================================================
class PasswordHistoryListView(LoginRequiredMixin, ListView):
"""
List password history.
"""
model = PasswordHistory
template_name = 'account/password_history_list.html'
context_object_name = 'password_history'
paginate_by = 50
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return PasswordHistory.objects.none()
queryset = PasswordHistory.objects.filter(user__tenant=tenant)
# Apply filters
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
date_from = self.request.GET.get('date_from')
if date_from:
queryset = queryset.filter(created_at__gte=date_from)
date_to = self.request.GET.get('date_to')
if date_to:
queryset = queryset.filter(created_at__lte=date_to)
return queryset.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
context.update({
'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
})
return context
class PasswordHistoryDetailView(LoginRequiredMixin, DetailView):
"""
Display password history details.
"""
model = PasswordHistory
template_name = 'account/password_history_detail.html'
context_object_name = 'password_history'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return PasswordHistory.objects.none()
return PasswordHistory.objects.filter(user__tenant=tenant)
# ============================================================================
# PROFILE AND SESSION MANAGEMENT VIEWS
# ============================================================================
class UserProfileView(LoginRequiredMixin, TemplateView):
"""
User profile management view.
"""
template_name = 'account/user_profile.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = self.request.user
# Get user's sessions
context['active_sessions'] = UserSession.objects.filter(
user=user,
is_active=True
).order_by('-created_at')
# Get user's two-factor devices
context['two_factor_devices'] = TwoFactorDevice.objects.filter(
user=user,
is_active=True
).order_by('-created_at')
# Get user's social accounts
context['social_accounts'] = SocialAccount.objects.filter(
user=user,
is_active=True
).order_by('-created_at')
# Get password history
context['password_history'] = PasswordHistory.objects.filter(
user=user
).order_by('-created_at')[:5]
return context
class SessionManagementView(LoginRequiredMixin, ListView):
"""
Session management view.
"""
model = UserSession
template_name = 'account/session_management.html'
context_object_name = 'sessions'
paginate_by = 50
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return UserSession.objects.none()
queryset = UserSession.objects.filter(user__tenant=tenant)
# Apply filters
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'expired':
queryset = queryset.filter(expires_at__lt=timezone.now())
device_type = self.request.GET.get('device_type')
if device_type:
queryset = queryset.filter(device_type=device_type)
return queryset.order_by('-created_at')
# ============================================================================
# HTMX VIEWS FOR REAL-TIME UPDATES
# ============================================================================
@login_required
def user_search(request):
"""
HTMX view for user search.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
search_query = request.GET.get('search', '')
queryset = User.objects.filter(tenant=tenant)
if search_query:
queryset = queryset.filter(
Q(username__icontains=search_query) |
Q(email__icontains=search_query) |
Q(first_name__icontains=search_query) |
Q(last_name__icontains=search_query) |
Q(employee_id__icontains=search_query)
)
users = queryset.order_by('last_name', 'first_name')[:20]
return render(request, 'account/partials/user_list.html', {
'users': users
})
@login_required
def user_stats(request):
"""
HTMX view for user statistics.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
# Calculate user statistics
total_users = User.objects.filter(tenant=tenant).count()
active_users = User.objects.filter(tenant=tenant, is_active=True).count()
pending_approval = User.objects.filter(tenant=tenant, is_approved=False).count()
# Active sessions in last 24 hours
yesterday = timezone.now() - timedelta(days=1)
active_sessions = UserSession.objects.filter(
user__tenant=tenant,
last_activity_at__gte=yesterday,
is_active=True
).count()
# Users by role
role_stats = User.objects.filter(tenant=tenant).values('role').annotate(
count=Count('id')
).order_by('-count')[:5]
# Two-factor adoption
two_factor_users = User.objects.filter(
tenant=tenant,
twofactordevice__is_active=True
).distinct().count()
stats = {
'total_users': total_users,
'active_users': active_users,
'pending_approval': pending_approval,
'active_sessions': active_sessions,
'two_factor_users': two_factor_users,
'role_stats': role_stats,
}
return render(request, 'account/partials/user_stats.html', {'stats': stats})
@login_required
def session_list(request):
"""
HTMX view for session list.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
user_id = request.GET.get('user_id')
if user_id:
sessions = UserSession.objects.filter(
user_id=user_id,
user__tenant=tenant
).order_by('-created_at')[:10]
else:
sessions = UserSession.objects.filter(
user__tenant=tenant,
is_active=True
).order_by('-created_at')[:20]
return render(request, 'account/partials/session_list.html', {
'sessions': sessions
})
@login_required
def two_factor_setup(request):
"""
HTMX view for two-factor authentication setup.
"""
user = request.user
if request.method == 'POST':
device_type = request.POST.get('device_type')
device_name = request.POST.get('device_name')
if device_type and device_name:
# Create new two-factor device
device = TwoFactorDevice.objects.create(
user=user,
name=device_name,
device_type=device_type,
phone_number=request.POST.get('phone_number'),
email_address=request.POST.get('email_address'),
)
# Generate secret key for TOTP devices
if device_type == 'TOTP':
import secrets
device.secret_key = secrets.token_urlsafe(32)
device.save()
# Log the setup
AuditLogger.log_event(
tenant=getattr(request, 'tenant', None),
event_type='CREATE',
event_category='SECURITY',
action='Setup Two-Factor Device',
description=f'User setup two-factor device: {device_name}',
user=request.user,
content_object=device,
request=request
)
return JsonResponse({'status': 'created', 'device_id': str(device.device_id)})
return render(request, 'account/partials/two_factor_setup.html')
# ============================================================================
# ACTION VIEWS FOR WORKFLOW OPERATIONS
# ============================================================================
@login_required
def end_session(request, session_id):
"""
End a user session.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
session = get_object_or_404(
UserSession,
session_id=session_id,
user__tenant=tenant
)
# End the session
session.end_session()
# Log the action
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='AUTHENTICATION',
action='End User Session',
description=f'Ended session for user: {session.user.username}',
user=request.user,
content_object=session,
additional_data={
'target_user': session.user.username,
'session_ip': session.ip_address,
},
request=request
)
messages.success(request, f'Session for {session.user.username} ended successfully.')
return redirect('accounts:session_management')
@login_required
def user_profile_update(request):
"""
HTMX view for user profile update.
"""
if request.method == 'POST':
employee = Employee.objects.get(user=request.user)
# Update basic information
employee.first_name = request.POST.get('first_name', employee.first_name)
employee.last_name = request.POST.get('last_name', employee.last_name)
employee.email = request.POST.get('email', employee.email)
employee.phone = request.POST.get('phone', employee.phone)
employee.mobile_phone = request.POST.get('mobile_phone', employee.mobile_phone)
employee.bio = request.POST.get('bio', employee.bio)
# Update preferences
employee.user_timezone = request.POST.get('timezone', employee.user_timezone)
employee.language = request.POST.get('language', employee.language)
employee.theme = request.POST.get('theme', employee.theme)
employee.save()
# Log the update
AuditLogger.log_event(
tenant=getattr(request, 'tenant', None),
event_type='UPDATE',
event_category='DATA_MODIFICATION',
action='Update User Profile',
description=f'User updated their profile: {employee.user.username}',
user=request.user,
content_object=employee,
request=request
)
messages.success(request, 'Profile updated successfully.')
return redirect('accounts:user_profile')
return JsonResponse({'error': 'Invalid request'}, status=400)
@login_required
def remove_two_factor_device(request, device_id):
"""
Remove a two-factor device.
"""
device = get_object_or_404(
TwoFactorDevice,
device_id=device_id,
user=request.user
)
device_name = device.name
device.delete()
# Log the removal
AuditLogger.log_event(
tenant=getattr(request, 'tenant', None),
event_type='DELETE',
event_category='SECURITY',
action='Remove Two-Factor Device',
description=f'User removed two-factor device: {device_name}',
user=request.user,
additional_data={'device_name': device_name},
request=request
)
messages.success(request, f'Two-factor device "{device_name}" removed successfully.')
return redirect('accounts:user_profile')
@login_required
def user_activity_log(request, user_id):
"""
HTMX view for user activity log.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
user_profile = get_object_or_404(User, id=user_id, tenant=tenant)
# Get recent audit logs for this user
from core.models import AuditLogEntry
audit_logs = AuditLogEntry.objects.filter(
tenant=tenant,
user=user_profile
).order_by('-timestamp')[:20]
return render(request, 'account/partials/user_activity_log.html', {
'audit_logs': audit_logs,
'user_profile': user_profile
})
@login_required
def approve_user(request, pk):
"""
Approve a user account.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('accounts:user_list')
user = get_object_or_404(User, pk=pk, tenant=tenant)
user.is_approved = True
user.save()
# Log approval
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='USER_MANAGEMENT',
action='Approve User',
description=f'Approved user: {user.username}',
user=request.user,
content_object=user,
request=request
)
messages.success(request, f'User "{user.username}" approved successfully.')
return redirect('accounts:user_detail', pk=pk)
@login_required
def activate_user(request, pk):
"""
Activate a user account.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('accounts:user_list')
user = get_object_or_404(User, pk=pk, tenant=tenant)
user.is_active = True
user.save()
# Log activation
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='USER_MANAGEMENT',
action='Activate User',
description=f'Activated user: {user.username}',
user=request.user,
content_object=user,
request=request
)
messages.success(request, f'User "{user.username}" activated successfully.')
return redirect('accounts:user_detail', pk=pk)
@login_required
def reset_user_password(request, pk):
"""
Reset user password.
"""
tenant = getattr(request, 'tenant', None)
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('accounts:user_list')
user = get_object_or_404(User, pk=pk, tenant=tenant)
# Generate temporary password
import secrets
import string
temp_password = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(12))
# Set password and force change on next login
user.set_password(temp_password)
user.password_change_required = True
user.save()
# Log password reset
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='SECURITY',
action='Reset User Password',
description=f'Reset password for user: {user.username}',
user=request.user,
content_object=user,
request=request
)
messages.success(request, f'Password reset for "{user.username}". Temporary password: {temp_password}')
return redirect('accounts:user_detail', pk=pk)
def upload_avatar(request, pk):
tenant = getattr(request, 'tenant', None)
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('accounts:user_list')
user = get_object_or_404(User, pk=pk, tenant=tenant)
if request.method == 'POST':
if 'profile_picture' in request.FILES:
# Delete old profile picture if it exists
if user.profile_picture:
old_picture_path = user.profile_picture.path
if os.path.exists(old_picture_path):
os.remove(old_picture_path)
# Save new profile picture
user.profile_picture = request.FILES['profile_picture']
user.save()
# Log the upload
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='USER_MANAGEMENT',
action='Upload Profile Picture',
description=f'Uploaded profile picture for user: {user.username}',
user=request.user,
content_object=user,
request=request
)
messages.success(request, f'Profile picture updated successfully for "{user.username}".')
if request.headers.get('HX-Request'):
# Return HTMX response with updated image
return render(request, 'account/partials/profile_picture.html', {
'user_profile': user
})
return redirect('accounts:user_detail', pk=pk)
else:
messages.error(request, 'No image file was uploaded.')
# For GET requests, return the upload form
if request.headers.get('HX-Request'):
return render(request, 'account/partials/upload_avatar_form.html', {
'user_profile': user
})
return redirect('accounts:user_detail', pk=pk)
# """
# Accounts app views for hospital management system with comprehensive CRUD operations.
# """
#
# from django.shortcuts import render, get_object_or_404, redirect
# from django.contrib.auth import authenticate, login, logout
# from django.contrib.auth.decorators import login_required
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.views.generic import (
# TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView
# )
# from django.http import JsonResponse
# from django.contrib import messages
# from django.db.models import Q, Count
# from django.utils import timezone
# from django.urls import reverse_lazy, reverse
# from django.core.paginator import Paginator
# from datetime import timedelta
# from .models import *
# from .forms import *
# from core.utils import AuditLogger
#
# # ============================================================================
# # USER VIEWS (FULL CRUD - Master Data)
# # ============================================================================
#
# from core.utils import AuditLogger
#
#
# # ============================================================================
# # USER VIEWS (FULL CRUD - Master Data)
# # ============================================================================
#
# class UserListView(LoginRequiredMixin, ListView):
# """
# User listing view.
# """
# model = User
# template_name = 'accounts/user_list.html'
# context_object_name = 'users'
# paginate_by = 25
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return User.objects.none()
#
# queryset = User.objects.filter(tenant=tenant)
#
# # Apply filters
# role = self.request.GET.get('role')
# if role:
# queryset = queryset.filter(role=role)
#
# department = self.request.GET.get('department')
# if department:
# queryset = queryset.filter(department=department)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'inactive':
# queryset = queryset.filter(is_active=False)
# elif status == 'pending':
# queryset = queryset.filter(is_approved=False)
#
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(username__icontains=search) |
# Q(email__icontains=search) |
# Q(first_name__icontains=search) |
# Q(last_name__icontains=search) |
# Q(employee_id__icontains=search)
# )
#
# return queryset.order_by('last_name', 'first_name')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
#
# if tenant:
# # Get filter options
# context.update({
# 'roles': User.objects.filter(tenant=tenant).values_list('role', flat=True).distinct(),
# 'departments': User.objects.filter(tenant=tenant).values_list('department', flat=True).distinct(),
# 'search_form': AccountsSearchForm(self.request.GET),
# })
#
# return context
#
#
# class UserDetailView(LoginRequiredMixin, DetailView):
# """
# User detail view.
# """
# model = User
# template_name = 'accounts/user_detail.html'
# context_object_name = 'user_profile'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return User.objects.none()
# return User.objects.filter(tenant=tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# user_profile = self.get_object()
#
# # Get user's sessions
# context['active_sessions'] = UserSession.objects.filter(
# user=user_profile,
# is_active=True
# ).order_by('-created_at')
#
# # Get user's two-factor devices
# context['two_factor_devices'] = TwoFactorDevice.objects.filter(
# user=user_profile,
# is_active=True
# ).order_by('-created_at')
#
# # Get user's social accounts
# context['social_accounts'] = SocialAccount.objects.filter(
# user=user_profile,
# is_active=True
# ).order_by('-created_at')
#
# # Get password history
# context['password_history'] = PasswordHistory.objects.filter(
# user=user_profile
# ).order_by('-created_at')[:5]
#
# # Get recent audit logs
# from core.models import AuditLogEntry
# context['recent_activity'] = AuditLogEntry.objects.filter(
# tenant=user_profile.tenant,
# user=user_profile
# ).order_by('-timestamp')[:10]
#
# return context
#
#
# class UserCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create new user.
# """
# model = User
# form_class = UserCreateForm
# template_name = 'accounts/user_create.html'
# permission_required = 'accounts.add_user'
# success_url = reverse_lazy('accounts:user_list')
#
# def form_valid(self, form):
# # Set tenant
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log user creation
# AuditLogger.log_event(
# tenant=form.instance.tenant,
# event_type='CREATE',
# event_category='USER_MANAGEMENT',
# action='Create User',
# description=f'Created new user: {self.object.username}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'User "{self.object.username}" created successfully.')
# return response
#
#
# class UserUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update user information.
# """
# model = User
# form_class = UserForm
# template_name = 'accounts/user_form.html'
# permission_required = 'accounts.change_user'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return User.objects.none()
# return User.objects.filter(tenant=tenant)
#
# def get_success_url(self):
# return reverse('accounts:user_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log user update
# AuditLogger.log_event(
# tenant=self.object.tenant,
# event_type='UPDATE',
# event_category='USER_MANAGEMENT',
# action='Update User',
# description=f'Updated user: {self.object.username}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'User "{self.object.username}" updated successfully.')
# return response
#
#
# class UserDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete user (soft delete to inactive).
# """
# model = User
# template_name = 'accounts/user_confirm_delete.html'
# permission_required = 'accounts.delete_user'
# success_url = reverse_lazy('accounts:user_list')
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return User.objects.none()
# return User.objects.filter(tenant=tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
#
# # Soft delete - set to inactive
# self.object.is_active = False
# self.object.save()
#
# # Log user deletion
# AuditLogger.log_event(
# tenant=self.object.tenant,
# event_type='DELETE',
# event_category='USER_MANAGEMENT',
# action='Deactivate User',
# description=f'Deactivated user: {self.object.username}',
# user=request.user,
# content_object=self.object,
# request=request
# )
#
# messages.success(request, f'User "{self.object.username}" deactivated successfully.')
# return redirect(self.success_url)
#
#
# # ============================================================================
# # TWO FACTOR DEVICE VIEWS (FULL CRUD - Security Data)
# # ============================================================================
#
# class TwoFactorDeviceListView(LoginRequiredMixin, ListView):
# """
# List two-factor devices.
# """
# model = TwoFactorDevice
# template_name = 'accounts/two_factor_device_list.html'
# context_object_name = 'devices'
# paginate_by = 20
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return TwoFactorDevice.objects.none()
#
# queryset = TwoFactorDevice.objects.filter(user__tenant=tenant)
#
# # Apply filters
# user_id = self.request.GET.get('user_id')
# if user_id:
# queryset = queryset.filter(user_id=user_id)
#
# device_type = self.request.GET.get('device_type')
# if device_type:
# queryset = queryset.filter(device_type=device_type)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'inactive':
# queryset = queryset.filter(is_active=False)
#
# return queryset.order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
#
# if tenant:
# context.update({
# 'device_types': TwoFactorDevice.DEVICE_TYPE_CHOICES,
# 'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
# })
#
# return context
#
#
# class TwoFactorDeviceDetailView(LoginRequiredMixin, DetailView):
# """
# Display two-factor device details.
# """
# model = TwoFactorDevice
# template_name = 'accounts/two_factor_device_detail.html'
# context_object_name = 'device'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return TwoFactorDevice.objects.none()
# return TwoFactorDevice.objects.filter(user__tenant=tenant)
#
#
# class TwoFactorDeviceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create new two-factor device.
# """
# model = TwoFactorDevice
# form_class = TwoFactorDeviceForm
# template_name = 'accounts/two_factor_device_form.html'
# permission_required = 'accounts.add_twofactordevice'
# success_url = reverse_lazy('accounts:two_factor_device_list')
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Generate secret key for TOTP devices
# if form.instance.device_type == 'TOTP':
# import secrets
# form.instance.secret_key = secrets.token_urlsafe(32)
# form.instance.save()
#
# # Log device creation
# AuditLogger.log_event(
# tenant=self.request.user.tenant,
# event_type='CREATE',
# event_category='SECURITY',
# action='Create Two-Factor Device',
# description=f'Created two-factor device: {self.object.name}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Two-factor device "{self.object.name}" created successfully.')
# return response
#
#
# class TwoFactorDeviceUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update two-factor device.
# """
# model = TwoFactorDevice
# form_class = TwoFactorDeviceForm
# template_name = 'accounts/two_factor_device_form.html'
# permission_required = 'accounts.change_twofactordevice'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return TwoFactorDevice.objects.none()
# return TwoFactorDevice.objects.filter(user__tenant=tenant)
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_success_url(self):
# return reverse('accounts:two_factor_device_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log device update
# AuditLogger.log_event(
# tenant=self.request.user.tenant,
# event_type='UPDATE',
# event_category='SECURITY',
# action='Update Two-Factor Device',
# description=f'Updated two-factor device: {self.object.name}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Two-factor device "{self.object.name}" updated successfully.')
# return response
#
#
# class TwoFactorDeviceDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete two-factor device.
# """
# model = TwoFactorDevice
# template_name = 'accounts/two_factor_device_confirm_delete.html'
# permission_required = 'accounts.delete_twofactordevice'
# success_url = reverse_lazy('accounts:two_factor_device_list')
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return TwoFactorDevice.objects.none()
# return TwoFactorDevice.objects.filter(user__tenant=tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
# device_name = self.object.name
#
# # Log device deletion
# AuditLogger.log_event(
# tenant=getattr(request, 'tenant', None),
# event_type='DELETE',
# event_category='SECURITY',
# action='Delete Two-Factor Device',
# description=f'Deleted two-factor device: {device_name}',
# user=request.user,
# content_object=self.object,
# request=request
# )
#
# messages.success(request, f'Two-factor device "{device_name}" deleted successfully.')
# return super().delete(request, *args, **kwargs)
#
#
# # ============================================================================
# # SOCIAL ACCOUNT VIEWS (FULL CRUD - Integration Data)
# # ============================================================================
#
# class SocialAccountListView(LoginRequiredMixin, ListView):
# """
# List social accounts.
# """
# model = SocialAccount
# template_name = 'accounts/social_account_list.html'
# context_object_name = 'social_accounts'
# paginate_by = 20
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return SocialAccount.objects.none()
#
# queryset = SocialAccount.objects.filter(user__tenant=tenant)
#
# # Apply filters
# user_id = self.request.GET.get('user_id')
# if user_id:
# queryset = queryset.filter(user_id=user_id)
#
# provider = self.request.GET.get('provider')
# if provider:
# queryset = queryset.filter(provider=provider)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'inactive':
# queryset = queryset.filter(is_active=False)
#
# return queryset.order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
#
# if tenant:
# context.update({
# 'providers': SocialAccount.objects.filter(
# user__tenant=tenant
# ).values_list('provider', flat=True).distinct(),
# 'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
# })
#
# return context
#
#
# class SocialAccountDetailView(LoginRequiredMixin, DetailView):
# """
# Display social account details.
# """
# model = SocialAccount
# template_name = 'accounts/social_account_detail.html'
# context_object_name = 'social_account'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return SocialAccount.objects.none()
# return SocialAccount.objects.filter(user__tenant=tenant)
#
#
# class SocialAccountCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create new social account.
# """
# model = SocialAccount
# form_class = SocialAccountForm
# template_name = 'accounts/social_account_form.html'
# permission_required = 'accounts.add_socialaccount'
# success_url = reverse_lazy('accounts:social_account_list')
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log social account creation
# AuditLogger.log_event(
# tenant=self.request.user.tenant,
# event_type='CREATE',
# event_category='INTEGRATION',
# action='Create Social Account',
# description=f'Created social account: {self.object.provider}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Social account "{self.object.provider}" created successfully.')
# return response
#
#
# class SocialAccountUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update social account.
# """
# model = SocialAccount
# form_class = SocialAccountForm
# template_name = 'accounts/social_account_form.html'
# permission_required = 'accounts.change_socialaccount'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return SocialAccount.objects.none()
# return SocialAccount.objects.filter(user__tenant=tenant)
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_success_url(self):
# return reverse('accounts:social_account_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log social account update
# AuditLogger.log_event(
# tenant=self.request.user.tenant,
# event_type='UPDATE',
# event_category='INTEGRATION',
# action='Update Social Account',
# description=f'Updated social account: {self.object.provider}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Social account "{self.object.provider}" updated successfully.')
# return response
#
#
# class SocialAccountDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete social account.
# """
# model = SocialAccount
# template_name = 'accounts/social_account_confirm_delete.html'
# permission_required = 'accounts.delete_socialaccount'
# success_url = reverse_lazy('accounts:social_account_list')
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return SocialAccount.objects.none()
# return SocialAccount.objects.filter(user__tenant=tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
# provider = self.object.provider
#
# # Log social account deletion
# AuditLogger.log_event(
# tenant=getattr(request, 'tenant', None),
# event_type='DELETE',
# event_category='INTEGRATION',
# action='Delete Social Account',
# description=f'Deleted social account: {provider}',
# user=request.user,
# content_object=self.object,
# request=request
# )
#
# messages.success(request, f'Social account "{provider}" deleted successfully.')
# return super().delete(request, *args, **kwargs)
#
#
# # ============================================================================
# # USER SESSION VIEWS (READ-ONLY - System Generated)
# # ============================================================================
#
# class UserSessionListView(LoginRequiredMixin, ListView):
# """
# List user sessions.
# """
# model = UserSession
# template_name = 'accounts/user_session_list.html'
# context_object_name = 'sessions'
# paginate_by = 50
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return UserSession.objects.none()
#
# queryset = UserSession.objects.filter(user__tenant=tenant)
#
# # Apply filters
# user_id = self.request.GET.get('user_id')
# if user_id:
# queryset = queryset.filter(user_id=user_id)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'expired':
# queryset = queryset.filter(expires_at__lt=timezone.now())
#
# device_type = self.request.GET.get('device_type')
# if device_type:
# queryset = queryset.filter(device_type=device_type)
#
# date_from = self.request.GET.get('date_from')
# if date_from:
# queryset = queryset.filter(created_at__gte=date_from)
#
# date_to = self.request.GET.get('date_to')
# if date_to:
# queryset = queryset.filter(created_at__lte=date_to)
#
# return queryset.order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
#
# if tenant:
# context.update({
# 'device_types': UserSession.objects.filter(
# user__tenant=tenant
# ).values_list('device_type', flat=True).distinct(),
# 'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
# })
#
# return context
#
#
# class UserSessionDetailView(LoginRequiredMixin, DetailView):
# """
# Display user session details.
# """
# model = UserSession
# template_name = 'accounts/user_session_detail.html'
# context_object_name = 'session'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return UserSession.objects.none()
# return UserSession.objects.filter(user__tenant=tenant)
#
#
# # ============================================================================
# # PASSWORD HISTORY VIEWS (READ-ONLY - System Generated)
# # ============================================================================
#
# class PasswordHistoryListView(LoginRequiredMixin, ListView):
# """
# List password history.
# """
# model = PasswordHistory
# template_name = 'accounts/password_history_list.html'
# context_object_name = 'password_history'
# paginate_by = 50
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return PasswordHistory.objects.none()
#
# queryset = PasswordHistory.objects.filter(user__tenant=tenant)
#
# # Apply filters
# user_id = self.request.GET.get('user_id')
# if user_id:
# queryset = queryset.filter(user_id=user_id)
#
# date_from = self.request.GET.get('date_from')
# if date_from:
# queryset = queryset.filter(created_at__gte=date_from)
#
# date_to = self.request.GET.get('date_to')
# if date_to:
# queryset = queryset.filter(created_at__lte=date_to)
#
# return queryset.order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
#
# if tenant:
# context.update({
# 'users': User.objects.filter(tenant=tenant, is_active=True).order_by('last_name', 'first_name'),
# })
#
# return context
#
#
# class PasswordHistoryDetailView(LoginRequiredMixin, DetailView):
# """
# Display password history details.
# """
# model = PasswordHistory
# template_name = 'accounts/password_history_detail.html'
# context_object_name = 'password_history'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return PasswordHistory.objects.none()
# return PasswordHistory.objects.filter(user__tenant=tenant)
#
#
# # ============================================================================
# # PROFILE AND SESSION MANAGEMENT VIEWS
# # ============================================================================
#
# class UserProfileView(LoginRequiredMixin, TemplateView):
# """
# User profile management view.
# """
# template_name = 'accounts/user_profile.html'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# user = self.request.user
#
# # Get user's sessions
# context['active_sessions'] = UserSession.objects.filter(
# user=user,
# is_active=True
# ).order_by('-created_at')
#
# # Get user's two-factor devices
# context['two_factor_devices'] = TwoFactorDevice.objects.filter(
# user=user,
# is_active=True
# ).order_by('-created_at')
#
# # Get user's social accounts
# context['social_accounts'] = SocialAccount.objects.filter(
# user=user,
# is_active=True
# ).order_by('-created_at')
#
# # Get password history
# context['password_history'] = PasswordHistory.objects.filter(
# user=user
# ).order_by('-created_at')[:5]
#
# return context
#
#
# class SessionManagementView(LoginRequiredMixin, ListView):
# """
# Session management view.
# """
# model = UserSession
# template_name = 'accounts/session_management.html'
# context_object_name = 'sessions'
# paginate_by = 50
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return UserSession.objects.none()
#
# queryset = UserSession.objects.filter(user__tenant=tenant)
#
# # Apply filters
# user_id = self.request.GET.get('user_id')
# if user_id:
# queryset = queryset.filter(user_id=user_id)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'expired':
# queryset = queryset.filter(expires_at__lt=timezone.now())
#
# device_type = self.request.GET.get('device_type')
# if device_type:
# queryset = queryset.filter(device_type=device_type)
#
# return queryset.order_by('-created_at')
#
#
# # ============================================================================
# # HTMX VIEWS FOR REAL-TIME UPDATES
# # ============================================================================
#
# @login_required
# def user_search(request):
# """
# HTMX view for user search.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# return JsonResponse({'error': 'No tenant found'}, status=400)
#
# search_query = request.GET.get('search', '')
# queryset = User.objects.filter(tenant=tenant)
#
# if search_query:
# queryset = queryset.filter(
# Q(username__icontains=search_query) |
# Q(email__icontains=search_query) |
# Q(first_name__icontains=search_query) |
# Q(last_name__icontains=search_query) |
# Q(employee_id__icontains=search_query)
# )
#
# users = queryset.order_by('last_name', 'first_name')[:20]
#
# return render(request, 'accounts/partials/user_list.html', {
# 'users': users
# })
#
#
# @login_required
# def user_stats(request):
# """
# HTMX view for user statistics.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# return JsonResponse({'error': 'No tenant found'}, status=400)
#
# # Calculate user statistics
# total_users = User.objects.filter(tenant=tenant).count()
# active_users = User.objects.filter(tenant=tenant, is_active=True).count()
# pending_approval = User.objects.filter(tenant=tenant, is_approved=False).count()
#
# # Active sessions in last 24 hours
# yesterday = timezone.now() - timedelta(days=1)
# active_sessions = UserSession.objects.filter(
# user__tenant=tenant,
# last_activity_at__gte=yesterday,
# is_active=True
# ).count()
#
# # Users by role
# role_stats = User.objects.filter(tenant=tenant).values('role').annotate(
# count=Count('id')
# ).order_by('-count')[:5]
#
# # Two-factor adoption
# two_factor_users = User.objects.filter(
# tenant=tenant,
# twofactordevice__is_active=True
# ).distinct().count()
#
# stats = {
# 'total_users': total_users,
# 'active_users': active_users,
# 'pending_approval': pending_approval,
# 'active_sessions': active_sessions,
# 'two_factor_users': two_factor_users,
# 'role_stats': role_stats,
# }
#
# return render(request, 'accounts/partials/user_stats.html', {'stats': stats})
#
#
# @login_required
# def session_list(request):
# """
# HTMX view for session list.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# return JsonResponse({'error': 'No tenant found'}, status=400)
#
# user_id = request.GET.get('user_id')
# if user_id:
# sessions = UserSession.objects.filter(
# user_id=user_id,
# user__tenant=tenant
# ).order_by('-created_at')[:10]
# else:
# sessions = UserSession.objects.filter(
# user__tenant=tenant,
# is_active=True
# ).order_by('-created_at')[:20]
#
# return render(request, 'accounts/partials/session_list.html', {
# 'sessions': sessions
# })
#
#
# @login_required
# def two_factor_setup(request):
# """
# HTMX view for two-factor authentication setup.
# """
# user = request.user
#
# if request.method == 'POST':
# device_type = request.POST.get('device_type')
# device_name = request.POST.get('device_name')
#
# if device_type and device_name:
# # Create new two-factor device
# device = TwoFactorDevice.objects.create(
# user=user,
# name=device_name,
# device_type=device_type,
# phone_number=request.POST.get('phone_number'),
# email_address=request.POST.get('email_address'),
# )
#
# # Generate secret key for TOTP devices
# if device_type == 'TOTP':
# import secrets
# device.secret_key = secrets.token_urlsafe(32)
# device.save()
#
# # Log the setup
# AuditLogger.log_event(
# tenant=getattr(request, 'tenant', None),
# event_type='CREATE',
# event_category='SECURITY',
# action='Setup Two-Factor Device',
# description=f'User setup two-factor device: {device_name}',
# user=request.user,
# content_object=device,
# request=request
# )
#
# return JsonResponse({'status': 'created', 'device_id': str(device.device_id)})
#
# return render(request, 'accounts/partials/two_factor_setup.html')
#
#
# # ============================================================================
# # ACTION VIEWS FOR WORKFLOW OPERATIONS
# # ============================================================================
#
# @login_required
# def end_session(request, session_id):
# """
# End a user session.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# return JsonResponse({'error': 'No tenant found'}, status=400)
#
# session = get_object_or_404(
# UserSession,
# session_id=session_id,
# user__tenant=tenant
# )
#
# # End the session
# session.end_session()
#
# # Log the action
# AuditLogger.log_event(
# tenant=tenant,
# event_type='UPDATE',
# event_category='AUTHENTICATION',
# action='End User Session',
# description=f'Ended session for user: {session.user.username}',
# user=request.user,
# content_object=session,
# additional_data={
# 'target_user': session.user.username,
# 'session_ip': session.ip_address,
# },
# request=request
# )
#
# messages.success(request, f'Session for {session.user.username} ended successfully.')
# return redirect('accounts:session_management')
#
#
# @login_required
# def user_profile_update(request):
# """
# HTMX view for user profile update.
# """
# if request.method == 'POST':
# user = request.user
#
# # Update basic information
# user.first_name = request.POST.get('first_name', user.first_name)
# user.last_name = request.POST.get('last_name', user.last_name)
# user.email = request.POST.get('email', user.email)
# user.phone_number = request.POST.get('phone_number', user.phone_number)
# user.mobile_number = request.POST.get('mobile_number', user.mobile_number)
# user.bio = request.POST.get('bio', user.bio)
#
# # Update preferences
# user.timezone = request.POST.get('timezone', user.timezone)
# user.language = request.POST.get('language', user.language)
# user.theme = request.POST.get('theme', user.theme)
#
# user.save()
#
# # Log the update
# AuditLogger.log_event(
# tenant=getattr(request, 'tenant', None),
# event_type='UPDATE',
# event_category='DATA_MODIFICATION',
# action='Update User Profile',
# description=f'User updated their profile: {user.username}',
# user=request.user,
# content_object=user,
# request=request
# )
#
# messages.success(request, 'Profile updated successfully.')
# return JsonResponse({'status': 'success'})
#
# return JsonResponse({'error': 'Invalid request'}, status=400)
#
#
# @login_required
# def remove_two_factor_device(request, device_id):
# """
# Remove a two-factor device.
# """
# device = get_object_or_404(
# TwoFactorDevice,
# device_id=device_id,
# user=request.user
# )
#
# device_name = device.name
# device.delete()
#
# # Log the removal
# AuditLogger.log_event(
# tenant=getattr(request, 'tenant', None),
# event_type='DELETE',
# event_category='SECURITY',
# action='Remove Two-Factor Device',
# description=f'User removed two-factor device: {device_name}',
# user=request.user,
# additional_data={'device_name': device_name},
# request=request
# )
#
# messages.success(request, f'Two-factor device "{device_name}" removed successfully.')
# return redirect('accounts:user_profile')
#
#
# @login_required
# def user_activity_log(request, user_id):
# """
# HTMX view for user activity log.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# return JsonResponse({'error': 'No tenant found'}, status=400)
#
# user_profile = get_object_or_404(User, id=user_id, tenant=tenant)
#
# # Get recent audit logs for this user
# from core.models import AuditLogEntry
# audit_logs = AuditLogEntry.objects.filter(
# tenant=tenant,
# user=user_profile
# ).order_by('-timestamp')[:20]
#
# return render(request, 'accounts/partials/user_activity_log.html', {
# 'audit_logs': audit_logs,
# 'user_profile': user_profile
# })
#
#
# @login_required
# def approve_user(request, pk):
# """
# Approve a user account.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# messages.error(request, 'No tenant found.')
# return redirect('accounts:user_list')
#
# user = get_object_or_404(User, pk=pk, tenant=tenant)
#
# user.is_approved = True
# user.save()
#
# # Log approval
# AuditLogger.log_event(
# tenant=tenant,
# event_type='UPDATE',
# event_category='USER_MANAGEMENT',
# action='Approve User',
# description=f'Approved user: {user.username}',
# user=request.user,
# content_object=user,
# request=request
# )
#
# messages.success(request, f'User "{user.username}" approved successfully.')
# return redirect('accounts:user_detail', pk=pk)
#
#
# @login_required
# def activate_user(request, pk):
# """
# Activate a user account.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# messages.error(request, 'No tenant found.')
# return redirect('accounts:user_list')
#
# user = get_object_or_404(User, pk=pk, tenant=tenant)
#
# user.is_active = True
# user.save()
#
# # Log activation
# AuditLogger.log_event(
# tenant=tenant,
# event_type='UPDATE',
# event_category='USER_MANAGEMENT',
# action='Activate User',
# description=f'Activated user: {user.username}',
# user=request.user,
# content_object=user,
# request=request
# )
#
# messages.success(request, f'User "{user.username}" activated successfully.')
# return redirect('accounts:user_detail', pk=pk)
#
#
# @login_required
# def reset_user_password(request, pk):
# """
# Reset user password.
# """
# tenant = getattr(request, 'tenant', None)
# if not tenant:
# messages.error(request, 'No tenant found.')
# return redirect('accounts:user_list')
#
# user = get_object_or_404(User, pk=pk, tenant=tenant)
#
# # Generate temporary password
# import secrets
# import string
# temp_password = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(12))
#
# # Set password and force change on next login
# user.set_password(temp_password)
# user.password_change_required = True
# user.save()
#
# # Log password reset
# AuditLogger.log_event(
# tenant=tenant,
# event_type='UPDATE',
# event_category='SECURITY',
# action='Reset User Password',
# description=f'Reset password for user: {user.username}',
# user=request.user,
# content_object=user,
# request=request
# )
#
# messages.success(request, f'Password reset for "{user.username}". Temporary password: {temp_password}')
# return redirect('accounts:user_detail', pk=pk)
#
#
#
#
#
# from django.shortcuts import render, redirect, get_object_or_404
# from django.contrib.auth import login, logout, authenticate
# from django.contrib.auth.decorators import login_required, permission_required
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.contrib import messages
# from django.views.generic import (
# CreateView, UpdateView, DeleteView, DetailView, ListView, FormView
# )
# from django.urls import reverse_lazy, reverse
# from django.http import JsonResponse, HttpResponse
# from django.utils import timezone
# from django.db import transaction, models
# from django.core.mail import send_mail
# from django.conf import settings
# from django.contrib.auth.models import Group
# from viewflow.workflow.flow.views import CreateProcessView, UpdateProcessView
#
# from .models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory
# from .forms import (
# UserRegistrationForm, AccountActivationForm, TwoFactorSetupForm,
# PermissionManagementForm, SecurityAuditForm, SessionManagementForm,
# ComplianceCheckForm, AccountDeactivationForm, PasswordResetForm,
# PasswordChangeForm
# )
# from .flows import UserOnboardingFlow, SecurityManagementFlow, AccountDeactivationFlow
#
#
# class UserRegistrationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView):
# """
# View for user registration in onboarding workflow
# """
# model = User
# form_class = UserRegistrationForm
# template_name = 'accounts/user_registration.html'
# permission_required = 'accounts.can_register_users'
# flow_class = UserOnboardingFlow
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['tenant'] = self.request.user.tenant
# return kwargs
#
# def form_valid(self, form):
# with transaction.atomic():
# # Create user
# user = form.save(commit=False)
# user.tenant = self.request.user.tenant
# user.is_active = False # Will be activated in workflow
# user.created_by = self.request.user
# user.save()
#
# # Start onboarding workflow
# process = self.flow_class.start.run(
# user=user,
# created_by=self.request.user
# )
#
# messages.success(
# self.request,
# f'User registration initiated for {user.get_full_name()}. '
# f'Onboarding workflow started.'
# )
#
# return redirect('accounts:user_detail', pk=user.pk)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Register New User'
# context['breadcrumbs'] = [
# {'name': 'Home', 'url': reverse('core:dashboard')},
# {'name': 'Users', 'url': reverse('accounts:user_list')},
# {'name': 'Register User', 'url': ''}
# ]
# return context
#
#
# class AccountActivationView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for account activation in onboarding workflow
# """
# form_class = AccountActivationForm
# template_name = 'accounts/account_activation.html'
# permission_required = 'accounts.can_activate_accounts'
#
# def get_success_url(self):
# return reverse('accounts:user_detail', kwargs={'pk': self.kwargs['pk']})
#
# def form_valid(self, form):
# user = get_object_or_404(User, pk=self.kwargs['pk'])
# activation_code = form.cleaned_data['activation_code']
#
# # Verify activation code (implement your verification logic)
# if self.verify_activation_code(user, activation_code):
# user.is_active = True
# user.email_verified = True
# user.activated_at = timezone.now()
# user.save()
#
# # Send welcome email
# self.send_welcome_email(user)
#
# messages.success(
# self.request,
# f'Account activated successfully for {user.get_full_name()}.'
# )
# else:
# messages.error(self.request, 'Invalid activation code.')
# return self.form_invalid(form)
#
# return super().form_valid(form)
#
# def verify_activation_code(self, user, code):
# """Verify activation code (implement your logic)"""
# # This would implement actual verification logic
# return True
#
# def send_welcome_email(self, user):
# """Send welcome email to activated user"""
# if user.email:
# send_mail(
# subject='Welcome to Hospital Management System',
# message=f'Welcome {user.get_full_name()}! Your account has been activated.',
# from_email=settings.DEFAULT_FROM_EMAIL,
# recipient_list=[user.email],
# fail_silently=True
# )
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['user'] = get_object_or_404(User, pk=self.kwargs['pk'])
# context['title'] = 'Activate Account'
# return context
#
#
# class TwoFactorSetupView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# View for two-factor authentication setup
# """
# model = TwoFactorDevice
# form_class = TwoFactorSetupForm
# template_name = 'accounts/two_factor_setup.html'
# permission_required = 'accounts.can_setup_two_factor'
#
# def get_success_url(self):
# return reverse('accounts:security_settings')
#
# def form_valid(self, form):
# device = form.save(commit=False)
# device.user = self.request.user
# device.is_active = True
# device.created_at = timezone.now()
#
# # Generate device-specific configuration
# device.configuration = self.generate_device_config(device.device_type)
# device.save()
#
# messages.success(
# self.request,
# 'Two-factor authentication has been set up successfully.'
# )
#
# return super().form_valid(form)
#
# def generate_device_config(self, device_type):
# """Generate device-specific configuration"""
# if device_type == 'totp':
# # Generate TOTP secret
# import pyotp
# return {'secret': pyotp.random_base32()}
# elif device_type == 'backup_codes':
# # Generate backup codes
# import secrets
# codes = [secrets.token_hex(4) for _ in range(10)]
# return {'codes': codes}
# return {}
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Setup Two-Factor Authentication'
# return context
#
#
# class PermissionManagementView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for managing user permissions
# """
# form_class = PermissionManagementForm
# template_name = 'accounts/permission_management.html'
# permission_required = 'accounts.can_manage_permissions'
#
# def get_success_url(self):
# return reverse('accounts:user_detail', kwargs={'pk': self.kwargs['pk']})
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['tenant'] = self.request.user.tenant
# return kwargs
#
# def get_initial(self):
# user = get_object_or_404(User, pk=self.kwargs['pk'])
# return {
# 'groups': user.groups.all(),
# 'is_staff': user.is_staff,
# 'is_superuser': user.is_superuser,
# 'access_level': getattr(user, 'access_level', 'basic'),
# 'department_access': getattr(user, 'department_access', [])
# }
#
# def form_valid(self, form):
# user = get_object_or_404(User, pk=self.kwargs['pk'])
#
# with transaction.atomic():
# # Update user permissions
# user.groups.set(form.cleaned_data['groups'])
# user.is_staff = form.cleaned_data['is_staff']
# user.is_superuser = form.cleaned_data['is_superuser']
# user.access_level = form.cleaned_data['access_level']
# user.save()
#
# # Log permission changes
# self.log_permission_changes(user, form.cleaned_data)
#
# messages.success(
# self.request,
# f'Permissions updated successfully for {user.get_full_name()}.'
# )
#
# return super().form_valid(form)
#
# def log_permission_changes(self, user, changes):
# """Log permission changes for audit"""
# from core.models import AuditLogEntry
# AuditLogEntry.objects.create(
# tenant=user.tenant,
# user=self.request.user,
# event_type='PERMISSION_CHANGE',
# action='UPDATE',
# object_type='User',
# object_id=str(user.id),
# details=changes,
# ip_address=self.request.META.get('REMOTE_ADDR'),
# user_agent=self.request.META.get('HTTP_USER_AGENT', '')
# )
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['user'] = get_object_or_404(User, pk=self.kwargs['pk'])
# context['title'] = 'Manage Permissions'
# return context
#
#
# class SecurityAuditView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for security audit configuration
# """
# form_class = SecurityAuditForm
# template_name = 'accounts/security_audit.html'
# permission_required = 'accounts.can_audit_security'
#
# def get_success_url(self):
# return reverse('accounts:security_dashboard')
#
# def form_valid(self, form):
# audit_config = form.cleaned_data
#
# # Start security audit workflow
# process = SecurityManagementFlow.start.run(
# user=self.request.user,
# audit_config=audit_config,
# created_by=self.request.user
# )
#
# messages.success(
# self.request,
# 'Security audit has been initiated. You will receive a notification when complete.'
# )
#
# return super().form_valid(form)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Security Audit'
# context['recent_audits'] = self.get_recent_audits()
# return context
#
# def get_recent_audits(self):
# """Get recent security audits"""
# # This would return recent audit records
# return []
#
#
# class SessionManagementView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for session management configuration
# """
# form_class = SessionManagementForm
# template_name = 'accounts/session_management.html'
# permission_required = 'accounts.can_manage_sessions'
#
# def get_success_url(self):
# return reverse('accounts:security_settings')
#
# def get_initial(self):
# # Get current session settings
# return {
# 'session_timeout': getattr(settings, 'SESSION_COOKIE_AGE', 1800) // 60,
# 'max_concurrent_sessions': 3,
# 'require_secure_cookies': getattr(settings, 'SESSION_COOKIE_SECURE', True),
# 'enable_session_monitoring': True,
# 'log_session_events': True,
# 'auto_logout_inactive': True
# }
#
# def form_valid(self, form):
# config = form.cleaned_data
#
# # Update session configuration
# self.update_session_config(config)
#
# messages.success(
# self.request,
# 'Session management settings updated successfully.'
# )
#
# return super().form_valid(form)
#
# def update_session_config(self, config):
# """Update session configuration"""
# # This would update session configuration
# pass
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Session Management'
# context['active_sessions'] = self.get_active_sessions()
# return context
#
# def get_active_sessions(self):
# """Get active user sessions"""
# return UserSession.objects.filter(
# user=self.request.user,
# is_active=True
# ).order_by('-created_at')
#
#
# class ComplianceCheckView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for compliance verification
# """
# form_class = ComplianceCheckForm
# template_name = 'accounts/compliance_check.html'
# permission_required = 'accounts.can_verify_compliance'
#
# def get_success_url(self):
# return reverse('accounts:compliance_dashboard')
#
# def form_valid(self, form):
# compliance_config = form.cleaned_data
#
# # Start compliance check
# self.start_compliance_check(compliance_config)
#
# messages.success(
# self.request,
# 'Compliance check has been initiated. Results will be available shortly.'
# )
#
# return super().form_valid(form)
#
# def start_compliance_check(self, config):
# """Start compliance verification process"""
# # This would start compliance checking
# pass
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Compliance Check'
# context['compliance_status'] = self.get_compliance_status()
# return context
#
# def get_compliance_status(self):
# """Get current compliance status"""
# return {
# 'hipaa': 'compliant',
# 'gdpr': 'compliant',
# 'sox': 'pending',
# 'pci_dss': 'non_compliant',
# 'iso27001': 'compliant'
# }
#
#
# class AccountDeactivationView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for account deactivation
# """
# form_class = AccountDeactivationForm
# template_name = 'accounts/account_deactivation.html'
# permission_required = 'accounts.can_deactivate_accounts'
#
# def get_success_url(self):
# return reverse('accounts:user_list')
#
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs['tenant'] = self.request.user.tenant
# return kwargs
#
# def form_valid(self, form):
# user = get_object_or_404(User, pk=self.kwargs['pk'])
# deactivation_config = form.cleaned_data
#
# # Start account deactivation workflow
# process = AccountDeactivationFlow.start.run(
# user=user,
# deactivation_config=deactivation_config,
# created_by=self.request.user
# )
#
# messages.success(
# self.request,
# f'Account deactivation initiated for {user.get_full_name()}.'
# )
#
# return super().form_valid(form)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['user'] = get_object_or_404(User, pk=self.kwargs['pk'])
# context['title'] = 'Deactivate Account'
# return context
#
#
# class UserListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# View for listing users
# """
# model = User
# template_name = 'accounts/user_list.html'
# context_object_name = 'users'
# permission_required = 'accounts.view_user'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = User.objects.filter(tenant=self.request.user.tenant)
#
# # Apply filters
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# models.Q(first_name__icontains=search) |
# models.Q(last_name__icontains=search) |
# models.Q(email__icontains=search) |
# models.Q(username__icontains=search)
# )
#
# department = self.request.GET.get('department')
# if department:
# queryset = queryset.filter(department_id=department)
#
# status = self.request.GET.get('status')
# if status == 'active':
# queryset = queryset.filter(is_active=True)
# elif status == 'inactive':
# queryset = queryset.filter(is_active=False)
#
# return queryset.order_by('last_name', 'first_name')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Users'
# context['departments'] = self.get_departments()
# context['search'] = self.request.GET.get('search', '')
# context['selected_department'] = self.request.GET.get('department', '')
# context['selected_status'] = self.request.GET.get('status', '')
# return context
#
# def get_departments(self):
# """Get departments for filter"""
# from core.models import Department
# return Department.objects.filter(tenant=self.request.user.tenant)
#
#
# class UserDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# View for user details
# """
# model = User
# template_name = 'accounts/user_detail.html'
# context_object_name = 'user'
# permission_required = 'accounts.view_user'
#
# def get_queryset(self):
# return User.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# user = self.object
# context['title'] = f'{user.get_full_name()}'
# context['two_factor_devices'] = user.two_factor_devices.filter(is_active=True)
# context['recent_sessions'] = user.user_sessions.order_by('-created_at')[:5]
# context['password_history'] = user.password_history.order_by('-created_at')[:5]
# return context
#
#
# class SecurityDashboardView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# View for security dashboard
# """
# template_name = 'accounts/security_dashboard.html'
# permission_required = 'accounts.view_security_dashboard'
#
# def get_queryset(self):
# return None
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = 'Security Dashboard'
# context['security_metrics'] = self.get_security_metrics()
# context['recent_alerts'] = self.get_recent_security_alerts()
# context['compliance_status'] = self.get_compliance_status()
# return context
#
# def get_security_metrics(self):
# """Get security metrics"""
# tenant = self.request.user.tenant
# return {
# 'total_users': User.objects.filter(tenant=tenant).count(),
# 'active_users': User.objects.filter(tenant=tenant, is_active=True).count(),
# 'users_with_2fa': User.objects.filter(
# tenant=tenant,
# two_factor_devices__is_active=True
# ).distinct().count(),
# 'failed_logins_today': 0, # Would be calculated from audit logs
# 'password_expiring_soon': 0 # Would be calculated from password history
# }
#
# def get_recent_security_alerts(self):
# """Get recent security alerts"""
# # This would return recent security alerts
# return []
#
# def get_compliance_status(self):
# """Get compliance status"""
# return {
# 'hipaa': 'compliant',
# 'gdpr': 'compliant',
# 'sox': 'pending',
# 'pci_dss': 'non_compliant',
# 'iso27001': 'compliant'
# }
#
#
# # AJAX Views
# @login_required
# @permission_required('accounts.can_manage_sessions')
# def terminate_session_ajax(request, session_id):
# """AJAX view to terminate user session"""
# if request.method == 'POST':
# try:
# session = UserSession.objects.get(
# id=session_id,
# user__tenant=request.user.tenant
# )
# session.end_session()
#
# return JsonResponse({
# 'success': True,
# 'message': 'Session terminated successfully.'
# })
# except UserSession.DoesNotExist:
# return JsonResponse({
# 'success': False,
# 'message': 'Session not found.'
# })
#
# return JsonResponse({'success': False, 'message': 'Invalid request.'})
#
#
# @login_required
# @permission_required('accounts.can_reset_passwords')
# def reset_password_ajax(request, user_id):
# """AJAX view to reset user password"""
# if request.method == 'POST':
# try:
# user = User.objects.get(
# id=user_id,
# tenant=request.user.tenant
# )
#
# # Generate temporary password
# import secrets
# temp_password = secrets.token_urlsafe(12)
# user.set_password(temp_password)
# user.must_change_password = True
# user.save()
#
# # Send password reset email
# send_mail(
# subject='Password Reset',
# message=f'Your temporary password is: {temp_password}',
# from_email=settings.DEFAULT_FROM_EMAIL,
# recipient_list=[user.email],
# fail_silently=True
# )
#
# return JsonResponse({
# 'success': True,
# 'message': 'Password reset successfully. User will receive email with temporary password.'
# })
# except User.DoesNotExist:
# return JsonResponse({
# 'success': False,
# 'message': 'User not found.'
# })
#
# return JsonResponse({'success': False, 'message': 'Invalid request.'})
#
#
# @login_required
# def user_search_ajax(request):
# """AJAX view for user search"""
# query = request.GET.get('q', '')
# if len(query) < 2:
# return JsonResponse({'users': []})
#
# users = User.objects.filter(
# tenant=request.user.tenant,
# is_active=True
# ).filter(
# models.Q(first_name__icontains=query) |
# models.Q(last_name__icontains=query) |
# models.Q(email__icontains=query) |
# models.Q(username__icontains=query)
# )[:10]
#
# user_data = [
# {
# 'id': user.id,
# 'name': user.get_full_name(),
# 'email': user.email,
# 'department': user.department.name if user.department else ''
# }
# for user in users
# ]
#
# return JsonResponse({'users': user_data})
#