from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required from django.views.decorators.http import require_http_methods from django.http import HttpRequest, HttpResponse, Http404 from django.template.loader import render_to_string from django.core.exceptions import PermissionDenied from .models import ChangeSet, CommentThread, Comment from .notifications import NotificationDispatcher from .state_machine import ApprovalStateMachine @login_required def get_comments(request: HttpRequest) -> HttpResponse: """HTMX endpoint to get comments for a specific anchor""" anchor = request.GET.get('anchor') if not anchor: raise Http404("Anchor parameter is required") thread = CommentThread.objects.filter(anchor__id=anchor).first() comments = thread.comments.all() if thread else [] return render(request, 'history_tracking/partials/comments_list.html', { 'comments': comments, 'anchor': anchor }) @login_required @require_http_methods(["POST"]) def preview_comment(request: HttpRequest) -> HttpResponse: """HTMX endpoint for live comment preview""" content = request.POST.get('content', '') return render(request, 'history_tracking/partials/comment_preview.html', { 'content': content }) @login_required @require_http_methods(["POST"]) def add_comment(request: HttpRequest) -> HttpResponse: """HTMX endpoint to add a comment""" anchor = request.POST.get('anchor') content = request.POST.get('content') parent_id = request.POST.get('parent_id') if not content: return HttpResponse("Comment content is required", status=400) thread, created = CommentThread.objects.get_or_create( anchor={'id': anchor}, defaults={'created_by': request.user} ) comment = thread.comments.create( author=request.user, content=content, parent_id=parent_id if parent_id else None ) comment.extract_mentions() # Send notifications dispatcher = NotificationDispatcher() dispatcher.notify_new_comment(comment, thread) # Return updated comments list return render(request, 'history_tracking/partials/comments_list.html', { 'comments': thread.comments.all(), 'anchor': anchor }) @login_required @require_http_methods(["POST"]) def approve_changes(request: HttpRequest, changeset_id: int) -> HttpResponse: """HTMX endpoint for approving/rejecting changes""" changeset = get_object_or_404(ChangeSet, pk=changeset_id) state_machine = ApprovalStateMachine(changeset) if not state_machine.can_user_approve(request.user): raise PermissionDenied("You don't have permission to approve these changes") decision = request.POST.get('decision', 'approve') comment = request.POST.get('comment', '') stage_id = request.POST.get('stage_id') success = state_machine.submit_approval( user=request.user, decision=decision, comment=comment, stage_id=stage_id ) if not success: return HttpResponse("Failed to submit approval", status=400) # Return updated approval status return render(request, 'history_tracking/partials/approval_status.html', { 'changeset': changeset, 'current_stage': state_machine.get_current_stage(), 'can_approve': state_machine.can_user_approve(request.user), 'pending_approvers': state_machine.get_pending_approvers() }) @login_required def approval_notifications(request: HttpRequest, changeset_id: int) -> HttpResponse: """HTMX endpoint for live approval notifications""" changeset = get_object_or_404(ChangeSet, pk=changeset_id) return render(request, 'history_tracking/partials/approval_notifications.html', { 'notifications': changeset.get_recent_notifications() }) @login_required def get_replies(request: HttpRequest, comment_id: int) -> HttpResponse: """HTMX endpoint to get comment replies""" comment = get_object_or_404(Comment, pk=comment_id) return render(request, 'history_tracking/partials/comment_replies.html', { 'replies': comment.replies.all() }) @login_required def reply_form(request: HttpRequest) -> HttpResponse: """HTMX endpoint to get the reply form template""" return render(request, 'history_tracking/partials/reply_form.html', { 'parent_id': request.GET.get('parent_id') })