From 916cbc4fcf725b09d805bf5677259f4ff4586faa Mon Sep 17 00:00:00 2001 From: ismail Date: Sun, 12 Oct 2025 13:30:16 +0300 Subject: [PATCH 1/2] more update and add qcluster --- .../__pycache__/settings.cpython-313.pyc | Bin 5232 -> 5654 bytes NorahUniversity/settings.py | 226 +----- recruitment/__pycache__/admin.cpython-313.pyc | Bin 11440 -> 11458 bytes .../__pycache__/models.cpython-313.pyc | Bin 44705 -> 45244 bytes .../__pycache__/signals.cpython-313.pyc | Bin 11075 -> 6443 bytes recruitment/__pycache__/urls.cpython-313.pyc | Bin 5754 -> 6220 bytes recruitment/__pycache__/utils.cpython-313.pyc | Bin 17282 -> 17282 bytes recruitment/__pycache__/views.cpython-313.pyc | Bin 36759 -> 43206 bytes .../views_frontend.cpython-313.pyc | Bin 19821 -> 19780 bytes recruitment/admin.py | 2 +- .../0004_candidate_applicant_status.py | 18 + recruitment/models.py | 13 +- recruitment/signals.py | 137 +--- recruitment/tasks.py | 155 ++++ .../__pycache__/form_filters.cpython-313.pyc | Bin 2515 -> 3046 bytes recruitment/templatetags/form_filters.py | 82 +- recruitment/urls.py | 9 +- recruitment/views.py | 163 +++- recruitment/views_frontend.py | 2 +- templates/forms/form_submission_details.html | 147 ++-- .../forms/form_template_all_submissions.html | 371 +++++++++ .../forms/form_template_submissions_list.html | 17 +- templates/forms/form_wizard.html | 21 +- templates/includes/candidate_modal_body.html | 21 + templates/jobs/job_detail.html | 55 +- .../candidate_tier_management.html | 724 ++++++++++++++++++ 26 files changed, 1719 insertions(+), 444 deletions(-) create mode 100644 recruitment/migrations/0004_candidate_applicant_status.py create mode 100644 recruitment/tasks.py create mode 100644 templates/forms/form_template_all_submissions.html create mode 100644 templates/includes/candidate_modal_body.html create mode 100644 templates/recruitment/candidate_tier_management.html diff --git a/NorahUniversity/__pycache__/settings.cpython-313.pyc b/NorahUniversity/__pycache__/settings.cpython-313.pyc index b6f4ada70ad7bcd970a163cc9981a567d5a0e7a9..48f3c69beda3231ee409a1985d04f28aa7fe401a 100644 GIT binary patch delta 588 zcmXv~zi-n(6n4&b9RJD>Hz^5Cr7oxhp@?)rf()cdADWftCr_uwXMQSUzec~A!M zA>CVL8Q<)IQrmw6KEz@L{}RUoi6pvDjA75#5Bw|fZ$LQ}D{I%w*XXK*-rvM&EbmRl z!}tm<|Dx$t;#sdHXZ`omh&>|eX05i{)a$KXxU;bxax}*L6JwaLO1?`dx zyht&=K#vkjxW4VUgd5q|C7`=!ewArzn$8%4^8mp$Eo6^f!eiv(2~jNLxo)^FvPP~G zMlzL-0A7zM8xa768`#4h;hjF^EXjl$8WtkLp^cv+><|H?&ZILyXDKAnv8@qCjzc8J zc!uDq%nhsHFtsT8Co{tSnRbNPcWMv|@ z=Tdl|GEjO)`=Vkn&Sy{2wuB`Oyi87S_#KT0kAE<^sl=$oAe9bMT9C>F>1?3of`!E( zn+w$Z&-7CCl1$A6Hn}iWn0ztF6@udOOyDw7gfB*bXEkZ2O1b!KxuAkqB7RHj{R8%@ BuC4$8 delta 149 zcmbQH^Fc%XGcPX}0}wbIex4C7&cN^(#DM`eDC2Y7M)i0mmUJdfhs}qWW-&5KY>s7N zW!jv>wx5Zoiqp`@T+aXq4KpX3bN*r!oovKa&M3Qi71vy5CQa+je*7z#Co>8Ma}@)P jV+7*jn8|U%0ql}OObvV=%rAj#G>NK;W9OB zOMnWCmTtZ&^PG`!>*RxS&lz`2UMcUuxNY()`D5H$L9#(0V%ua}DT&FK6~q|xHosEn zVPxDtxm+ofZ7)b}@8nBL^{gOf@(#>mcU!$u~7}7_U!u)BGX;b{g0ou+i5idub^%KHr?D<-`O4 Dyxd~@ delta 307 zcmX>UxgnDGGcPX}0}#w;d!Dg(Bd?+iBl~218Li3LGF5Dgf#O9=Houm6&d9a}$i5{v znNdM}@_V_{jN2#gmUm#>I{Aa7lQ4omOI{B=E9%J<8KMFmJjQb{cDuuG`0g3OK z{6wjq6~s)QC@4C)R(TKGF_8H2$@VIW0uUyMe*#3DoLr!CgzX53d1SJc>NLh9n=h*R zFtS|&iCmhjtX|4^Y4Sx?$;q44mvi3&3Elt^Hz%iPnCO9-w?TZ6OqHl(K|xMta$;VI zf@fY@eo<~>NoIbYCR5Q(kdix-_bbV>T>~+%O@6JB!+33Sgyt6ku#>^|gRQ(aIYvvF L@!94EEhi=bn@wij diff --git a/recruitment/__pycache__/models.cpython-313.pyc b/recruitment/__pycache__/models.cpython-313.pyc index 7de510d782a45d32a2b42e26ea8b9d65c33c7315..1236c5d99bd4bc5078e1e9a0d396dc65e516cfef 100644 GIT binary patch delta 4300 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 Z#^&S8LYpOs?ef2_px^6D@x$Y<{~Jn3V&VV* delta 3906 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 diff --git a/recruitment/__pycache__/signals.cpython-313.pyc b/recruitment/__pycache__/signals.cpython-313.pyc index 530e3d0bd289545b8e713b9a9b34ac4766373eb8..3a9c25cfbdb9f6604c5e7da686b8bec2893ae361 100644 GIT binary patch delta 1084 zcmaJ7fK6rNeH*ZX4|NbIC_DRE2)TBP~_iUd^~wN&blH?mr+Rv;oR!|t%z#@-EY z)>P#Z4pm!D6s;k}LBJtX!{|z!DJ#n$ zv$jRJS%y?u@D%r{1t;h6GA>d)y6L@Odyb>A>KxDgFLgwA6YZ_f2vn+ zSvReF6Q}Nc{D5Z!FVWzPp z9)unk>CdhDq>d&Vhftn0CdIfEwe)W5r|CMvtezLZ_4ySx?Bm2FEZ_n@Law&{-O+Q} z+3~C-i-}dw4F5|O1##QI45Paa?CYUeVTrc{vUpiFx4KvJ20}4?{lt+~O;Xw*_IY1` zObg_2fUGdcVatqwCkuJkbk~irDy|C$BrQ8J%IFsYlM;_I*WbazhJ8K{pP^08oVbKy zyFe*@LaLi&dXvm-l4F~s{STS%J|OeYjDwGi#(kr)cKU%ab3^-=8sFP%pKQ?C9i>Fg f-2zdLZ%ec@MidjNg$-)&D6UGYk~@*ZQ40S74=oN- literal 11075 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 diff --git a/recruitment/__pycache__/urls.cpython-313.pyc b/recruitment/__pycache__/urls.cpython-313.pyc index cce2bd915df6eb42c6a9c9e3e2cc673b37572f92..f3436fb6ed11b4a575bad585a1b79dcb9f954391 100644 GIT binary patch delta 1100 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 F{|AGQe`o*z delta 1993 zcmai!du&s66vumR*GnH;hqy7=)^&rycHIbdFmMqzCNfzGlL-u#(sgCM+q#ree(jz? zF>z!2!(@;nQI{ArAjStMUR@lbyy8%!CJ@A=7w7ejQ2(#HRV=chB#8 z9=~($?+zZ5UfwQQM-vjvI{xb!9BK6I*lL{wp}jfpNKk^urNOucP!?!=^tbas!96p3 zVE~IAj^qKZXZr}B67~~5!xtR6a6o&{@hZR(t*qdbfj>=otQg>=<}K=%rkvoisL|UT zY4kL+Kv>ToGcz;ULh?Q;pcT#QlVA`}6n_riAePLroFY3pvg3H7Bo9u1xS$Q-3v4ef zln;^lFn&~;1821#ORHeg5Vu6*g5Gs1OXEu=j@6Rp0y-DYgo|3oLWco{@!iE~c^Alj zo-`60ruAzaQFDl?KDFK-RDEUKd4x8G@!I0{ynb4a3QfIV4fs5f_K?c{AnTumUkSev zuHd$ECtScY<>eL;*+te%INSLY4B-K+#uY<-<@;7q~$MJ zU|1o_Gch_8yH23|cjXjrSIKsb@CyeoTF6CWGO)`WD=HLu%#H__Wo^1dN{KC}eLABu zk)_f)m#~vS3RX-Y|ETN@h18%g7UM56->;O|320X|Lewyh9xcETPuNY-vgM}rYdwCS zGHz@{@Tt#}e3aQFS#R_x9>k7{PtjIgq8Ds}4c(1d=8Z{_B+m8(i5i8DDheBuIRVx2Kj; zOvZz*X)s+Ic9{Uq z?)LZc6U}e3EfJ|-A@}k3_L4lK##jcwkIkmXL~mWB*&FcuYo%nYkWhrLH`(xTQ$8%! zt~7mRNOf>)N5YJ7^V)U(NJRB{yb%_r1>1yT)&|Zmf@QlwqQz2vJ?c|S}+MWu1T}&U0e|Rx#T;m)l-*CMfzae zNDn(GgC@z9-Fk!^$|kW=ld_D1+N3qOp~qq&5kQTH_%J%UbP_g7vLy z(#P(*Xqu>Byh`HgCgM-6*|K=`7NN22k$GZYbYHxbi+EMh#Bjvhpn8}Z4)OD-VI}_F zdy~&A=6BuSmiDypu!hxuS{LCi0Wa?%dye)+e$g+}T|+CO#@r_>TR|KB_+^{JyoxX1 z()0Up7&p07;;+lP2~&3#f3WV@L#s4b}UbzrI+@naYXe2H7MRXrlSpNs$z@v z(@F;V)G(FcD h0LIqIr?jG2I2d?@CYxv*u`@9oVq$UPSe&b^1OVAb7VrQ7 delta 110 zcmX>yi}CF&M&8f7yj%=GuxZEhjJ}P$xf+amldCm8@U!SMnlgeU7#Q+cqNOJ%X=*cu zOzzW6XXKmwO*4&!4Ja`=S}Txo;^ehjQ37lXd@2jV7I<9d)opOQ!!0 Li<8J=7i}c~&T<|4 diff --git a/recruitment/admin.py b/recruitment/admin.py index 92200c8..bfcf6cc 100644 --- a/recruitment/admin.py +++ b/recruitment/admin.py @@ -143,7 +143,7 @@ class JobPostingAdmin(admin.ModelAdmin): @admin.register(Candidate) class CandidateAdmin(admin.ModelAdmin): - list_display = ['full_name', 'job', 'email', 'phone', 'stage', 'applied', 'created_at'] + list_display = ['full_name', 'job', 'email', 'phone', 'stage', 'applied','is_resume_parsed', 'created_at'] list_filter = ['stage', 'applied', 'created_at', 'job__department'] search_fields = ['first_name', 'last_name', 'email', 'phone'] readonly_fields = ['slug', 'created_at', 'updated_at'] diff --git a/recruitment/migrations/0004_candidate_applicant_status.py b/recruitment/migrations/0004_candidate_applicant_status.py new file mode 100644 index 0000000..866ba2e --- /dev/null +++ b/recruitment/migrations/0004_candidate_applicant_status.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.6 on 2025-10-11 14:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('recruitment', '0003_candidate_is_resume_parsed_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='candidate', + name='applicant_status', + field=models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=100, null=True, verbose_name='Applicant Status'), + ), + ] diff --git a/recruitment/models.py b/recruitment/models.py index d470e25..a6df23c 100644 --- a/recruitment/models.py +++ b/recruitment/models.py @@ -267,6 +267,10 @@ class Candidate(Base): ACCEPTED = "Accepted", _("Accepted") REJECTED = "Rejected", _("Rejected") + class ApplicantType(models.TextChoices): + APPLICANT = "Applicant", _("Applicant") + CANDIDATE = "Candidate", _("Candidate") + # Stage transition validation constants STAGE_SEQUENCE = { "Applied": ["Exam", "Interview", "Offer"], @@ -298,7 +302,14 @@ class Candidate(Base): choices=Stage.choices, verbose_name=_("Stage"), ) - + applicant_status = models.CharField( + choices=ApplicantType.choices, + default="Applicant", + max_length=100, + null=True, + blank=True, + verbose_name=_("Applicant Status"), + ) exam_date = models.DateField(null=True, blank=True, verbose_name=_("Exam Date")) exam_status = models.CharField( choices=ExamStatus.choices, diff --git a/recruitment/signals.py b/recruitment/signals.py index 2c6edb1..2649cb0 100644 --- a/recruitment/signals.py +++ b/recruitment/signals.py @@ -1,136 +1,21 @@ -from . import models -from django.urls import reverse +import logging from django.db import transaction from django.dispatch import receiver +from django_q.tasks import async_task from django.db.models.signals import post_save -from .models import FormField,FormStage,FormTemplate +from .models import FormField,FormStage,FormTemplate,Candidate -# @receiver(post_save, sender=models.Candidate) -# def parse_resume(sender, instance, created, **kwargs): -# if instance.resume and not instance.summary: -# from .utils import extract_summary_from_pdf,match_resume_with_job_description -# summary = extract_summary_from_pdf(instance.resume.path) -# if 'error' not in summary: -# instance.summary = summary -# instance.save() - - # match_resume_with_job_description - -import logging logger = logging.getLogger(__name__) -import os -from .utils import extract_text_from_pdf,score_resume_with_openrouter -import asyncio -@receiver(post_save, sender=models.Candidate) +@receiver(post_save, sender=Candidate) def score_candidate_resume(sender, instance, created, **kwargs): - if instance.is_resume_parsed: - return - try: - # Get absolute file path - file_path = instance.resume.path - if not os.path.exists(file_path): - logger.warning(f"Resume file not found: {file_path}") - return - - resume_text = extract_text_from_pdf(file_path) - # if not resume_text: - # instance.scoring_error = "Could not extract text from resume." - # instance.save(update_fields=['scoring_error']) - # return - job_detail=str(instance.job.description)+str(instance.job.qualifications) - prompt1 = f""" - You are an expert resume parser and summarizer. Given a resume in plain text format, extract and organize the following key-value information into a clean, valid JSON object: - - full_name: Full name of the candidate - current_title: Most recent or current job title - location: City and state (or country if outside the U.S.) - contact: Phone number and email (as a single string or separate fields) - linkedin: LinkedIn profile URL (if present) - github: GitHub or portfolio URL (if present) - summary: Brief professional profile or summary (1–2 sentences) - education: List of degrees, each with: - institution - degree - year - gpa (if provided) - relevant_courses (as a list, if mentioned) - skills: Grouped by category if possible (e.g., programming, big data, visualization), otherwise as a flat list of technologies/tools - experience: List of roles, each with: - company - job_title - location - start_date and end_date (or "Present" if applicable) - key_achievements (as a list of concise bullet points) - projects: List of notable projects (if clearly labeled), each with: - name - year - technologies_used - brief_description - Instructions: - - Be concise but preserve key details. - Normalize formatting (e.g., “Jun. 2014” → “2014-06”). - Omit redundant or promotional language. - If a section is missing, omit the key or set it to null/empty list as appropriate. - Output only valid JSON—no markdown, no extra text. - Now, process the following resume text: - {resume_text} - """ - result = score_resume_with_openrouter(prompt1) - prompt = f""" - You are an expert technical recruiter. Your task is to score the following candidate for the role of a Senior Data Analyst based on the provided job criteria. - - **Job Criteria:** - {job_detail} - - **Candidate's Extracted Resume Json:** - \"\"\" - {result} - \"\"\" - - **Your Task:** - Provide a response in strict JSON format with the following keys: - 1. 'match_score': A score from 0 to 100 representing how well the candidate fits the role. - 2. 'strengths': A brief summary of why the candidate is a strong fit, referencing specific criteria. - 3. 'weaknesses': A brief summary of where the candidate falls short or what criteria are missing. - 4. 'criteria_checklist': An object where you rate the candidate's match for each specific criterion (e.g., {{'Python': 'Met', 'AWS': 'Not Mentioned'}}). - - - Only output valid JSON. Do not include any other text. - """ - - result1 = score_resume_with_openrouter(prompt) - - instance.parsed_summary = str(result) - - # Update candidate with scoring results - instance.match_score = result1.get('match_score') - instance.strengths = result1.get('strengths', '') - instance.weaknesses = result1.get('weaknesses', '') - instance.criteria_checklist = result1.get('criteria_checklist', {}) - - instance.is_resume_parsed = True - - # Save only scoring-related fields to avoid recursion - instance.save(update_fields=[ - 'match_score', 'strengths', 'weaknesses', - 'criteria_checklist','parsed_summary', 'is_resume_parsed' - ]) - - logger.info(f"Successfully scored resume for candidate {instance.id}") - - except Exception as e: - # error_msg = str(e)[:500] # Truncate to fit TextField - # instance.scoring_error = error_msg - # instance.save(update_fields=['scoring_error']) - logger.error(f"Failed to score resume for candidate {instance.id}: {e}") - - -# @receiver(post_save,sender=models.Candidate) -# def trigger_scoring(sender,intance,created,**kwargs): - - + if not instance.is_resume_parsed: + logger.info(f"Scoring resume for candidate {instance.pk}") + async_task( + 'recruitment.tasks.handle_reume_parsing_and_scoring', + instance.pk, + # hook='myapp.tasks.email_sent_callback' # Optional callback + ) @receiver(post_save, sender=FormTemplate) def create_default_stages(sender, instance, created, **kwargs): diff --git a/recruitment/tasks.py b/recruitment/tasks.py new file mode 100644 index 0000000..abfa760 --- /dev/null +++ b/recruitment/tasks.py @@ -0,0 +1,155 @@ +import os +import json +import logging +import requests +from PyPDF2 import PdfReader +from recruitment.models import Candidate + +logger = logging.getLogger(__name__) + +OPENROUTER_API_KEY ='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' +OPENROUTER_MODEL = 'qwen/qwen-2.5-72b-instruct:free' + +if not OPENROUTER_API_KEY: + logger.warning("OPENROUTER_API_KEY not set. Resume scoring will be skipped.") + +def extract_text_from_pdf(file_path): + print("text extraction") + text = "" + try: + with open(file_path, "rb") as f: + reader = PdfReader(f) + for page in reader.pages: + text += (page.extract_text() or "") + except Exception as e: + logger.error(f"PDF extraction failed: {e}") + raise + return text.strip() + +def ai_handler(prompt): + print("model call") + response = requests.post( + url="https://openrouter.ai/api/v1/chat/completions", + headers={ + "Authorization": f"Bearer {OPENROUTER_API_KEY}", + "Content-Type": "application/json", + }, + data=json.dumps({ + "model": OPENROUTER_MODEL, + "messages": [{"role": "user", "content": prompt}], + }, + ) + ) + res = {} + print(response.status_code) + if response.status_code == 200: + res = response.json() + content = res["choices"][0]['message']['content'] + try: + + content = content.replace("```json","").replace("```","") + + res = json.loads(content) + + except Exception as e: + print(e) + + # res = raw_output["choices"][0]["message"]["content"] + else: + print("error response") + return res + +def handle_reume_parsing_and_scoring(pk): + logger.info(f"Scoring resume for candidate {pk}") + try: + instance = Candidate.objects.get(pk=pk) + file_path = instance.resume.path + if not os.path.exists(file_path): + logger.warning(f"Resume file not found: {file_path}") + return + + resume_text = extract_text_from_pdf(file_path) + job_detail= f"{instance.job.description} {instance.job.qualifications}" + resume_parser_prompt = f""" + You are an expert resume parser and summarizer. Given a resume in plain text format, extract and organize the following key-value information into a clean, valid JSON object: + + full_name: Full name of the candidate + current_title: Most recent or current job title + location: City and state (or country if outside the U.S.) + contact: Phone number and email (as a single string or separate fields) + linkedin: LinkedIn profile URL (if present) + github: GitHub or portfolio URL (if present) + summary: Brief professional profile or summary (1–2 sentences) + education: List of degrees, each with: + institution + degree + year + gpa (if provided) + relevant_courses (as a list, if mentioned) + skills: Grouped by category if possible (e.g., programming, big data, visualization), otherwise as a flat list of technologies/tools + experience: List of roles, each with: + company + job_title + location + start_date and end_date (or "Present" if applicable) + key_achievements (as a list of concise bullet points) + projects: List of notable projects (if clearly labeled), each with: + name + year + technologies_used + brief_description + Instructions: + + Be concise but preserve key details. + Normalize formatting (e.g., “Jun. 2014” → “2014-06”). + Omit redundant or promotional language. + If a section is missing, omit the key or set it to null/empty list as appropriate. + Output only valid JSON—no markdown, no extra text. + Now, process the following resume text: + {resume_text} + """ + resume_parser_result = ai_handler(resume_parser_prompt) + resume_scoring_prompt = f""" + You are an expert technical recruiter. Your task is to score the following candidate for the role of a Senior Data Analyst based on the provided job criteria. + + **Job Criteria:** + {job_detail} + + **Candidate's Extracted Resume Json:** + \"\"\" + {resume_parser_result} + \"\"\" + + **Your Task:** + Provide a response in strict JSON format with the following keys: + 1. 'match_score': A score from 0 to 100 representing how well the candidate fits the role. + 2. 'strengths': A brief summary of why the candidate is a strong fit, referencing specific criteria. + 3. 'weaknesses': A brief summary of where the candidate falls short or what criteria are missing. + 4. 'criteria_checklist': An object where you rate the candidate's match for each specific criterion (e.g., {{'Python': 'Met', 'AWS': 'Not Mentioned'}}). + + + Only output valid JSON. Do not include any other text. + """ + + resume_scoring_result = ai_handler(resume_scoring_prompt) + + instance.parsed_summary = str(resume_parser_result) + + # Update candidate with scoring results + instance.match_score = resume_scoring_result.get('match_score') + instance.strengths = resume_scoring_result.get('strengths', '') + instance.weaknesses = resume_scoring_result.get('weaknesses', '') + instance.criteria_checklist = resume_scoring_result.get('criteria_checklist', {}) + + instance.is_resume_parsed = True + + # Save only scoring-related fields to avoid recursion + instance.save(update_fields=[ + 'match_score', 'strengths', 'weaknesses', + 'criteria_checklist','parsed_summary', 'is_resume_parsed' + ]) + + logger.info(f"Successfully scored resume for candidate {instance.id}") + + except Exception as e: + logger.error(f"Failed to score resume for candidate {instance.id}: {e}") diff --git a/recruitment/templatetags/__pycache__/form_filters.cpython-313.pyc b/recruitment/templatetags/__pycache__/form_filters.cpython-313.pyc index a5b4be1d95a3ea5aa300882d7da19d8b2edd9430..c7fbf5f7ce4beb6f0b1aa2def5dbee529bd028cd 100644 GIT binary patch literal 3046 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/upload_image_simple/', views.job_image_upload, name='job_image_upload'), + path('job//upload_image_simple/', views.job_image_upload, name='job_image_upload'), path('jobs//update/', views.edit_job, name='job_update'), # path('jobs//delete/', views., name='job_delete'), path('jobs//', views.job_detail, name='job_detail'), @@ -32,7 +32,7 @@ urlpatterns = [ path('candidates//delete/', views_frontend.CandidateDeleteView.as_view(), name='candidate_delete'), path('candidate//view/', views_frontend.candidate_detail, name='candidate_detail'), path('candidate//update-stage/', views_frontend.candidate_update_stage, name='candidate_update_stage'), - + # Training URLs path('training/', views_frontend.TrainingListView.as_view(), name='training_list'), @@ -64,11 +64,14 @@ urlpatterns = [ path('forms/builder//', views.form_builder, name='form_builder'), path('forms/', views.form_templates_list, name='form_templates_list'), path('forms/create-template/', views.create_form_template, name='create_form_template'), + path('jobs//candidate-tiers/', views.candidate_tier_management_view, name='candidate_tier_management'), + path('htmx//candidate_criteria_view/', views.candidate_criteria_view_htmx, name='candidate_criteria_view_htmx'), # path('forms/form//submit/', views.submit_form, name='submit_form'), # path('forms/form//', views.form_wizard_view, name='form_wizard'), - path('forms//submissions//', views.form_submission_details, name='form_submission_details'), + path('forms//submissions//', views.form_submission_details, name='form_submission_details'), path('forms/template//submissions/', views.form_template_submissions_list, name='form_template_submissions_list'), + path('forms/template//all-submissions/', views.form_template_all_submissions, name='form_template_all_submissions'), # path('forms//', views.form_preview, name='form_preview'), # path('forms//submit/', views.form_submit, name='form_submit'), diff --git a/recruitment/views.py b/recruitment/views.py index d83b636..a4da922 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -991,13 +991,38 @@ def form_template_submissions_list(request, slug): ) -def form_submission_details(request, template_id, submission_id): +def form_template_all_submissions(request, template_id): + """Display all submissions for a form template in table format""" + template = get_object_or_404(FormTemplate, id=template_id) + print(template) + # Get all submissions for this template + submissions = FormSubmission.objects.filter(template=template).order_by("-submitted_at") + + # Get all fields for this template, ordered by stage and field order + fields = FormField.objects.filter(stage__template=template).select_related('stage').order_by('stage__order', 'order') + + # Pagination + paginator = Paginator(submissions, 10) # Show 10 submissions per page + page_number = request.GET.get("page") + page_obj = paginator.get_page(page_number) + + return render( + request, + "forms/form_template_all_submissions.html", + { + "template": template, + "page_obj": page_obj, + "fields": fields, + }, + ) + + +def form_submission_details(request, template_id, slug): """Display detailed view of a specific form submission""" # Get the form template and verify ownership - template = get_object_or_404(FormTemplate, id=template_id, created_by=request.user) - + template = get_object_or_404(FormTemplate, id=template_id) # Get the specific submission - submission = get_object_or_404(FormSubmission, id=submission_id, template=template) + submission = get_object_or_404(FormSubmission, slug=slug, template=template) # Get all stages with their fields stages = template.stages.prefetch_related("fields").order_by("order") @@ -1192,3 +1217,133 @@ def schedule_interviews_view(request, job_id): "interviews/schedule_interviews.html", {"form": form, "break_formset": break_formset, "job": job}, ) + + +def candidate_tier_management_view(request, slug): + """ + Manage candidate tiers and stage transitions + """ + job = get_object_or_404(JobPosting, slug=slug) + + # Get all candidates for this job, ordered by match score (descending) + candidates = job.candidates.all().order_by("-match_score") + + # Get tier categorization parameters + tier1_count = int(request.GET.get("tier1_count", 100)) + + # Categorize candidates into tiers + tier1_candidates = candidates[:tier1_count] if tier1_count > 0 else [] + remaining_candidates = candidates[tier1_count:] if tier1_count > 0 else [] + + if len(remaining_candidates) > 0: + # Tier 2: Next 50% of remaining candidates + tier2_count = max(1, len(remaining_candidates) // 2) + tier2_candidates = remaining_candidates[:tier2_count] + tier3_candidates = remaining_candidates[tier2_count:] + else: + tier2_candidates = [] + tier3_candidates = [] + + # Handle form submissions + if request.method == "POST": + # Update tier categorization + if "update_tiers" in request.POST: + tier1_count = int(request.POST.get("tier1_count", 100)) + messages.success(request, f"Tier categorization updated. Tier 1: {tier1_count} candidates") + return redirect("candidate_tier_management", slug=slug) + + # Update individual candidate stages + elif "update_stage" in request.POST: + candidate_id = request.POST.get("candidate_id") + new_stage = request.POST.get("new_stage") + candidate = get_object_or_404(Candidate, id=candidate_id, job=job) + + if candidate.can_transition_to(new_stage): + old_stage = candidate.stage + candidate.stage = new_stage + candidate.save() + messages.success(request, f"Updated {candidate.name} from {old_stage} to {new_stage}") + else: + messages.error(request, f"Cannot transition {candidate.name} from {candidate.stage} to {new_stage}") + + # Update exam status + elif "update_exam_status" in request.POST: + candidate_id = request.POST.get("candidate_id") + exam_status = request.POST.get("exam_status") + exam_date = request.POST.get("exam_date") + candidate = get_object_or_404(Candidate, id=candidate_id, job=job) + + if candidate.stage == "Exam": + candidate.exam_status = exam_status + if exam_date: + candidate.exam_date = exam_date + candidate.save() + messages.success(request, f"Updated exam status for {candidate.name}") + else: + messages.error(request, f"Can only update exam status for candidates in Exam stage") + + # Bulk stage update + elif "bulk_update_stage" in request.POST: + selected_candidates = request.POST.getlist("selected_candidates") + new_stage = request.POST.get("bulk_new_stage") + updated_count = 0 + + for candidate_id in selected_candidates: + candidate = get_object_or_404(Candidate, id=candidate_id, job=job) + if candidate.can_transition_to(new_stage): + candidate.stage = new_stage + candidate.save() + updated_count += 1 + + messages.success(request, f"Updated {updated_count} candidates to {new_stage} stage") + + # Mark individual candidate as Candidate + elif "mark_as_candidate" in request.POST: + candidate_id = request.POST.get("candidate_id") + candidate = get_object_or_404(Candidate, id=candidate_id, job=job) + + if candidate.applicant_status == "Applicant": + candidate.applicant_status = "Candidate" + candidate.save() + messages.success(request, f"Marked {candidate.name} as Candidate") + else: + messages.info(request, f"{candidate.name} is already marked as Candidate") + + # Mark all Tier 1 candidates as Candidates + elif "mark_as_candidates" in request.POST: + updated_count = 0 + for candidate in tier1_candidates: + if candidate.applicant_status == "Applicant": + candidate.applicant_status = "Candidate" + candidate.save() + updated_count += 1 + + if updated_count > 0: + messages.success(request, f"Marked {updated_count} Tier 1 candidates as Candidates") + else: + messages.info(request, "All Tier 1 candidates are already marked as Candidates") + + # Group candidates by current stage for display + stage_groups = { + "Applied": candidates.filter(stage="Applied"), + "Exam": candidates.filter(stage="Exam"), + "Interview": candidates.filter(stage="Interview"), + "Offer": candidates.filter(stage="Offer"), + } + + context = { + "job": job, + "tier1_candidates": tier1_candidates, + "tier2_candidates": tier2_candidates, + "tier3_candidates": tier3_candidates, + "stage_groups": stage_groups, + "tier1_count": tier1_count, + "total_candidates": candidates.count(), + } + + return render(request, "recruitment/candidate_tier_management.html", context) + +def candidate_criteria_view_htmx(request, pk): + candidate = get_object_or_404(Candidate, pk=pk) + print(candidate) + return render(request, "includes/candidate_modal_body.html", {"candidate": candidate}) \ No newline at end of file diff --git a/recruitment/views_frontend.py b/recruitment/views_frontend.py index 7451276..5427f7b 100644 --- a/recruitment/views_frontend.py +++ b/recruitment/views_frontend.py @@ -223,7 +223,7 @@ def candidate_detail(request, slug): stage_form = forms.CandidateStageForm(candidate=candidate) # parsed = JSON(json.dumps(parsed), indent=2, highlight=True, skip_keys=False, ensure_ascii=False, check_circular=True, allow_nan=True, default=None, sort_keys=False) - parsed = json_to_markdown_table([parsed]) + # parsed = json_to_markdown_table([parsed]) return render(request, 'recruitment/candidate_detail.html', { 'candidate': candidate, 'parsed': parsed, diff --git a/templates/forms/form_submission_details.html b/templates/forms/form_submission_details.html index 0b38326..4846c18 100644 --- a/templates/forms/form_submission_details.html +++ b/templates/forms/form_submission_details.html @@ -9,8 +9,8 @@ @@ -51,62 +51,79 @@
Responses
- {% get_all_responses_flat stage_responses as all_responses %} - {% if all_responses %} -
- - - - - - - - - - {% for response in all_responses %} - - - - - - {% endfor %} - -
Field LabelResponse ValueFile
- {{ response.field_label }} - {% if response.required %} - * - {% endif %} - - {% if response.uploaded_file %} - File: {{ response.uploaded_file.name }} - {% elif response.value %} - {% if response.field_type == 'checkbox' and response.value|length > 0 %} -
- {% for val in response.value %} - {{ val }} - {% endfor %} -
- {% elif response.field_type == 'radio' or response.field_type == 'select' %} - {{ response.value }} - {% else %} -

