From a3348e1199995c194d0f250d106d554eb8035182 Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 28 Nov 2025 20:25:16 +0300 Subject: [PATCH] update some urls --- recruitment/views.py | 164 ++++++++++++++++++++++++++++++------------- 1 file changed, 115 insertions(+), 49 deletions(-) diff --git a/recruitment/views.py b/recruitment/views.py index 01b6808..5f3ecca 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -1196,6 +1196,19 @@ def application_submit_form(request, template_slug): """Display the form as a step-by-step wizard""" if not request.user.is_authenticated: return redirect("application_signup",slug=template_slug) + job = get_object_or_404(JobPosting, form_template__slug=template_slug) + if request.user.user_type == "candidate": + person=request.user.person_profile + if job.has_already_applied_to_this_job(person): + messages.error( + request, + _( + "You have already applied to this job: Multiple applications are not allowed." + ), + ) + return redirect("job_application_detail", slug=job.slug) + + template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True) stage = template.stages.filter(name="Contact Information") @@ -4514,6 +4527,8 @@ def agency_assignment_detail_admin(request, slug): return render(request, "recruitment/agency_assignment_detail.html", context) + +#will check the changes application to appliaction in this function @agency_user_required def agency_portal_edit_application(request, candidate_id): """Edit a candidate for agency portal""" @@ -4870,6 +4885,14 @@ def message_mark_unread(request, message_id): @login_required def message_delete(request, message_id): """Delete a message""" + """ + Deletes a message using a POST request, primarily designed for HTMX. + Redirects to the message list on success (either via standard redirect + or HTMX's hx-redirect header). + """ + + # 1. Retrieve the message + # Use select_related to fetch linked objects efficiently for checks/logging message = get_object_or_404( Message.objects.select_related("sender", "recipient"), id=message_id ) @@ -4877,6 +4900,14 @@ def message_delete(request, message_id): # Check if user has permission to delete this message if message.sender != request.user and message.recipient != request.user: messages.error(request, "You don't have permission to delete this message.") + + # HTMX requests should handle redirection via client-side logic (hx-redirect) + if "HX-Request" in request.headers: + # Returning 403 or 400 is ideal, but 200 with an empty body is often accepted + # by HTMX and the message is shown on the next page/refresh. + return HttpResponse(status=403) + + # Standard navigation redirect return redirect("message_list") if request.method == "POST": @@ -5029,49 +5060,84 @@ def document_delete(request, document_id): """Delete a document""" document = get_object_or_404(Document, id=document_id) - # Check permission - document is now linked to Application or Person via Generic Foreign Key - if hasattr(document.content_object, "job"): - # Application document - if ( - document.content_object.job.assigned_to != request.user - and not request.user.is_superuser - ): - messages.error( - request, "You don't have permission to delete this document." - ) - return JsonResponse({"success": False, "error": "Permission denied"}) - job_slug = document.content_object.job.slug - redirect_url = "applicant_portal_dashboard" if request.user.user_type == "candidate" else "job_detail" - elif hasattr(document.content_object, "person"): - # Person document - if request.user.user_type == "candidate": - candidate = request.user.person_profile - if document.content_object != candidate: - messages.error( - request, "You can only delete your own documents." - ) - return JsonResponse({"success": False, "error": "Permission denied"}) - redirect_url = "applicant_portal_dashboard" - else: - # Handle other content object types - messages.error(request, "You don't have permission to delete this document.") - return JsonResponse({"success": False, "error": "Permission denied"}) + # Initialize variables for redirection outside of the complex logic + is_htmx = "HX-Request" in request.headers + # 1. Permission and Context Initialization + has_permission = False + + content_object = document.content_object + + # Case A: Document linked to an Application (via content_object) + if hasattr(content_object, "job"): + # Staff/Superuser checking against Application's Job assignment + if (content_object.job.assigned_to == request.user) or request.user.is_superuser: + has_permission = True + + # Candidate checking if the Application belongs to them + elif request.user.user_type == "candidate" and content_object.person.user == request.user: + has_permission = True + + # Determine redirect URL for non-HTMX requests (fallback) + if request.user.user_type == "candidate": + # Assuming you redirect to the candidate's main dashboard after deleting their app document + redirect_view_name = "applicant_portal_dashboard" + else: + # Assuming you redirect to the job detail page for staff + redirect_view_name = "job_detail" + redirect_args = [content_object.job.slug] # Pass the job slug + + # Case B: Document linked directly to a Person (e.g., profile document) + elif hasattr(content_object, "user"): + # Check if the document belongs to the requesting candidate + if request.user.user_type == "candidate" and content_object.user == request.user: + has_permission = True + redirect_view_name = "applicant_portal_dashboard" + # Check if the requesting user is staff/superuser (Staff can delete profile docs) + elif request.user.is_staff or request.user.is_superuser: + has_permission = True + # Staff should probably go to the person's profile detail, but defaulting to a safe spot. + redirect_view_name = "dashboard" + + # Case C: No clear content object linkage or unhandled type + else: + has_permission = request.user.is_superuser # Only superuser can delete unlinked docs + + + # 2. Enforce Permissions + if not has_permission: + messages.error(request, "Permission denied: You cannot delete this document.") + # Return a 403 response for HTMX/AJAX + return HttpResponse(status=403) + + + # 3. Handle POST Request (Deletion) if request.method == "POST": file_name = document.file.name if document.file else "Unknown" document.delete() messages.success(request, f'Document "{file_name}" deleted successfully!') - # Handle AJAX requests - if request.headers.get("X-Requested-With") == "XMLHttpRequest": - return JsonResponse( - {"success": True, "message": "Document deleted successfully!"} - ) + # --- HTMX / AJAX Response --- + if is_htmx or request.headers.get("X-Requested-With") == "XMLHttpRequest": + # For HTMX, return a 200 OK. The front-end is expected to use hx-swap='outerHTML' + # to remove the element, or hx-redirect to navigate. + return HttpResponse(status=200) + + # --- Standard Navigation Fallback --- else: - return redirect("application_detail", slug=job_slug) - - return JsonResponse({"success": False, "error": "Method not allowed"}) + try: + # Use the calculated redirect view name and arguments + if 'redirect_args' in locals(): + return redirect(redirect_view_name, *redirect_args) + else: + return redirect(redirect_view_name) + except NameError: + # If no specific redirect_view_name was set (e.g., Case C failure) + return redirect("dashboard") + # 4. Handle non-POST (e.g., GET) + # The delete view should not be accessed via GET. + return HttpResponse(status=405) # Method Not Allowed @login_required def document_download(request, document_id): @@ -5114,14 +5180,6 @@ def document_download(request, document_id): return JsonResponse({"success": False, "error": "File not found"}) - if document.file: - response = HttpResponse( - document.file.read(), content_type="application/octet-stream" - ) - response["Content-Disposition"] = f'attachment; filename="{document.file.name}"' - return response - - return JsonResponse({"success": False, "error": "File not found"}) @login_required @@ -5416,8 +5474,10 @@ def compose_application_email(request, job_slug): if request.method == 'POST': candidate_ids = request.POST.getlist('candidate_ids') - candidates=Application.objects.filter(id__in=candidate_ids) - form = CandidateEmailForm(job, candidates, request.POST) + print("candidate_ids from post:", candidate_ids) + + applications=Application.objects.filter(id__in=candidate_ids) + form = CandidateEmailForm(job, applications, request.POST) if form.is_valid(): print("form is valid ...") # Get email addresses @@ -5453,18 +5513,24 @@ def compose_application_email(request, job_slug): ) if email_result["success"]: - for candidate in candidates: - if hasattr(candidate, 'person') and candidate.person: + for application in applications: + if hasattr(application, 'person') and application.person: try: + print(request.user) + print(application.person.user) + print(subject) + print(message) + print(job) + Message.objects.create( sender=request.user, - recipient=candidate.person.user, + recipient=application.person.user, subject=subject, content=message, job=job, message_type='email', is_email_sent=True, - email_address=candidate.person.email if candidate.person.email else candidate.email + email_address=application.person.email if application.person.email else application.email ) except Exception as e: