HH/apps/references/ui_views.py

527 lines
18 KiB
Python

"""
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)