{{ response.value|linebreaksbr }}

- {% endif %} - {% else %} - Not provided - {% endif %} -
- {% if response.uploaded_file %} - - Download - - {% endif %} -
-
- {% else %} -
-

No responses found for this submission.

-
- {% endif %} + {% with submission=submission %} + {% get_all_responses_flat submission as flat_responses %} + + {% if flat_responses %} +
+ + + + + {% for response in flat_responses %} + + {% endfor %} + + + + + + {% for response in flat_responses %} + + {% endfor %} + + + + {% for response in flat_responses %} + + {% endfor %} + + + + {% for response in flat_responses %} + + {% endfor %} + + +
Field Label{{ response.field_label }}
Response Value + {% if response.uploaded_file %} +
+ {{ response.uploaded_file.name }} + + + +
+ {% elif response.value %} + {% if response.field_type == 'checkbox' and response.value|length > 0 %} +
+ {% for val in response.value %} + {{ val }} + {% endfor %} +
+ {% elif response.field_type == 'radio' or response.field_type == 'select' %} + {{ response.value }} + {% else %} +

{{ response.value|linebreaksbr }}

+ {% endif %} + {% else %} + Not provided + {% endif %} +
Stage + {{ response.stage_name|default:"N/A" }} +
Required + {% if response.required %} + Yes + {% else %} + No + {% endif %} +
+
+ {% else %} +
+

