3124 lines
104 KiB
Python
3124 lines
104 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 .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)
|
|
# ============================================================================ession, 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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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=getattr(self.request, 'tenant', None),
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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=getattr(self.request, 'tenant', None),
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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=getattr(self.request, 'tenant', None),
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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=getattr(self.request, 'tenant', None),
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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 = getattr(self.request, 'tenant', None)
|
|
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':
|
|
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, '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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
#
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
#
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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=getattr(self.request, 'tenant', None),
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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=getattr(self.request, 'tenant', None),
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
#
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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=getattr(self.request, 'tenant', None),
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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=getattr(self.request, 'tenant', None),
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
#
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
#
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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 = getattr(self.request, 'tenant', None)
|
|
# 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})
|
|
#
|