527 lines
18 KiB
Python
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)
|