No responses found for this submission.

+
+ {% endif %} + {% endwith %}
@@ -119,6 +136,8 @@ border-top: none; font-weight: 600; color: #495057; + vertical-align: top; + white-space: nowrap; } .table td { vertical-align: top; @@ -126,5 +145,17 @@ .response-value { max-width: 300px; } +.table th:first-child, +.table td:first-child { + background-color: #f8f9fa; + font-weight: 600; +} +.table-striped > tbody > tr:nth-of-type(odd) > td { + background-color: rgba(0, 0, 0, 0.02); +} +.table-bordered th, +.table-bordered td { + border: 1px solid #dee2e6; +} {% endblock %} diff --git a/templates/forms/form_template_all_submissions.html b/templates/forms/form_template_all_submissions.html new file mode 100644 index 0000000..9b0e498 --- /dev/null +++ b/templates/forms/form_template_all_submissions.html @@ -0,0 +1,371 @@ +{% extends 'base.html' %} +{% load static i18n form_filters %} +{% load partials %} + +{% block title %}All Submissions for {{ template.name }} - ATS{% endblock %} + +{% block customCSS %} + +{% endblock %} + +{% block content %} +
+ + +
+
+
+

+ + {% trans "All Submissions for" %}: {{ template.name }} +

+ Template ID: #{{ template.id }} +
+ + {% trans "Back to Submissions" %} + +
+
+ {% if page_obj.object_list %} +
+ + + + + + + + {% for field in fields %} + + {% endfor %} + + + + {% for submission in page_obj %} + + + + + + {% for field in fields %} + {% get_field_response_for_submission submission field as response %} + + {% endfor %} + + {% endfor %} + +
{% trans "Submission ID" %}{% trans "Applicant Name" %}{% trans "Applicant Email" %}{% trans "Submitted At" %}{{ field.label }}
{{ submission.id }}{{ submission.applicant_name|default:"N/A" }}{{ submission.applicant_email|default:"N/A" }}{{ submission.submitted_at|date:"M d, Y H:i" }} + {% if response %} + {% if response.uploaded_file %} +
+ + + + +
+ {% elif response.value %} + {% if response.field.field_type == 'checkbox' and response.value|length > 0 %} +
+ {% for val in response.value|to_list %} + {{ val }} + {% endfor %} +
+ {% elif response.field.field_type == 'radio' or response.field.field_type == 'select' %} + {{ response.value }} + {% else %} +

{{ response.value|linebreaksbr|truncatewords:10 }}

+ {% endif %} + {% else %} + Not provided + {% endif %} + {% else %} + Not provided + {% endif %} +
+
+ + + {% if page_obj.has_other_pages %} +
+
+ {% blocktrans with start=page_obj.start_index end=page_obj.end_index total=page_obj.paginator.count %} + Showing {{ start }} to {{ end }} of {{ total }} results. + {% endblocktrans %} +
+ +
+ {% endif %} + {% else %} +
+ +

{% trans "No Submissions Found" %}

+

+ {% trans "There are no submissions for this form template yet." %} +

