""" References UI views - Server-rendered templates for Reference Section """ from django.contrib.auth.decorators import login_required from django.contrib import messages from django.core.paginator import Paginator from django.db.models import Q from django.http import JsonResponse from django.shortcuts import get_object_or_404, render, redirect from django.views.decorators.http import require_http_methods from apps.references.models import ReferenceFolder, ReferenceDocument from apps.references.forms import ReferenceFolderForm, ReferenceDocumentForm, ReferenceDocumentSearchForm @login_required def reference_dashboard(request): """ Reference dashboard - Main entry point for Reference Section. Shows: - Root folders - Recent documents - Quick search - Statistics """ # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return render(request, 'core/no_hospital_assigned.html') # Get root folders (no parent) folders = ReferenceFolder.objects.filter( hospital=hospital, parent=None, is_active=True, is_deleted=False ).order_by('order', 'name') # Filter by access folders = [f for f in folders if f.has_access(request.user)] # Get recent documents (last 10) recent_documents = ReferenceDocument.objects.filter( hospital=hospital, is_published=True, is_deleted=False ).select_related('folder').order_by('-created_at')[:10] # Filter by access recent_documents = [d for d in recent_documents if d.has_access(request.user)] # Statistics total_folders = ReferenceFolder.objects.filter( hospital=hospital, is_active=True, is_deleted=False ).count() total_documents = ReferenceDocument.objects.filter( hospital=hospital, is_published=True, is_deleted=False ).count() context = { 'folders': folders, 'recent_documents': recent_documents, 'total_folders': total_folders, 'total_documents': total_documents, } return render(request, 'references/dashboard.html', context) @login_required def folder_view(request, pk=None): """ Folder view - Browse folders and documents. If pk is provided, shows contents of that folder. Otherwise, shows root level folders. """ # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return render(request, 'core/no_hospital_assigned.html') current_folder = None breadcrumb = [] subfolders = [] documents = [] if pk: current_folder = get_object_or_404( ReferenceFolder, pk=pk, hospital=hospital, is_deleted=False ) # Check access if not current_folder.has_access(request.user): messages.error(request, "You don't have permission to access this folder.") return redirect('references:dashboard') # Build breadcrumb breadcrumb = [] folder = current_folder while folder: breadcrumb.insert(0, folder) folder = folder.parent # Get subfolders subfolders = current_folder.get_subfolders() subfolders = [f for f in subfolders if f.has_access(request.user)] # Get documents documents = current_folder.get_documents() documents = [d for d in documents if d.has_access(request.user)] else: # Root level - show root folders subfolders = ReferenceFolder.objects.filter( hospital=hospital, parent=None, is_active=True, is_deleted=False ).order_by('order', 'name') subfolders = [f for f in subfolders if f.has_access(request.user)] context = { 'current_folder': current_folder, 'breadcrumb': breadcrumb, 'subfolders': subfolders, 'documents': documents, } return render(request, 'references/folder_view.html', context) @login_required @require_http_methods(["GET", "POST"]) def folder_create(request, parent_pk=None): """Create a new folder""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: messages.error(request, "No hospital assigned.") return redirect('references:dashboard') parent = None if parent_pk: parent = get_object_or_404(ReferenceFolder, pk=parent_pk, hospital=hospital, is_deleted=False) if not parent.has_access(request.user): messages.error(request, "You don't have permission to access this folder.") return redirect('references:dashboard') if request.method == 'POST': form = ReferenceFolderForm(request.POST, hospital=hospital) if form.is_valid(): folder = form.save(commit=False) folder.hospital = hospital folder.parent = parent folder.save() form.save_m2m() messages.success(request, f"Folder '{folder.name}' created successfully.") if parent: return redirect('references:folder_view', pk=parent_pk) return redirect('references:dashboard') else: form = ReferenceFolderForm(hospital=hospital) if parent: form.fields['parent'].initial = parent # Get all folders for parent dropdown with level info all_folders = [] for f in ReferenceFolder.objects.filter(hospital=hospital, is_deleted=False): level = 0 temp = f while temp.parent: level += 1 temp = temp.parent # Create a display string with appropriate number of dashes f.level_display = '—' * level all_folders.append(f) context = { 'form': form, 'folder': None, 'parent': parent, 'all_folders': all_folders, } return render(request, 'references/folder_form.html', context) @login_required @require_http_methods(["GET", "POST"]) def folder_edit(request, pk): """Edit a folder""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: messages.error(request, "No hospital assigned.") return redirect('references:dashboard') folder = get_object_or_404(ReferenceFolder, pk=pk, hospital=hospital, is_deleted=False) # Check access if not folder.has_access(request.user): messages.error(request, "You don't have permission to edit this folder.") return redirect('references:dashboard') if request.method == 'POST': form = ReferenceFolderForm(request.POST, instance=folder, hospital=hospital) if form.is_valid(): form.save() messages.success(request, f"Folder '{folder.name}' updated successfully.") if folder.parent: return redirect('references:folder_view', pk=folder.parent.id) return redirect('references:dashboard') else: form = ReferenceFolderForm(instance=folder, hospital=hospital) # Get all folders for parent dropdown with level info all_folders = [] for f in ReferenceFolder.objects.filter(hospital=hospital, is_deleted=False): level = 0 temp = f while temp.parent: level += 1 temp = temp.parent # Create a display string with appropriate number of dashes f.level_display = '—' * level all_folders.append(f) context = { 'form': form, 'folder': folder, 'all_folders': all_folders, } return render(request, 'references/folder_form.html', context) @login_required @require_http_methods(["POST"]) def folder_delete(request, pk): """Soft delete a folder""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return JsonResponse({'success': False, 'error': 'No hospital assigned'}, status=400) folder = get_object_or_404(ReferenceFolder, pk=pk, hospital=hospital, is_deleted=False) # Check access if not folder.has_access(request.user): return JsonResponse({'success': False, 'error': 'Permission denied'}, status=403) # Soft delete folder.is_deleted = True folder.save() return JsonResponse({'success': True}) @login_required def document_view(request, pk): """Document detail view""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return render(request, 'core/no_hospital_assigned.html') document = get_object_or_404( ReferenceDocument.objects.select_related('folder', 'uploaded_by'), pk=pk, hospital=hospital, is_deleted=False ) # Check access if not document.has_access(request.user): messages.error(request, "You don't have permission to access this document.") return redirect('references:dashboard') # Get version history versions = document.get_version_history() # Get related documents (same folder) related_documents = [] if document.folder: related_documents = ReferenceDocument.objects.filter( folder=document.folder, is_published=True, is_deleted=False ).exclude(pk=document.pk)[:5] related_documents = [d for d in related_documents if d.has_access(request.user)] context = { 'document': document, 'versions': versions, 'related_documents': related_documents, } return render(request, 'references/document_view.html', context) @login_required @require_http_methods(["GET", "POST"]) def document_create(request, folder_pk=None): """Upload a new document""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: messages.error(request, "No hospital assigned.") return redirect('references:dashboard') folder = None if folder_pk: folder = get_object_or_404(ReferenceFolder, pk=folder_pk, hospital=hospital, is_deleted=False) if not folder.has_access(request.user): messages.error(request, "You don't have permission to access this folder.") return redirect('references:dashboard') if request.method == 'POST': form = ReferenceDocumentForm(request.POST, request.FILES, hospital=hospital, folder=folder) if form.is_valid(): document = form.save(commit=False) document.hospital = hospital # Use folder from form, fallback to URL parameter folder document.folder = form.cleaned_data.get('folder') or folder document.uploaded_by = request.user if 'file' in request.FILES: document.filename = request.FILES['file'].name document.save() form.save_m2m() messages.success(request, f"Document '{document.title}' uploaded successfully.") if document.folder: return redirect('references:folder_view', pk=document.folder.id) return redirect('references:dashboard') else: # Show error to user messages.error(request, "Please fix the errors below to upload the document.") else: form = ReferenceDocumentForm(hospital=hospital, folder=folder) # Get all folders for dropdown with level info all_folders = [] for f in ReferenceFolder.objects.filter(hospital=hospital, is_deleted=False): level = 0 temp = f while temp.parent: level += 1 temp = temp.parent # Create a display string with appropriate number of dashes f.level_display = '—' * level all_folders.append(f) context = { 'form': form, 'folder': folder, 'all_folders': all_folders, } return render(request, 'references/document_form.html', context) @login_required @require_http_methods(["GET", "POST"]) def document_edit(request, pk): """Edit a document""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: messages.error(request, "No hospital assigned.") return redirect('references:dashboard') document = get_object_or_404(ReferenceDocument, pk=pk, hospital=hospital, is_deleted=False) # Check access if not document.has_access(request.user): messages.error(request, "You don't have permission to edit this document.") return redirect('references:dashboard') if request.method == 'POST': form = ReferenceDocumentForm(request.POST, request.FILES, instance=document, hospital=hospital) if form.is_valid(): # Check if uploading as new version new_version = form.cleaned_data.get('new_version') file = request.FILES.get('file') if new_version and file: # Create new version old_document = document document.pk = None # Create new instance document.parent_document = old_document document.uploaded_by = request.user document.filename = file.name document.save() form.save_m2m() # Mark old version as not latest old_document.is_latest_version = False old_document.save() messages.success(request, f"New version '{document.title}' created successfully.") else: # Just update metadata if file: document.filename = file.name form.save() messages.success(request, f"Document '{document.title}' updated successfully.") return redirect('references:document_view', pk=document.id) else: form = ReferenceDocumentForm(instance=document, hospital=hospital) # Get all folders for dropdown with level info all_folders = [] for f in ReferenceFolder.objects.filter(hospital=hospital, is_deleted=False): level = 0 temp = f while temp.parent: level += 1 temp = temp.parent # Create a display string with appropriate number of dashes f.level_display = '—' * level all_folders.append(f) context = { 'form': form, 'document': document, 'all_folders': all_folders, } return render(request, 'references/document_form.html', context) @login_required @require_http_methods(["POST"]) def document_delete(request, pk): """Soft delete a document""" # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return JsonResponse({'success': False, 'error': 'No hospital assigned'}, status=400) document = get_object_or_404(ReferenceDocument, pk=pk, hospital=hospital, is_deleted=False) # Check access if not document.has_access(request.user): return JsonResponse({'success': False, 'error': 'Permission denied'}, status=403) # Soft delete document.is_deleted = True document.save() return JsonResponse({'success': True}) @login_required def search(request): """ Search documents across all folders. """ # Get current hospital - use tenant_hospital for PX admins, user.hospital for regular users hospital = getattr(request, 'tenant_hospital', None) or request.user.hospital if not hospital: return render(request, 'core/no_hospital_assigned.html') form = ReferenceDocumentSearchForm(request.GET or None, hospital=hospital) documents = [] if form.is_valid(): documents = ReferenceDocument.objects.filter( hospital=hospital, is_published=True, is_deleted=False ).select_related('folder') # Apply filters search = form.cleaned_data.get('search') if search: documents = documents.filter( Q(title__icontains=search) | Q(title_ar__icontains=search) | Q(description__icontains=search) | Q(description_ar__icontains=search) | Q(tags__icontains=search) ) folder = form.cleaned_data.get('folder') if folder: documents = documents.filter(folder=folder) file_type = form.cleaned_data.get('file_type') if file_type: documents = documents.filter(file_type__iexact=file_type) tags = form.cleaned_data.get('tags') if tags: tag_list = [tag.strip() for tag in tags.split(',')] for tag in tag_list: documents = documents.filter(tags__icontains=tag) # Filter by access documents = [d for d in documents if d.has_access(request.user)] # Pagination page_size = int(request.GET.get('page_size', 20)) paginator = Paginator(documents, page_size) page_number = request.GET.get('page', 1) page_obj = paginator.get_page(page_number) context = { 'form': form, 'page_obj': page_obj, 'documents': page_obj.object_list, } return render(request, 'references/search.html', context)