From 9eb2b90da6f4df31093a667eabf0b236f92a0d20 Mon Sep 17 00:00:00 2001 From: Faheed Date: Sun, 26 Oct 2025 23:19:31 +0300 Subject: [PATCH] user registeration done --- .../__pycache__/models.cpython-312.pyc | Bin 60689 -> 60814 bytes .../views_frontend.cpython-312.pyc | Bin 24309 -> 24589 bytes recruitment/models.py | 10 +++--- recruitment/views_frontend.py | 34 +++++++++++------- .../email/email_confirmation_message.txt | 18 ++++++++++ .../email/password_reset_key_message.txt | 27 ++++++++++++++ templates/account/login.html | 22 ++++++------ templates/recruitment/dashboard.html | 2 +- 8 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 templates/account/email/email_confirmation_message.txt create mode 100644 templates/account/email/password_reset_key_message.txt diff --git a/recruitment/__pycache__/models.cpython-312.pyc b/recruitment/__pycache__/models.cpython-312.pyc index c63aa4945965177ecce4c12aac7888627080198b..5f501401d576ea8ed98e2a7f8e990e91a6309a18 100644 GIT binary patch delta 4296 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 U5_KUW=)?_QkAV-Bwy!JT|JDV&4FCWD delta 4215 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 Y4$A!y*2Aw1K%Nz}Zm+bFw|$kr0WFIlr~m)} diff --git a/recruitment/models.py b/recruitment/models.py index 0e4f3cf..4d545ec 100644 --- a/recruitment/models.py +++ b/recruitment/models.py @@ -321,23 +321,23 @@ class JobPosting(Base): def all_candidates_count(self): return self.candidates.annotate( sortable_score=Cast('ai_analysis_data__match_score', output_field=CharField())).order_by( - '-sortable_score').count() + '-sortable_score').count() or 0 @property def screening_candidates_count(self): - return self.all_candidates.filter(stage="Applied").count() + return self.all_candidates.filter(stage="Applied").count() or 0 @property def exam_candidates_count(self): - return self.all_candidates.filter(stage="Exam").count() + return self.all_candidates.filter(stage="Exam").count() or 0 @property def interview_candidates_count(self): - return self.all_candidates.filter(stage="Interview").count() + return self.all_candidates.filter(stage="Interview").count() or 0 @property def offer_candidates_count(self): - return self.all_candidates.filter(stage="Offer").count() + return self.all_candidates.filter(stage="Offer").count() or 0 @property def vacancy_fill_rate(self): diff --git a/recruitment/views_frontend.py b/recruitment/views_frontend.py index 2055fde..4e97d0e 100644 --- a/recruitment/views_frontend.py +++ b/recruitment/views_frontend.py @@ -339,6 +339,8 @@ class TrainingDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView): @login_required def dashboard_view(request): + all_candidates_count=0 + # --- Performance Optimization: Aggregate Data in ONE Query --- # 1. Base Job Query: Get all jobs and annotate with candidate count @@ -393,27 +395,33 @@ def dashboard_view(request): sortable_score__gte=75 ).count() high_potential_ratio = round((high_potential_count / total_candidates) * 100, 1) if total_candidates > 0 else 0 - + jobs=models.JobPosting.objects.all().order_by('internal_job_id') selected_job_pk=request.GET.get('selected_job_pk','') candidate_stage=['APPLIED','EXAM','INTERVIEW','OFFER'] apply_count,exam_count,interview_count,offer_count=[0]*4 if selected_job_pk: - job=jobs.get(pk=selected_job_pk) - apply_count=job.screening_candidates_count - exam_count=job.exam_candidates_count - interview_count=job.interview_candidates_count - offer_count=job.offer_candidates_count - all_candidates_count=job.all_candidates_count + try: + job=jobs.get(pk=selected_job_pk) + apply_count=job.screening_candidates_count + exam_count=job.exam_candidates_count + interview_count=job.interview_candidates_count + offer_count=job.offer_candidates_count + all_candidates_count=job.all_candidates_count + except Exception as e: + print(e) else: #default job - job=jobs.first() - apply_count=job.screening_candidates_count - exam_count=job.exam_candidates_count - interview_count=job.interview_candidates_count - offer_count=job.offer_candidates_count - all_candidates_count=job.all_candidates_count + try: + job=jobs.first() + apply_count=job.screening_candidates_count + exam_count=job.exam_candidates_count + interview_count=job.interview_candidates_count + offer_count=job.offer_candidates_count + all_candidates_count=job.all_candidates_count + except Exception as e: + print(e) candidates_count=[ apply_count,exam_count,interview_count,offer_count ] context = { diff --git a/templates/account/email/email_confirmation_message.txt b/templates/account/email/email_confirmation_message.txt new file mode 100644 index 0000000..5dd0cb4 --- /dev/null +++ b/templates/account/email/email_confirmation_message.txt @@ -0,0 +1,18 @@ +{% load account i18n %} +{% autoescape off %} + +{% blocktrans %}Hello,{% endblocktrans %} + +{% blocktrans %}To verify the ownership of your email address, please click the confirmation link below:{% endblocktrans %} + + +{% trans "Confirm My KAAUH ATS Email" %} +{{ activate_url }} + + +{% blocktrans %}If you did not request this verification, you can safely ignore this email.{% endblocktrans %} + +{% blocktrans %}Alternatively, copy and paste this link into your browser:{% endblocktrans %} +{{ activate_url }} + +{% endautoescape %} \ No newline at end of file diff --git a/templates/account/email/password_reset_key_message.txt b/templates/account/email/password_reset_key_message.txt new file mode 100644 index 0000000..7930487 --- /dev/null +++ b/templates/account/email/password_reset_key_message.txt @@ -0,0 +1,27 @@ +{% load i18n %} +{% load static %} +{% autoescape off %} + +{% trans "Password Reset Request" %} + +{% trans "Hello," %} + +{% blocktrans %}You are receiving this email because you or someone else has requested a password reset for your account at{% endblocktrans %} {{ current_site.name }}. + +------------------------------------------------------ +{% trans "Click Here to Reset Your Password" %} +{{ password_reset_url }} +------------------------------------------------------ + +{% trans "This link is only valid for a limited time." %} + +{% trans "If you did not request a password reset, please ignore this email. Your password will remain unchanged." %} + +{% trans "Thank you," %} +{% trans "KAAUH ATS Team" %} + +--- +{% trans "If the button above does not work, copy and paste the following link into your browser:" %} +{{ password_reset_url }} + +{% endautoescape %} \ No newline at end of file diff --git a/templates/account/login.html b/templates/account/login.html index b7e66c7..5cf52e8 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -1,6 +1,8 @@ -{% load static %} +{% load static i18n %} +{% get_current_language_bidi as LANGUAGE_BIDI %} +{% get_current_language as LANGUAGE_CODE %} - + @@ -146,34 +148,34 @@
-

Sign In

+

{% trans "Sign In" %}

{% csrf_token %}
- - + +
- - + +
- +
diff --git a/templates/recruitment/dashboard.html b/templates/recruitment/dashboard.html index c297668..84d5bea 100644 --- a/templates/recruitment/dashboard.html +++ b/templates/recruitment/dashboard.html @@ -167,7 +167,7 @@

{% trans "High Potential" %}

{{ high_potential_count }}
-
{% trans "Candidates with Score ≥ 75 ({{ high_potential_ratio }}%)" %}
+
{% trans "Candidates with Score ≥ 75%" %} ({{ high_potential_ratio }})