+ + {% trans "Back to Submissions" %} + +
+ {% endif %} +
+
+
+{% endblock %} diff --git a/templates/forms/form_template_submissions_list.html b/templates/forms/form_template_submissions_list.html index 77edba2..11df1ba 100644 --- a/templates/forms/form_template_submissions_list.html +++ b/templates/forms/form_template_submissions_list.html @@ -200,9 +200,14 @@ Template ID: #{{ template.id }} - - {% trans "Back to Templates" %} - +
{% if page_obj.object_list %} @@ -231,10 +236,10 @@ {{ submission.applicant_email|default:"N/A" }} {{ submission.submitted_at|date:"M d, Y H:i" }} - + {% trans "View Details" %} - + {% endfor %} @@ -260,7 +265,7 @@

diff --git a/templates/forms/form_wizard.html b/templates/forms/form_wizard.html index 73de014..3705ad6 100644 --- a/templates/forms/form_wizard.html +++ b/templates/forms/form_wizard.html @@ -881,17 +881,28 @@ formData.append('csrfmiddlewaretoken', csrfToken); // Add field responses - state.stages.forEach(stage => { + state.stages.forEach(stage => { stage.fields.forEach(field => { const value = state.formData[field.id]; - if (value !== undefined && value !== null) { - if (field.type === 'file' && value instanceof File) { + + // Always include the field, even if it's empty + if (field.type === 'file') { + if (value instanceof File) { formData.append(`field_${field.id}`, value); - } else if (field.type === 'checkbox') { + } else { + // Include empty file field + formData.append(`field_${field.id}`, ''); + } + } else if (field.type === 'checkbox') { + // For checkboxes, send empty array if no selection + if (Array.isArray(value) && value.length > 0) { formData.append(`field_${field.id}`, JSON.stringify(value)); } else { - formData.append(`field_${field.id}`, value); + formData.append(`field_${field.id}`, JSON.stringify([])); } + } else { + // For other field types, send the value or empty string + formData.append(`field_${field.id}`, value || ''); } }); }); diff --git a/templates/includes/candidate_modal_body.html b/templates/includes/candidate_modal_body.html new file mode 100644 index 0000000..6b32d24 --- /dev/null +++ b/templates/includes/candidate_modal_body.html @@ -0,0 +1,21 @@ +{% load i18n %} + +
+ + +
+
+ + +
+
+ +
    + {% for key, value in candidate.criteria_checklist.items %} +
  • + {{ key }} + {{ value|yesno:"Yes,No" }} +
  • + {% endfor %} +
+
\ No newline at end of file diff --git a/templates/jobs/job_detail.html b/templates/jobs/job_detail.html index 28ba0d1..4b9ce4e 100644 --- a/templates/jobs/job_detail.html +++ b/templates/jobs/job_detail.html @@ -136,7 +136,7 @@ } .right-column-tabs .nav-link { padding: 0.9rem 1rem; - font-size: 0.95rem; + font-size: 0.95rem; font-weight: 600; color: var(--kaauh-primary-text); border-radius: 0; @@ -409,11 +409,11 @@ {% trans "Edit Job" %} - + - + @@ -472,9 +472,9 @@ {% trans "View All Applicants" %} ({{ total_candidates }}) - + {% endif %} - + @@ -551,6 +551,43 @@ {% endif %} + + {# Applicant Form Management (Content from old card) #} +
{% trans "Form Management" %}
+
+

+ {% trans "Manage the custom application forms associated with this job posting." %} +

+ + + {% trans "Create New Form" %} + + + + {% trans "View All Existing Forms" %} + + + + {% trans "Create Candidate" %} + + + {% trans "Manage Tiers" %} + +
+ + + {# TAB 3: INTERNAL INFO CONTENT #} +
+
{% trans "Internal Information" %}
+
+

{% trans "Internal Job ID:" %} {{ job.internal_job_id }}

+

{% trans "Created:" %} {{ job.created_at|date:"M d, Y" }}

+

{% trans "Last Updated:" %} {{ job.updated_at|date:"M d, Y" }}

+ {% if job.reporting_to %} +

{% trans "Reports To:" %} {{ job.reporting_to }}

+ {% endif %} +
+
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/recruitment/candidate_tier_management.html b/templates/recruitment/candidate_tier_management.html new file mode 100644 index 0000000..42d10f5 --- /dev/null +++ b/templates/recruitment/candidate_tier_management.html @@ -0,0 +1,724 @@ +{% extends 'base.html' %} +{% load static i18n %} + +{% block title %}Candidate Tier Management - {{ job.title }} - ATS{% endblock %} + +{% block customCSS %} + +{% endblock %} + +{% block content %} +
+ + + +
+
+ {% csrf_token %} +
+
+ + +
+
+ +
+
+
+
+ + +
+

{% trans "Bulk Stage Update" %}

+
+ {% csrf_token %} +
+
+ + +
+
+ +
+
+
+
+ + + {% comment %}
+ {% for stage_name, stage_candidates in stage_groups.items %} +
+
+ {{ stage_name }} + {{ stage_candidates.count }} +
+
+ {% for candidate in stage_candidates %} +
+
+ + +
+
+ {% empty %} +

{% trans "No candidates in this stage" %}

+ {% endfor %} +
+
+ {% endfor %} +
{% endcomment %} + + +

{% trans "Candidate Tiers" %}

+ + + + + +
+ +
+ {% if tier1_candidates %} +
+ +
+
+ + + + + + + + + + + + + {% for candidate in tier1_candidates %} + + + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Contact" %}{% trans "AI Score" %}{% trans "Status" %}{% trans "Stage" %}{% trans "Actions" %}
+
{{ candidate.name }}
+
+
+ Email: {{ candidate.email }}
+ Phone: {{ candidate.phone }}
+
+
+ {{ candidate.match_score|default:"0" }} + + + {{ candidate.get_applicant_status_display }} + + + + {{ candidate.get_stage_display }} + + {% if candidate.stage == "Exam" and candidate.exam_status %} +
+ {{ candidate.get_exam_status_display }} + {% endif %} +
+ +
+
+ {% else %} +

{% trans "No candidates in Tier 1" %}

+ {% endif %} +
+ + +
+ {% if tier2_candidates %} +
+ + + + + + + + + + + + + {% for candidate in tier2_candidates %} + + + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Contact" %}{% trans "AI Score" %}{% trans "Status" %}{% trans "Stage" %}{% trans "Actions" %}
+
{{ candidate.name }}
+
+
+ Email: {{ candidate.email }}
+ Phone: {{ candidate.phone }}
+
+
+ {{ candidate.match_score|default:"0" }} + + + {{ candidate.get_applicant_status_display }} + + + + {{ candidate.get_stage_display }} + + {% if candidate.stage == "Exam" and candidate.exam_status %} +
+ {{ candidate.get_exam_status_display }} + {% endif %} +
+ +
+ {% if candidate.applicant_status == 'Applicant' %} + + {% endif %} + {% for next_stage in candidate.get_available_stages %} + + {% endfor %} + {% if candidate.stage == "Exam" %} + + {% endif %} +
+ + +
+
+ {% else %} +

{% trans "No candidates in Tier 2" %}

+ {% endif %} +
+ + +
+ {% if tier3_candidates %} +
+ + + + + + + + + + + + + {% for candidate in tier3_candidates %} + + + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Contact" %}{% trans "AI Score" %}{% trans "Status" %}{% trans "Stage" %}{% trans "Actions" %}
+
{{ candidate.name }}
+
+
+ Email: {{ candidate.email }}
+ Phone: {{ candidate.phone }}
+
+
+ {{ candidate.match_score|default:"0" }} + + + {{ candidate.get_applicant_status_display }} + + + + {{ candidate.get_stage_display }} + + {% if candidate.stage == "Exam" and candidate.exam_status %} +
+ {{ candidate.get_exam_status_display }} + {% endif %} +
+ +
+ {% if candidate.applicant_status == 'Applicant' %} + + {% endif %} + {% for next_stage in candidate.get_available_stages %} + + {% endfor %} + {% if candidate.stage == "Exam" %} + + {% endif %} +
+ + +
+
+ {% else %} +

{% trans "No candidates in Tier 3" %}

+ {% endif %} +
+
+
+ + +{% for candidate in tier1_candidates|add:tier2_candidates|add:tier3_candidates %} +{% if candidate.stage == "Exam" %} + +{% endif %} +{% endfor %} + + +{% endblock %} + +{% block customJS %} + + +{% endblock customJS %} From 9a768726e5f4ef8fcb51252e398439377fe785ce Mon Sep 17 00:00:00 2001 From: ismail Date: Sun, 12 Oct 2025 13:44:52 +0300 Subject: [PATCH 2/2] update --- .gitignore | 3 +- .../__pycache__/settings.cpython-313.pyc | Bin 5654 -> 7678 bytes .../__pycache__/urls.cpython-313.pyc | Bin 2176 -> 2177 bytes NorahUniversity/settings.py | 103 +++++++++++++++++- db.sqlite3 | Bin 651264 -> 663552 bytes recruitment/__pycache__/admin.cpython-313.pyc | Bin 11458 -> 11558 bytes recruitment/__pycache__/forms.cpython-313.pyc | Bin 22858 -> 22538 bytes .../__pycache__/models.cpython-313.pyc | Bin 45244 -> 45475 bytes .../__pycache__/signals.cpython-313.pyc | Bin 6443 -> 6443 bytes recruitment/__pycache__/urls.cpython-313.pyc | Bin 6220 -> 6491 bytes recruitment/__pycache__/views.cpython-313.pyc | Bin 43206 -> 45573 bytes .../views_frontend.cpython-313.pyc | Bin 19780 -> 19475 bytes recruitment/migrations/0001_initial.py | 7 +- ...postingimage_post_image_height_and_more.py | 26 ----- .../0004_candidate_applicant_status.py | 18 --- .../__pycache__/0001_initial.cpython-313.pyc | Bin 28730 -> 29938 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 167 -> 167 bytes recruitment/models.py | 6 +- .../__pycache__/form_filters.cpython-313.pyc | Bin 3046 -> 3046 bytes 19 files changed, 108 insertions(+), 55 deletions(-) delete mode 100644 recruitment/migrations/0002_remove_jobpostingimage_post_image_height_and_more.py delete mode 100644 recruitment/migrations/0004_candidate_applicant_status.py diff --git a/.gitignore b/.gitignore index 488280b..74f846b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -<<<<<<< HEAD + # Byte-compiled / optimized / DLL files __pycache__/ *.pyc @@ -110,4 +110,3 @@ local_settings.py # If a rule in .gitignore ends with a directory separator (i.e. `/` # character), then remove the file in the remaining pattern string and all # files with the same name in subdirectories. ->>>>>>> 29790ab (add external integration) diff --git a/NorahUniversity/__pycache__/settings.cpython-313.pyc b/NorahUniversity/__pycache__/settings.cpython-313.pyc index 48f3c69beda3231ee409a1985d04f28aa7fe401a..23e0028488eca88c9f350625a6b242e64d327ff4 100644 GIT binary patch delta 2152 zcmZ`(%X8aA7?&(RBH3{~c{pj(g3B~*4XK+rY1%@7rf!mENaG}%&{tYlme#hgESc3R zZB4)zLCqK`7-zt7y&J-$mEG{RX<}?YGcvZ(m1u_ zrqEsTCd!ew&^@G{6;OUz9EA@kZJDq7vWPG$fUSUvo}>g4!{gsu7T2fNr%*ZN^Y+_7 zATuSQ3bK%ms_1>7333ocF4{=>(S7s)Jw!E+{s28fAEJ*qebzrJqIxQTHsL7#eVmd& z@;D`tx6u=Fspw07vh|B^LQ=Fc)(vWt+_@iv3v#^{D>>%riIK#`(czKAxeLQdCaqvS z>0<%SHf=((P^DToHyWQ99Z6hBbF(y<`Iii<+|r~kj*TQHCqOg7HNhp9R88F0O{P5u z(48Mn*1}gXt|s;k>JT?Q4&Dp5KEu!Oy&Gy0{jusW3a#e-%iCQhOj`k5_ z`&4?L8Yj1*q9n(cdqN#nk5_?DCde%=<^mS7U8-Y?0yvBBEwgp5zr&Zi+(>poM*uZu zoem{N8PgK6-C~LPHCx9_cHF$95u-|3*m0|vv>CZ%6iX)j>#ev<=H{1qZV$f#kaaB5bq80JGJb2`JPiuG{v zvZ~d~MZjz6EvZt0*;Hqs-a3mAT(LLstW7E^pl_jARr4lheo9=N^pTsq1aYTiyQaQq z(>aJ#y3 z0wtog_&>!N=m#dXu0wLifJX4#lL6*0008FaA|~%gXNpI9Az9d?Gq}zJK`J+RDnW;z z>_CJt<%vR3+=>OI=FEzHpLJC*DPpe(8El#k>+)1f#D>;V13Rpz8Fi-X?(0 ztFpslc~xuIz1|WfB^K47Baqi>>%NfBcr!oeutIi~8n)#SjdSwS-k8^Vwep$vr04dB zA3_BxFia*3P=i9Z0-C8h4$--@uQXPZueR=AVyxB!{ojwUcW07*@&&i`Zy5MK`4UL- z6<=^GK>8p+8Up;wKTQfP!|?;d@&7U$hdM`0?>_J4>~$gFbrsO_s(TlbDb@W7CnfTj z$5$Mx!mWVo_keW}41?vst0|FQt_;D`LxjF0+PKv)6JNgjoL}@$CGksxvcS7NAWp_|~`8-58KHfMn3CAa*fO3yH5#8wmo93X<8E*`o{C;SA?#}aAt}!(H zE&Zvyy=pvi;8 zZobCm!^xy+v$;idGxOw4lEK{lK&^~GT)cs4vVfF7pR^ED1K$TL25z1P_77~EbESfr L*c&;EdVxv+N>(2& diff --git a/NorahUniversity/__pycache__/urls.cpython-313.pyc b/NorahUniversity/__pycache__/urls.cpython-313.pyc index 56ff2beb6b7bdf70aefaa5f6d15cd887801a35f3..e7abc5515055cad45f6eb6e93fe77892eebbe01e 100644 GIT binary patch delta 100 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 delta 34417 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 diff --git a/recruitment/__pycache__/admin.cpython-313.pyc b/recruitment/__pycache__/admin.cpython-313.pyc index ea1b2f982387927a3f96c97959673ba32f358616..c67547f63693a27f6f29f7f3ddd02c317c30233c 100644 GIT binary patch delta 2954 zcmai0eQZ-z6z^-huItCTv9EUP`mt_nA9Lfw4H&|75eY*+w^i7Ll}G#575e3UEwB!!OTmTIqM*RbfL`jhF$0BN?#2Lv06%$BIz-U7JLt~=%+}Ew0YvW7y+db#} z&bjxVd(OSRIdoyT{E69YP|yO5CzNvDnT3<5dJ5;^dN~|uGRn?>#D6Llw==X5_ zE5W6%uORhISw@wHIi;F3fQzdI183vbQkI8vFnMHNb~5>LR`!C2s{);Rj_qdF;d!}< z$sf+k9ww_b$WLk%@0XZ_bG0z*dvmg_l`d-=?rGuI-+fB!t|@4MRYfgPt^37-J`01R zw5PUdX;#sVR&@L0QvtAMVOuPbEB=EVLT2`Lqchx=ke7&N+XxJH=O zJ+HG-S7L+4QirZp8TOV6dmC`rNMRdqBn}ju2rdLSf*GL+!Gq9@fT85lNIV*eixO!; z6^0-zt`|o<1Nf)3Rhf*x(x%sN-sPxXiSRT+C&DrcvN0q|K@v%(B8fQZ1b^8wBkBor z=z^1FHf{x6DqGir&T>^Go)W`EKz87eNF?-P5m%v8Cm0N;xs`C%Frs6tSr1y{0M`n; zjmNp?;J&fJ){DFi6eKML7ySrh_CU4CPnicyZmW_N%c88nJEncB*HbsSQW{H;R3Lxt zJs7x9M%vNP4r|R9m5j7Qo8ES+{N0@^(14lXwPZJrhY@zoYc;Y-N~B3p3^DY6=kEES7g;L}PscM$GXdVNu(u{mONG^ljRrNvzWKU?fBwyT1> z7{xH75MGkq#psoXOEz&6*(D!A>o^6u{BVLCOhyHI(5dmHm|p?p5V8&c@1PL>NGrM3_P-)Uy&ABzU?0FQowK zu;HOjsV&%OZ(YI;QA^Gt?`?!mc-7v~H(z};(^@H-4(C#usop{Ft3+Igy87ay2@+!` zGFOe~F~$Xi>?D8KJ;t*rv*_o*(|C;TSH2fsPGY1(+_6!!^Sa~40!tMIpTNI4fTbU5wJw4q$tiLx(8fjg3ByfZK3 zIIoiNt2io@>}fPi!z0%%CE3%g+rM=m>t+@G2AbKX8K6!s4JK%P##00vG_MKNO2gcM z6HRT)bB=j!OkP0`yt48ht?MXWhX+j=Ln|9n2u@Yjz%kDU8`-QnRI}0NIJ$*^Q8SjU zqKI#;?0Y?h{lBnmYNP8Cul?1fq>U}!2_K| z!z_5bNo5DKbO$!L?7e8bhZY&(E`)sT!|X2BD4HKojf6~1FIICOr9SS-mCH-@YWu9p{<~hq>5dy-GkmYAx~;03-2R=anU(0j@GfoS delta 2763 zcmai0ZERCz6z=W%wSMfA(GS|L?LOK|$LJgmHGBr5;*gI~z7!~z?sdD+we`KXuq`q8 z2Y(s1<;Xt_BMQhbqGUuv7K6!D{2?T02p2T^!F?&;pIZQush(!*IfEoDNRi7Lq%MKsX_{8_t3=z$)) z*TEw`i=I&E^yqt5oVnpxZ#k6^$>S1^KL-KCI*U$L5Mw+ zbJjx2xm)Of8E4p|m#BVGiQtj*u)u=5+^uUdOr>IUp`i;-xi0C&=;Fobuls0c0xehq zwvoLk??>2E($;8BC0C$nl1gQz5kmJdi{>Jf=4fh!D2g;hM5pf0>HA=Fz3AXUUdJE_ z7_ASV#02Bb1LVyDQPj|u>>D{cBJnb>W){)1FaWX+a4JHIfo9q)sgh`<2T^kfHP!*5 z6f!E7zntqZnlaUjdQbFNyRdC=H`} z^^&Z5?+M-TPGdaDr|0N=V$sYei4LJ+7(r&BnX@^SD4M;H$83WsNu_;g0Zaq z&n-7tfaMqu!dkZn-u76l(k5Wqvy)MN_e|=PR!*7r+Nx3}StdNCZeJvz&s@WzQ;H?P z21UA0qd0&tfiQ_ssc94q6fXMy)~Ak%%YL!wLj_a*&L$iSHviM;cOIb^Zu+}DrLki* zHYu6HP_dX$AMm-06ZavyUqC3v+Yo4ToGS&IhHT)vkb~vHWfpz-pg(vYcd;FNO9q&-0-b#dJ$g3r-)+BLn-q;B7OD ze`jH3+qk}hS-8^nrH`kxpovRgq4YIE1}55D=9^Jg-$dItaJ~IpoD=>p>m2&e!KscZ zJ?k9!J10-_cUF1n{7uJ!$K=*kd=Uucd&s0;UEIXk$kA*`d4%9wmR-M3uSs-O8gnD> zTXS~|!!JkJj<5rvQuFSh;SOY@d3_Ui*e1O2PxO-GK3eV}XmBOAqKOZ0jjnls>ih60 z7Km#o{=lGkJyvYcU39t&ed3U_gNqEdiBY&LUO1__lG2evMxtBz_XPjA;NK6Ljglc* zQ3=)TujU3xX5-+9oTXhDAc;T__(A0($fsZqb$nBplN~{s@t+(Q&9-JFH(1D!b@W$* b!DHQ z!DFuxy{QN|#SjLN&IuW- zz^j8Zr*i-7`#K@Ltwm4<$%Gj1Qv3MdJ?e826 z^h*Mft?jFpg~Ev#UBI5vL`mLQnf4$d`RqwuKg-h>sA(0e&<_{P1~-3}^+1dc*2blX z6if&@ma8vhujrp74J>Hr)RluoK6}>ivc3f<>KmiRJ?aV<(0#IzN`X);8re-}!TUKP zn}YGUKNtzb#<7}tI66|=><~O?+l0fr39@-KCUs%LC8W_$S!3q)wd$q#cbIQ zeHD=Lzp+Q1z3g!I_cr73=Lqe_e?~eN<>n#GM`%RwA#@=u0gx?z#gw2FiTM4{bt7=& z1i(l6Fm@D0$YTdBZe@OUw%ui8zqAC%VkYGLKFI}f8Y4xkrJe4!p`l1P7)XR;QMZ@? zS5x#LtwX3mXaHC(STfp|hXM-_&>3_gLKA`pVG+V&1hk$jqAdkTavOX|g#cRFqt;~; zi}AiSq!!RT*}zScLV`us48?|MKgzE{K#$1kp>4FDJ&-@EnlFSQxHT3IN^!atCD0PV zNY^8M55fjEmS0`TS1*e1+;c{t+{&|8v8juFmhUE=V~&Cr4XI}vi!Tz9SxW57_|&)s z1K6D#m=_F0{RtX~#>417Kg8xXXq2@Bv2aw-^3i2eRNCo}bH~P5q@Helr-Z^+(E#qz`;hVjOpSp6G7%QD@zPm}TLTaSo7sph zkL(!xhAp3voov+ZBeU35yG<`(hZ^>|z4(4ydRd#;JtR>rl4@_mISmg8Su+@p(m5!q z1cWt{xil9AzBC}3*|5XynH~|?WilZ4!Rt=;qGR7gK(v)TNRmrYs2$;Mgk=c(5pbK* z

85zK+ldFp|>_TR9=QyCn&;2we%xbC${Yp(Yf?y+>Cg^dPK3=tVFiq_=W|658v4 zc}`i^R8*l94<&RLL{d78wmHkme)h2Ql)#hBW)%Di!t~|Zi%f(aY?UjuW%t5zQO9Gz z48kw{7*f>rk6E&>hIT-nw~1K}umr5ij%!+}T#q|3T)DG~VOICEF5guvKVVK*s(0SeiVDrO`x zHUtel1OMo^5x#?Pr(noOfiDjRXqAoY)^>G9hlUffsUsYbIQfN?fofWL-tZxL3g9^W z;``Y>m0h}Vy~^QcFI6^81kA0s6u#Coy6K zIrrd}+D6*Rc2zao(@EwFLBf7rRqo`u0AqnNfcW&K*H>4PruaGbLN2{D#QD3KFy(`L18qtXBEgD#Nm&0Th zbz;`Un~uM+o)s>gM$8sXDaw+jazrcgKu2y$$M!CVMI+{k`KY6rY&NjDx)NwF5DUd3 zWkk?boYqjHP#{q{sR1NF18QEV5p4<|V$fb^rP-o`TKda`a=BpggrAJQ*I}kYAw9$X zEgWHw&prf!STm=g2t$wO9z3774~MA~f`qkWPVK!sMDeT=)XKT_bD(AYQYal_QCZ#H zHey*94JV`!o^1&!o)VLFI|7kmX(X@8+fdWc(BQ6hS2b};)`oCT9AX!0J+?wOvW85?Vh7A^Hr$PY}){TtIjh;W>oo5ne%f72!pMmk@r6 z@G}HuALV3Bsyy^3_Ypr^n^j5Zg(s|Rx*IH3cFqx0b?5y0Ll8kX$B#p{IH0cLo*k)dFt+-O=zGl$Y>2k*kz;jr|XrrYdQ@pt2b(m zDw~rv)E5Eas$#wMMO(8~PS2?Sw4!4s$Tfljjng`g5~H!xF|NP^4GXZrg$)%m&RV~3 z#Rl6fXjq6171r@=Re9xT&*>iCV;(fj$A)t2c&Vy-HcK`X^_oHFd(QgbIk{OSrB__d zU^4dCf?~7E?izKScJcm=*L2zjY_MC$b5!o?(d6kQZ>R&sUR3M`Q&`R1&fII8)V-v@ zeAqyF?)HuCpZg{u=ULDEqD{E6BiUkLI23lb(ZH5)fUh&u8e#PPuMpDdLpFw^aP&um z5*@$>F9NSmGA54K=9dvC`(XZ4q-AVhL~=I())nlu7wd=@y^W-9 z>{IU_2sy*vY}z_ckq04J6Op3y687QIg1sU1*CPWHcw7zOcGFfCY_1_q>`3!=Ezb2= zOEGiYb(vgb<9BuBbMcF}iLY4HM11UPi#DdkZ!UT-Pqqdot4RMajj&6Lo14?tP(A3F zVu(hmj5Hu9n_we`Vavs694&<-6pU(L;v*en4=uSsy3m)hE*OylQ7R&B3WP#_iP9Jq zbjpPIID98PkK^#;Sf}WkIFCQUo`vlGMTKMyd#p8-#K}V8h07&m-gJAQiTV(D{rxUd zA0S*s_!t4T-k}gXi_HkH!Y_`8#=j1z-q$wX(r(HoI`cKvCcv8`YW9%Nqnur5dGdGl z)fZ36j{N?EDKb33&aZ1pmQE(lbQ3?j!`om-%jO}-ef}_Bno>z6^VOmRt(#0LOYjww zkP`Eg_1NEmhl=A^3_-p~=9C}QUCAvwxaY7wwLd1hu0E&Fn7@1|kZFKVu>oNK2gnBE zfa;c7t#jT`0VvwBd1@8J_PWgM4d1;aHs)??Ck5M~E9?muh{@V$U{InL*^Z@6aB`eq z>LNAl?WOa0=^|@sY-e1lVDUWpESKLAgIlHGw%Rb3AW+==6B;N+JiUd0{#Y$!u5=4g zVA6lMyi=||&G0H4`=nio0F@d8vZWoz*%I4zhYANZ_z-RaY-i84e|Msy*?9LON<}lh z1jboUDS@Y%{~v7aWUh`mOO7F#Dd_-TwqbPjNrOWXI7s+m?Ds=?nDF}#;kulG3+o2< zVaIY2cMaVPAeb^P^t3(0m;65L;|G{}N4btngc#esJQe)cCxV~-Ww}*%5=IUl%`0LB zD;`dsf)`%j%SI_0@+ZQB65LV%m0P-+9!7nYlsO* zHuZtt+gHhvd1q)r{VC?{Y+uR!;zMP8GYx#J8rVeNk45{Oiwe;A%USwO4t>kuD8;=b4PrqwTOYU9l(H@Wf4d@kb zhfpnLZ}-%b7WR41nTB#yrJ*}eEk8Xp;VAC&^~k_RSrZEEo^tZMwWf{ymSy*Ll;Bi^ z{4azJ3-`_<9(Js^axI!K7jzFt65*kU)XqOYbcCfyh-;=k9D|=7vqA6<=R`I(BRs+M zYj+uVFl7^#JEN4rQNVt)wv1fH%+F?u70GvTPz!u`fNwy4xZ%cQ(bW27PV)t5#pL>B z%EH{x`Jfkd$F0yIRTf^!uXrb~^0qYZL$|EX7~pfEH$}LNY9^Dp2a~x+iHf-s(^}@Z z0#Z}+x(ZhnpX(iPyDcMX77%Pnji`kitge|f5NZ7N%md2Dt7Iy+;T`)=5A7xx3J=C zh;$-yEb{cs3rpS++Ab9@9oML*6qTs%%bn@PX?O|bcl1-*n>tJv0E!{r32)Z3Z>_Vl zP+u$ibe&7QihZY?Uzr1A+WGaRfw360U1k3DB|ZO7mb(kbM)(kZX|vTj7Y2b#F&mp# z3$^SQ>vxicY{@+jCMgypvMn?ai1x?)!EF-%&g)-Lr+i$E(^70Vb;m*y|5U+0aq@3m zbT9hxI07%XctwE+3s1Fj?o!wy+c2YJgouzx`DWvx%3aLut-5_}W#i((SZFvRwa^t{ zD*UP9X2NLerz+hvDZNSEMj19)-K~g&;vXGuZSRZ(v z*S+&3K?zQ)6aScZ=gyrwckbM|ck=KR^8IIt^;Z^4fdIew#s8Zc9K2wyB(oP9A9aa> zBuEAOUHhtOwJ1~ywSrXW6r`eYGP3O=sj_)E$pR#6mLzhL4M@crsV2V!K1#FwwYdFnZj9Y~cKlBZ$ZTq}$>NIJwx-SzmJFcIwdWl*rrD8Fe#uG`I{X!onMTfDOK-<=5Gs+C1}j2$Wb|z^cv}EZuT3~*GMaS(mY^v z0lS60YktAB9cA<`UdcPF+vbM$sG3LRU^o$vo}rEKeVM5FAw>y9gUY(+a8d$745K&|Kx#>0_tFe&c=)%}4$Bpyiy z0;sw24r^;@Wgod~+4qW`97jDb6FP{0@@O0Up&Jp}5jqfh5l|}K2B2C3n$96P8Vv+s z=wYBL1fY*{1suqVP{h7#5j8_NSjl<^Gg^aW3!Ak5*mMW-_*tK=DvcJVK7?k3R)7Ou z%bJ>$Aj2jEGzjfP*n*%(;4-&j3-#oJDBlIH6<x+9b#e_N zIGih35(>rxNg9kRkz^zR%>PSr4-h{U}HKD(M9mrn(hWN;Gvo;_`^COzzBdmA~z zKD57jADYHX_{zKmYnfX$2Ljpp;$TYnUZ2wRxn(WII6DBt>* zJ^k$4juLWW@%xTaLMZ#GvyU_~ca^gkfmCclru>6` zvOj$qrL$jGeJ1NcY1jSa@D8NzMCeD@h45JfJoj`D!sigqA?yX1we~}7NXp`n49kyC z(g7e|wk$gw%}3TjcEDZPv-;#?&nWV1o1Sqwq;fw)vw@rCeC)Ej+VmjMl=GP|Aba^C zxd%s#Bdp%kG!hX`u+Muk=Q*9()Wfdx(1FJ)_e00V->(G1F7$rZ?bk^K-DJEFZyF5w zQqg7%7Vv8$QUM$4t72C~Q@JHemGUzq@<*KPhM|0uRWc)IH<5IH1GP#vYMU(fmZ*+V z8icSGpBw_y(MT}LL*0;^4F3NGwyS0zxYwgK&h;?6Q#u{#djVk|R83?<+@o@CF~ ztk*)3=1s+GdQ&NA{mI@$?ZBeujg1Uy&Xm6=64m_bFSyd2Aee;XD*;+{0j#UAsk>osIPYOxPz`mF9Im5Jt?oDmi#?y zZg~7JInZM$0^vOSMMK7c9s>vZ5_z6IwSHS+&ST!ufycNEZGxm{;yy=-K{84v$?Vrl zdEF#Hr2GuEKq>?u(P%~EX7-q!k&Y)*Ov__BkyE zsVz&;rp?by%WgDQbsMCO*?y_ruis7J_;tYX+vMG>mhDSS984$}ua*zqzr!wj%jrBD z^PVrZ1@RIM1^ES)qEYsy_Yo6!(?&M4q0NcGogYd}jZUN@R1Rx7z}MMx8+_Wm@D1d_ z?7*vC2J|H)d=ufH094aXP$3bg|BN5Hp&j%JG-fShknYG~QA)xwS29CYy>xPRSxoMCBHd%F0Xvm?k1o zxN~KtMT8tnluyq;?=`2BvEi{D8v!6fuq1pJ)cIT%rrAVFKDcp?>yMvi4n1A>&} zk!TeD%Hfn|E|8th2&WM_9+E*cT|`MG^_^`kZEbC$Ppt3aE&45__wJR0(d3jEi7P2c z3qoAsB-k_t(M_C*LZ;9nCR03H07W9Pi4;|MCrq0R`RQ{grC}E+*hLJ)QK|3lRlPNBi_m*UIN3(!_Uiu$wYjd6H3pm}2EYMtOq~C@% zJJmdx*3;*a{BH>8f|-5=WSe#d@ny-6KX{+eKRk&4H_)r@)*rD4eHFt4I=;veAXmrXT!BqDjRsWG;Iu7C8p}~&K^@cc zY0lz@*|{k|!Jx)6rDNao4HUn3KmUBhtW_+%Ox(C`vD5z?Nn@0owT(p11jADz4_a_Q zc(|J_l7gvlMBG7x6OkYfd{A~wp{u@(kh|U0JUoyX6KDiGxZCqmWvzQ1I8=KswzKIr zEAg^3ZBLQyi{i!`#FRo2Bh1`UXE}+@(*Rg-uq_=}V2pKaBHfD*cf3Z(JUg~|s$Jtp zsrslKr&nIdoFgikbdUtJVCazh0b4+XV@3F>?!4Z7`t

!FB!dnP9$tM(HPhmF##zY0{=h@Sbj*J-)rQ|v|$B_|h0d;3Y*X~@oDKix1+HN=DPX7UVsy05DSi6eS5M!? zF}R&{2|>%c*RJ8#A;WUO?!-@A)^g}p^G4;HBXL*16W@}Ne!sI zL+R+lC z%{u{k;28xT(%mgSo?l&nwRYYT9Lm{{ShZbb9qf# z#!-wxh^_Uru*XB?TG z8~n~BJ`T}x=<%ADF92EsRMniAn1)nUQBB7pQApghd%%pmT7XjxN;EaO`T=28gyZjD zZgzcNMSk{G@dxa`h6W)7R~~qx&5q*qG=*yLFshHl@wks60XtQFICw@uXMw0md)ONX zc95U2hT%PST%))2W1G)DJ={d9+1H0_NjdxPVMiBASrH-Y@$>d4#Dv`lPczTK)0(MF z%rml=y>-wGMFro#+q{ad$|BeDOukD#ko!7& z@lfT!DnF+>)NIwpHX{w;HTaivW}UI_mH?nRb2Dgv9~&I)O*@t^8mx3uO0E!#Tt`7K zpwamvXe)lNnvCn$0UgM!Sb-UzL?LaxR_Z+Oe8i+p$GJ2it2A!tLHQd|GQ!VLO7{He zj4o8!MYl8O$PjBEb&@y0*7r(pBKwMvzxJE+s*rzM>uv#QZ?fNy+K2xd>*5m=MR)`L ztx(m2s(Q5LV)p@WGYgHKBAx8DvHR1iBRn09PbLCN?*Ab8wWoMRd+o^|N`z(p`oy2T z=}|OG8sRYnejoEdjZsQ1-U;4y9OESJmIN_~yC~mzZcDD^@>V&~%4*)WSR$N?%009n z6omf-P+khm%&ekyd{GBN+%{bjQ{;=)qnLg1Ew?OU@(_NBX}Iz4gC cZC>d8O7ATJnz!=w#Dm%CSJLmpx3>O20XN?yNB{r; diff --git a/recruitment/__pycache__/models.cpython-313.pyc b/recruitment/__pycache__/models.cpython-313.pyc index 1236c5d99bd4bc5078e1e9a0d396dc65e516cfef..3c548915f02847e1d87087313093351a3b9281c4 100644 GIT binary patch delta 12762 zcma(%33!{;k@_WDmM!0w580M2`Iha(SM1z}Ne zB9$#ES7l4?mDbM%M{dT^|J9}BFggX%sS)T>Bcsz0o!)C~)DUZxO5`#&1F?n(;>kQl zXCgW)f;gYC*@(@Fz?v9qL~L#Zwt%sDh|Q0{7Bbd^*n$YGnX!e4H7nRjmd(Ow3!;l6 zh>I9ojM$P0Y%ya?5nC34En#dqVk;uBrHr*AwlV@+#@H&vR`(ji3Myyx97NBJP*7b3 zqiYad8^OcM*gC}4M_?-l8?5tSO#M*0Rg#li*0wp_ey?b3ce^}JNYUIQrNX0{_a!5I zEv7Xgm8?P_737%t+7j-<$QmQm#-5Qf;horPq)MpJRwL}*ZG=&6p<1N& zQZEkwmugF2sDbAA@}!xV+xznKi&P{5{i~5|nM|IwFh*qcYVl+|ugf$NgKT7%Gn1V# zLYmGPC*f$0%?O1FmXutZVWCFk)u?QF>m-p+{e$RW-)$2NDNR@C%r zL8>;)MJ?7KvbMJlTXl_+qAu>$PxovM3u8q+vKb(TQXFhbEYxVkJQO1zAh9qmMl|9m zZ=-)&=q7giMd<`{Rn9p+}?=yN-)Y9BJgpA5 z+mQ_msUH*W5r>$t54$ErExem@o3stSmbx}I#8fbst?)tWid1AloET-5L=RM@jp;)R zh%NAFTD_LGg3Y(mL}oTMa|lEdxzatU%!WrQ74nPei}fMiq7uq87SEPJi7Gn=tnj^z zH0c@mc}Deijx48jQI0-F7O!x+1lmf_8gj;Nm+15QT&za>m}gu#Jker~;CL~HQ=Wlt zgGq^Vjo>ppTf`wL&ThwmWw*=eVQ-il#JvDLne(L*c(u_8Co}zt`;d!|yxA;Dp){*Z z`WbW}ESd6U{aBLrLVZqgbpVGy`W*j>SZv9f+9szpNf1`VFk;lZM~<0rIfPgO2Xj{B z-$2+HhZyw9+TlIQ-!b7DaPJjggWu*X&Lc6!T||`g+I z49qKb%pv?fADs^~30j!HNO}jh=6^+@gg@o~XZ8_Z)amfM#Eeb7XDX9E27LkT`lZcA z=q)&(zX)m3J?^1D@v_$EclgJBycux>Ruz^>i@;l$nMM-MWOjFcPu&5S@^kSc;1afozm$To#^orROZYlY|@aMT*~ekbdB~;$niaR z*pzg+wWxYCyUu>36JH^~J3L9P#|cakphP4m+3o!vhtJpV@_6j_(~`I!vFs=-1Y2(j zkrJqWYk5qnJXS&|3pVyiVV>k}zH!?IIa zOZ(PYr&6IqB3#1f_k zJ;6Xkd{nLatE@+38Up7DSP;mXo!&lCK&^x^JhDNqQ4i~zG>HHS;-iC(^?@$=b)E4w zo$*-p*{pK~PZhkl?N!}%2U;$qWxt+Q^jcccsZFn@H6B`{ln`&K;O)n9rVf=gNSRV^ zGA5w3P|8Wi9F_*VDsyse%239Pq4eIE^<}Wjo0&q>456`1uvD1RvY1(R2%8SqA~uJy z#t7^Uh|OheUI?2HPgIzUCdL+ou!Sg295TPiLSwWZs=Bf!VrFesG7Sq)pmLm;RWQ6)nRA`9#TykKkfhETRE;bf& zv9SoLS7PlEB43P%mWcimTPxQjZ4os|yBy!*7Y&oHAuVVzopww{**QJ$w6cg}# zry1|7JGS}$#ZXaWh~-!YuU6;6bu~R|cLF?Ble1CT_CFCp*WA+5*4=|b=+?KbX=}k& zR57$c5&noPCqQ9sxuS``MQY+yt#LA$6cOJ%Hs*2nJ4XHDA`*PLBI297yE|65GkQ~WOsUJ5rYfR5$iixeUf*H-`0e`GtYrGCu!+nut z)}XA^79O~+p-!oD!>pCM7EUxcC!J^w_60d1bWVMWUqr83`G6?;8>a=LoKB@c%|On? z-Is}EH>uvp&N-F``wu6+QBZh1@qX{Gba|NGVvs{4ReLaYdS*YFHSe)&l#S?Mpfa;x;jN2z}nK-Y@5mfsg zo>}+0nyRERINDT-b?>>RO&aMzNLh4i9vxAuT2{}km9@dEQm6v`-lBTx7WiOM)rtyI zpp^iXNa8jGvS!fbmy>Nh&DXTqZEfo|v~{(#2|W!zOyCm&WJ+|J8({t7lB#MF6?K8- zEfu)fkYoEjF2|^x65cr@c2AvH{GPO`fffYfb61cLweKcCRjpF41sNVtDmEgFR3w$# zx53LxsoKA?v_$G=UoJ<+r?rB2721%fq2+j!wb&xDiCO%pYY$#EC=k~XK|O+qUBJ-t z2I)?CVEF)=>YZleRQ`%YsW`NXSU{}Q%!=oS>-)9M3#I$vtIb<^;@Kins`xsAw`kqi z0Xpe34gTGgrKu0o`c+7AKy`)cOn84KniO^&G(t(sxGta8(})&0(PF5a?Pl#bC})I~ zEnL1a@2Jn^dko%gsbybVFv%PwQGm2FRwv2!lVoXO2Ehy0w@D_&2```%?!RUKd7VkA z>)5}pzAO+k4KdSG>E5E;(b;DfiqB|}Lc5?SD##d0Rl0<576O#NSWV&_wQ`8WcxPLI z^lK<=%h485{}-^dt;R$i$VQb@9n)!n%t;CDIk=_mhm)@&g`D9V?;COZ{Vu1yZz6cD z;1e$E#)KC`y?=rasiKw=;?Lem{w5YtcPW7u0;FZuloB>B5Xl<|_`nBm78eOg;Pa^$ z+V^S_W2D$l>C;%1Hu+Kvw6C!!_uY&1uBXnIVELg+=#9-Z>98`4?bRaGhU%g?n+~h8 zc)Tm5ZODOl*2L=LLt_b0u-25J56(#p;gg_i?c&MgP(KCh&@`^CQn9v53)NQXwsb6Z zGHe;bFlex5%BelV;U2}CS0`OT-42iYEN%98xDh$F$L;sH1XTzhnfrO22r%UfOceqD~MH0?{zppK*FyK&_GLXt(jN1VyfmmTtkbK_5PB8Sz7qb zJ?;^g&><69*NQJV^i(F6!u9K_q(pdZ-L=XaQqWka?qE!jWBt6?RSHMWa>iD#cOG9Hc4)Nu&1ZBe{9Uq{)zYs$lg>O^l%?djppG;kn&Hk zeN*U_3{`F>4;Ll^QPpjL%LfhFf5-6%Cl6H*lub;V7Z>p{QS;*wz9(S1_KxG3j${ad z&Gl-P8lK#2!u;{l=J)4J&l#YfFMQ%CE`bTKiX@@r8cKk)n>p~-mU-$JH5j%o$hw0_ zt|2gEfxfNvYKh3H1mqG(qiWvl9WeWcTxO-xI1FRktmqHl*mk{?4O!buzRU%V<1*Q> zeS63S4sIV=wgyX?cY zCunnA-pyvvfFp8Bm;sk?g^;+TJknr>Xa*Da6IYIzYy{Szg`|3v2F_87g{H$QSOm6C z5?TizTk%QXJ&IS|kcE__9I{PrL@s!c7!rt6qZ96f=Y56n@eYS#CBpM@9d_u{xM_cX zXKg16Ul=^jp&U&8EfR?1Y$F%4y1{z2o|20A zE`cd%bJt0`V2}G&+@*TwP!^lxDrbNLI}OqR+`aQNjt53~WEk2WK@M0@b8*dWCV)#P@_@EkAy!gc=$*mKvUE^+aKh7bFTRuS(b`W@m0Lc;| zB+JK=va8aGiKq}~g^};jD1j34)N8SElj^cs9jp6;E@A42BkfWgTj@IzjIPOY=h@GojpAXZt56zHGd!2bv##^NJcNwPWFx_2#fg!uJR0-EJ-n0b~%}xB`}Hd;xVVvI4fNVrtsQI;M?u+jJw3s#GAv#!z95+v&Dk{+gBs~7nI%Li*(7`2?Ea?nke!0!(jrOS67tXrW351E+Fii9lKXE<;< z(i7*9CpJcS;;w`Ctdlf7(kE!|`{DNo3#HFMdt-5=2GgS+if}1nrn$2MK&U7j8}Gx% zW$_x(P*jlhz9Fmzoc29#|4>9FGV5fe@P+geNlD;6ICtZqawWSoRdOg*qu+_V+<(S> zifdu{O{ESl074fp{;@xxw|U1!zspPo!*q?nXL$=rvjIUMui5Mjf4?vty?s0nr?CE& zDe&@5wYl6^E^5Sr`Mg9z{tmKlUY^N9%%*|in{UQT(Wf^zrgGg8mS8C?IJ_d_gMr{e zhYz=BhSN=$d>y=dxXb!CTn=|OG1_m&0u-A_L^{F(@!hJ+*K+9ql) zfcZztwB(uM0q8$6uY&KWd}yKxMSJB9|9R@!BOgkN_wA%7rm3Ibc1|sIOzpqJC`s$! z*wM;36?vkhhF>0CKBx$t7*%N2NH!503GlQ$YMBTW5Qrj+oYahWEAQy^!(SHCtpo3! zb_c7f5W8}!8()wHmB$6U$2;g_*+nc_lj>$!tMHgU2<$0ro8RGRkF0AOb&lap-hVn+ zO|u_YLJgGQX9_(~qfa7Me-1w5 zeM9nxyBA5RWjG>8af%JHVadIwnYq?=Z>_W+?zwj;G8Ps^wQ4vPt|j#_TfU&N4_QbD zEHUfn9CcayB!jHO@1mO`?)V%SkRFyuv=> z^7-hMT~7mv@Z_;M^*m8#$oOQ#?)e(o=O`fzY^WB>4DOwL2L$+Z7z?i-)~mlJ?I&dorr>&tnc$U zMu+WuhrwDv8K4-o{7Yh#VHJP8qR25FsqP^OqeiMEIP}eo*86CDlw?X#rki=b8^7{6 zL_)KNiFn!xH6!Xujt9$d;69MQS)tgTaf(w$uZD58t71_yyoLEb#qDwR`P}%_z?O|2_4-jjdPSx8PkKA5nGkfNQEoq97^=u@w zcxmLRh#u=grvg7X!r6Q~Rn7q|E3P5sv&$Bf__NH=N}~iGLf!i6kph1%jA?j>zJ{^9 zmS#B(x1T6cYAB-Os{geUE7e%_XFjs3gKl&94G;aO83;bY(vPY92pgbK$G@!x5;u9p zFg@P3IwpLA_0xvj@P}<*|B%Z$?m=^W3a1}gk;aj-hXlP$!oMUzVoMI(dTp95}tJTEVW1f>`8KypYo$}{;ofX5e0PWX?< zbCcKOgdWs2+p>yo8IbzK?Pfl~|3u~R>=T9fi2U{w^^uy*|5r47kwml*=%elMB4+CP zPzX6OfRFANdHKPg_lno)phY9pz6ohrvvNl=Wo5R!a>6+H(-(me8eK@;FI4MBl7qm{ zrhfD7GAWS{H}$)$RgnB-iL@0Oo*akIPFv^=lP|F??QY(;`0v17-NBsPg(aRRZOU?~KM8(Fq~CnB=ttmFhM zr8a@13E`CvX`uv2piojC4K+tYcwVo3<-Sq~p>5KimckVZX(`YGSMCmuo0(sh6i1XM z-#6Z!-JO}8nVp&4U-$k&^VFM~jE~aOQ{(WTY2r`Yp1k@%hDquw`p}gjJA`}-VOpMJ&tRV_(W^4{(jZxTq#^xe6 zFA7`0SQBE+QP@Jp<|DR1#m+E03!@7WZHby(#MmOl7Dr)=8EZvsNfg$~*iyunMPW-A zTaMU@C~PTXD-l~YR3F)M8KbKaZHt;*&e$5n*3Rp!p@MOX5VtsLW+h|m5L+LGt=hW8 z)&Tcw?uMeNTo{j^mD1t;__rk!{4${@HItN0ARS5*TeW4}1!v+5QZ`g;*GM*))Gk8! zMz$Fq*VfFKae_mb5DwV1f_fsKKmmb51WK}N#2*l@(SRr=98DEWwwy*2`sIL2G+>j~ z`jZe`7k9>xw?A2()P#r-`Scj%!I{)v#&cp27nQV_KsG#+bg8=GO@NB9nf5=!G*NlYeU%h0{ zwI|{KyyXcZ7arAFP?tX(wIDGwFEJCbqZ`iq?W{&+q22#&@J z!YWCl+kBo;*{>wI$P6t8?m}&|ETax20XqAt7l@= zJLN_eRw4T*eG`7qh{x**cx1oTHQ`3&jwz3j$K{ED-zF(3+hp&gGaz3X2$l}2LvHJi zDVNtX<{5PnL3NpbyT|MGAJqsgNh=)iN=C6YEWL1$JXu}xggoX6_^rONF37iM)N*d$?x+p{KhVQFwrIr>H| zuXaG6UKn$UP+o)@wH)xO-kZfb;1QdOT%X;hV##ZN;!t79&2t?3{3o%g#yflyG@tg(uNOl8hrb4$l}YY6NM5Hx189 z)8~Bm1DGQu-rITWE8STFw?O$9ZU8pg$>!)*o;Mru;0g*b9#rRj#E8N@mE#$mg6> z!poALLzreIO-_w?J^pPJLGA)0my&l=?hIH%di;0|)(t~?toVbtrrf89)j|?+bQb&c13*63; zX(hw%=yYtfJGIo&Y z-!(Dq@DWs5w-7dcn}=M|>Dnq!j84NZN)}zp{WtX1GcKkJ7W6;j7 zLu78@X=BAHW5t<_?2|=ZperlMLTpy<>CEC&nZ<|QCtKD+YgwD&OmW5O;`&p?^*pf~ z30PsatS|97$H|K~&b?Unv6RG#y)6!Ie!w)hvTCVh)DLA~CddwF0s|-4H>%BgbtES; z0>`RLbjEN$7k*o9(dY4cQy6Q2RGTHw%-H-07OCb9CBX14x%pVg5zE5xpalobLkWXT zl;MpqvMxMc zi$z2^5Z9+_^NbM+_2C(dVX`*Db4eIq3x{i?c{YSch-cM2&-{6wjp1?PS&ie+Fl430(qX>%63y6O8PyLJ5?n%HF@Yt-GAbqJ3kjT!r9^mj8}_lN z2=}qLz_}OLd&NpFF;?lZ##p1IbYqtHP?S9T3Ea5&pyt2gpuDaeZwXZQrk)p)5G`6j zuB#}a)4H(cO|%E_$cxu-2OzCrl&`RR!akLMHV6Iv=;HZ+gVViG47JbxC>U6uY zX7mS>5l)TE{(40_$Ss>j7;px!>kX#Qs95U;mq4o{H!hlps3Vx6BCYnRaVpeskn1Am z$a@*UX}B*Ikk@h1#^ayjP%ta3Fso`IysYsQp3KYEM~XID7fc~fu~N3g;(5WCj>kfj z5>-k}Bx)W!ymX!UQlx~cA!%{D%#0=XfWE0gtpy`X)Y=aw51L`JX`Si39yDWzq=jXfg5(GaPR5om&_dwAM;vu%@*F%eC>=P4Utl@cfGF z@z%JZ&5VWR6>W{u4BXjPn^j6GC?jwiak(DOv=wC^rsmrO$bx9~ASAb!XIA1gKNXNx z{D*0wt-V0<&TVRcOIo{_DBMCT4un=v`&$Hn01=;GI;++XG%{#j=Y>|LOEM-F8<@9sptECBx5X>_rd5b!hN_%0jV+^%+ zQvdXi&5v5m*8oRT<3 z$M{?;ZR@VcxSa@*x6j7Cm1%)HyU`->)TL(lZTHmTT;donR^lHe1rIM>`|#!%@A7)j zp+u}Y;Tt_B=@5LUX9*jq_H?>G7UF>W8XJU zCR@~Z5EEi;9WfJ4JQ34TsoSkyZpk@T#EHKkUVK7;0-_*Wh?l6iLC(-!;Q89NBh!(-a1~UgT`ewi%Qxhj4i&u>SAI5G(M)?zxXPOle0+ba(<@S;Qg2 zp(J(tCIa}fAd;{fOufY8mVMSfyl(^z_^!qzobb~=L$!gFkxhUDcxtzLb+L|2qZ{WE zo?|UO;coaOPV|?~2h1;;TZ`sBd?zhf z7&Ui8>wsnEF87hm%5Ww;iRjV zScjaHgfVne)yL@}QMA5H@HqmJi&czzLbzz-1jq#bn;~_5LC%?soYNUar!tBTJD!k^ z+n!8&C1W)-uXn2|aLwJlewAk9aatHMnQziF$|e(31UQ1J{jyB2Qq~K5FoSY>tRqp# zIRBH1$x{TZ4$rtOG)P2A?!iY0x;KleHKcPTF~Ho;*Ls%S zH1lf`%0qz5A-1i}{7-3`BuO1t<#u}9q8VjXQt?cSfHOd{zDS5<_q?o>Zv-17`3fK2 ze(BCHJr57q*Gik=ul9nn$oXC1R}&;3f#Y-a4%{w_Ix#oAu}hK^xc8C{-6KTXNT3hi zzobOV8gzhhQRwGQP<7UXslBz3wJq|9`1zW?;Zk$n-*70(zo++2pG-Ch zN+Av@7xb4I&&~Udmo-{HA?CEJ**J>vyZ7xrooRg~)B0*=>B;0$T>GfS40m4kVk74d zjiMc+_Y1$c0oP&vs~}-0w}$f{?X(IJNS?+$C+eIK+ddT10 zsQFZafz6dOQT}0y(k~b&)+VywMDQ7ak6ZInw;l{n~htPJ3O zj%t+TfIL3wrQkhFyNuQ`^~v)UeXmc@b!)3!7s~N^c*|LfHA2?#wM!1s{&cYxQ&Lni zBa279vTGs-emYzgZL^$MHWS|_s%$T|11r%=OsKq2!|E(`=_m^pfen<72Aah8WqfR& zz}sfnNNR!(nJHGPkVP%BS$hrjH$b~=)^QBry2Am(a-MVvTq&2M zvG0`k=pwfZ$6U==m887{jVcbormdExUlA34gdBMGoy3YyMH3gHPi}41=pH2G!vr3I z&pi#27wWILUiu!KxMEu^>u;gyBi7@ZsgA9;8Tz+>f`+H_J>-SecOyZpjk!){%aBo& zM6YW^KEJ+NA3kJEA4 z27J(rI1O9YN)E#EJw~l(iQvB?P;}__qw+SN7vI#y^W!8p-fsC5h&#%y?xzKt32>Su zS)znw`B+kRHPTsBwYMO4KR}}d%yYvNmxkUMACO=;(KL73XOOgQIOds!4=2}2Mrhw* zF3cs7IdgJFM0ZQPh*lG}4|eP*K-al(MyDFDU(T&-$HX!92?Ug#5S!CXGkQzPRZzaLZmd`$Q*Tiu>()`3BpuSpj3Ku^o{gD-wj7X_YH(9X;NBG^oS^YNTl<7Gm>iCCGe$>Gy zZ3_ak5C|Mm&wU%8`=+T5NxBQBcJ^vJX_68CZD(bPjGTk%_zh~@ImKt)Uymgz*Q=_D z_Qiwtznh|_3T_HUS#$ZWk#fIRfssfya8j7s2EL=vLFM^kXRxGzZ2+}(n zU7BlmPfA*}=UF4?`s1bA7fTEQE_M{=haWPC~;qxz!O} z#yUWMCYcEQ27K3SRWUhRj)3EtG>A;pZn@{h}1;%#Lr0B zFW_h2TxDcV3+F(=-fv1<;NHE>SzIB6CBci?j3kc8^bG*}25g@q zyP(cKJuy1}k{bF<&U^<+B9#r@AXfaN8w4pMLsiv$R9S`@SnQ(>;TPJ2wNTSv3NKur zKh{QgQoWL-F7T^0ry3(uV!A~OiNewgYV9Bp%h>D+@o3RDSi8TXpWTgds?X)eB#!cg zN=arji(N&hn#~!YC;8(v;R!ggze?Lo%~p74f2Ee3QG5psH#AlAL1sR&grdFjhTos_ z-SBSccDR+Eaprd3^ka?GIahbUEJ?kv_FFYcpOL~omtgu^tG22_r^OVSMKzG`8VT^S zJZhN<xE))x>!{O*j2JT_(HQ)y}vuXzO8>~J4jc^~7j`Ba{2t1&vPihKUYA6B{5t^+th}{W zN`@{7mEPO*~CCvFz#d5Gf+78PPwqUxLJm}L-kYD-W?SoYVs^Vh1 z68p{qe~O_gwP>h7g-pQZ-?pi7qltcMFn7;W}SbTeSaW#obj;y3(o$C`${CeZ3FLy~akPKUHU)&gRV@^snG*U|3&UGS@MFRvn z=bpa(>QDijrGdliO>B4ay#i|hb%26X$5#cXoVEP> z1XYmv5VfB~JTFA0!_vD9JvY(Vb`mI4U25gE_$w*)PS(kQNTh8nP!9)!6*zDcTz^-! zYW=7n6uTZqZs!G|40<8NL*T?1^TWd{ z`M7GtG-B8X)hD&{jwupS^j-LPyPci~=N125xZ_Ag^tp%~4QllZq?!O-(2eLdvo%^*cM{+Jj{+vF45=~=YLHSHIyolfNFP*VJ(+hq5Y z7me{gTy|fFo&zK&)Ava9pGolar6%~veVbOaQ-3EZJf`x@7h*UTJ3aC)dx+$`5+4Wq z{Uy;#EcuGy!Xc%NI9UlW%RKwCw1wuh(m%3dHD!AR%q+nCT z5~OQIJ3_Yhix)xn{hG$-h@6@;sr99{T0^7=+%>oL`z4_ixn}OB2U;}J33&boU0N~- z{)8<3!GeMmQkVuoFe9uR_3?QFbU)aJpDSk`%+I(O7dW_}LOa&bg#w;@@K)BXOrpp?HfB%ZO}R)Ye&ptYoF7#9e#3VjzLRj7&FPA>1IH6Sfoxh9 z#6*-?gmP>t$?fAlIw32?I7%cXBF{e_ delta 20 acmZ2&wAzUKGcPX}0}!+%yxPdEAPE3I?ggL# diff --git a/recruitment/__pycache__/urls.cpython-313.pyc b/recruitment/__pycache__/urls.cpython-313.pyc index f3436fb6ed11b4a575bad585a1b79dcb9f954391..08329cb3946205c7585502a1a76891b8deea6956 100644 GIT binary patch delta 1770 zcmZ{k-A^J{7>5}c5L`u8WW>sc0_wEY0g+kP75rADtH`44`hg%-s<KeYWy-KC=rdHVHh+A^)}QAMaY!7N#h1zD-9Hj(@W*^r{7vZQRS4so~xYTPn8Qe=oczg^p0%Yyj9kr zTk7D)>z37cU4_N~k{Zv=fih`Ox|K2D*EBonXzew(G*ae{0s~bKPBnOUr14T}z*RJ- zCgbX8_?o5RvZYhfHj!(bNSSl*O%C|7;>R$4adAnBU(;r>tW83464y9M;^aN6OK+#Z zg!U`HYd!bA+h54;tlp7_KKIU6HkVpSW;Rl*>0}|Zv6W4`FAS1(HAVQYS(*VaDjD!f zo1i#g*EO=Kt*vZkIklb1ZMq9P%ggCP;lfxpnY@}jjp)A9m^v?RtgNRtS99D>K3mAE zq`S>KfZi}tldqEUg*LsC*-py4qzrXcdHG!OMj4m^RcQoY7;>6MdCqeBuYsWq9dhR6 z!7UFS&{FF%c;(n74?cO|!CdV^<%|?5=~MU({9Ma4Oi?w;KWOc~4uhWWa)>N{&UNqFg^?EIq@FRqCm&kwbP`S0UpMlh>_wx zX@F067_!5{d-IT95FZd4#}8sXR3kGB&8*<=hxCBBNMM32Z8~Z>=ALn-JxGsHVX+`XmGW{MOx2r;J4F3ZR`<;ZJTkUJW4q8b4(X8i5rH3*KFvowat5F? zAdKMm@Cl*2gtnig5f_DARG7o3{g}{C3GFQLs4E7$q~F3Wq#ui)5jv7l;xpFz7*_Bi3&xA8du6vNGXP} M^yEf9D*aRZ2VrpQhyVZp delta 1391 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 delta 3383 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 NE2DFL%1} diff --git a/recruitment/migrations/__pycache__/__init__.cpython-313.pyc b/recruitment/migrations/__pycache__/__init__.cpython-313.pyc index b67d53b93f0a33df30615d946798251409282d7f..6b9887c6147de6454a71051204a7edefbdbb4abd 100644 GIT binary patch delta 19 ZcmZ3^xSWyuGcPX}0}yz$yq?HC2LLgs1!4dI delta 19 ZcmZ3^xSWyuGcPX}0}v>8J)g)u2LLeG1wQ}) diff --git a/recruitment/models.py b/recruitment/models.py index a6df23c..a038f86 100644 --- a/recruitment/models.py +++ b/recruitment/models.py @@ -79,7 +79,7 @@ class JobPosting(Base): # Job Details description = CKEditor5Field( - 'Description', + 'Description', config_name='extends' # Matches the config name you defined in settings.py ) @@ -118,7 +118,7 @@ class JobPosting(Base): ("ARCHIVED", "Archived"), ] status = models.CharField( - max_length=20, choices=STATUS_CHOICES, default="DRAFT", null=True, blank=True + max_length=20, choices=STATUS_CHOICES, default="DRAFT" ) # hashtags for social media @@ -250,7 +250,7 @@ class JobPosting(Base): class JobPostingImage(models.Model): job=models.ForeignKey('JobPosting',on_delete=models.CASCADE,related_name='post_images') post_image = models.ImageField(upload_to='post/') - + class Candidate(Base): class Stage(models.TextChoices): diff --git a/recruitment/templatetags/__pycache__/form_filters.cpython-313.pyc b/recruitment/templatetags/__pycache__/form_filters.cpython-313.pyc index c7fbf5f7ce4beb6f0b1aa2def5dbee529bd028cd..9436ae7db28a18169b8629dc071206f69fd81aa2 100644 GIT binary patch delta 20 acmaDR{!E