small fix for the form template marked active when the job is made active
This commit is contained in:
parent
e3435e3627
commit
d1dda003d6
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,19 +1,18 @@
|
|||||||
# jobs/linkedin_service.py
|
# jobs/linkedin_service.py
|
||||||
import uuid
|
import uuid
|
||||||
import re
|
|
||||||
from html import unescape
|
|
||||||
from urllib.parse import quote, urlencode
|
|
||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Define constants
|
# Define constants
|
||||||
LINKEDIN_API_VERSION = '2.0.0'
|
LINKEDIN_API_VERSION = '2.0.0'
|
||||||
LINKEDIN_VERSION = '202409'
|
LINKEDIN_VERSION = '202409'
|
||||||
MAX_POST_CHARS = 3000 # LinkedIn's maximum character limit for shareCommentary
|
|
||||||
|
|
||||||
class LinkedInService:
|
class LinkedInService:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -162,113 +161,114 @@ class LinkedInService:
|
|||||||
|
|
||||||
# ---------------- POSTING UTILITIES ----------------
|
# ---------------- POSTING UTILITIES ----------------
|
||||||
|
|
||||||
def clean_html_for_social_post(self, html_content):
|
# def clean_html_for_social_post(self, html_content):
|
||||||
"""Converts safe HTML to plain text with basic formatting."""
|
# """Converts safe HTML to plain text with basic formatting."""
|
||||||
if not html_content:
|
# if not html_content:
|
||||||
return ""
|
# return ""
|
||||||
|
|
||||||
text = html_content
|
# text = html_content
|
||||||
|
|
||||||
# 1. Convert Bolding tags to *Markdown*
|
# # 1. Convert Bolding tags to *Markdown*
|
||||||
text = re.sub(r'<strong>(.*?)</strong>', r'*\1*', text, flags=re.IGNORECASE)
|
# text = re.sub(r'<strong>(.*?)</strong>', r'*\1*', text, flags=re.IGNORECASE)
|
||||||
text = re.sub(r'<b>(.*?)</b>', r'*\1*', text, flags=re.IGNORECASE)
|
# text = re.sub(r'<b>(.*?)</b>', r'*\1*', text, flags=re.IGNORECASE)
|
||||||
|
|
||||||
# 2. Handle Lists: Convert <li> tags into a bullet point
|
# # 2. Handle Lists: Convert <li> tags into a bullet point
|
||||||
text = re.sub(r'</(ul|ol|div)>', '\n', text, flags=re.IGNORECASE)
|
# text = re.sub(r'</(ul|ol|div)>', '\n', text, flags=re.IGNORECASE)
|
||||||
text = re.sub(r'<li[^>]*>', '• ', text, flags=re.IGNORECASE)
|
# text = re.sub(r'<li[^>]*>', '• ', text, flags=re.IGNORECASE)
|
||||||
text = re.sub(r'</li>', '\n', text, flags=re.IGNORECASE)
|
# text = re.sub(r'</li>', '\n', text, flags=re.IGNORECASE)
|
||||||
|
|
||||||
# 3. Handle Paragraphs and Line Breaks
|
# # 3. Handle Paragraphs and Line Breaks
|
||||||
text = re.sub(r'</p>', '\n\n', text, flags=re.IGNORECASE)
|
# text = re.sub(r'</p>', '\n\n', text, flags=re.IGNORECASE)
|
||||||
text = re.sub(r'<br/?>', '\n', text, flags=re.IGNORECASE)
|
# text = re.sub(r'<br/?>', '\n', text, flags=re.IGNORECASE)
|
||||||
|
|
||||||
# 4. Strip all remaining, unsupported HTML tags
|
# # 4. Strip all remaining, unsupported HTML tags
|
||||||
clean_text = re.sub(r'<[^>]+>', '', text)
|
# clean_text = re.sub(r'<[^>]+>', '', text)
|
||||||
|
|
||||||
# 5. Unescape HTML entities
|
# # 5. Unescape HTML entities
|
||||||
clean_text = unescape(clean_text)
|
# clean_text = unescape(clean_text)
|
||||||
|
|
||||||
# 6. Clean up excessive whitespace/newlines
|
# # 6. Clean up excessive whitespace/newlines
|
||||||
clean_text = re.sub(r'(\n\s*){3,}', '\n\n', clean_text).strip()
|
# clean_text = re.sub(r'(\n\s*){3,}', '\n\n', clean_text).strip()
|
||||||
|
|
||||||
return clean_text
|
# return clean_text
|
||||||
|
|
||||||
def hashtags_list(self, hash_tags_str):
|
# def hashtags_list(self, hash_tags_str):
|
||||||
"""Convert comma-separated hashtags string to list"""
|
# """Convert comma-separated hashtags string to list"""
|
||||||
if not hash_tags_str:
|
# if not hash_tags_str:
|
||||||
return ["#HigherEd", "#Hiring", "#UniversityJobs"]
|
# return ["#HigherEd", "#Hiring", "#UniversityJobs"]
|
||||||
|
|
||||||
tags = [tag.strip() for tag in hash_tags_str.split(',') if tag.strip()]
|
# tags = [tag.strip() for tag in hash_tags_str.split(',') if tag.strip()]
|
||||||
tags = [tag if tag.startswith('#') else f'#{tag}' for tag in tags]
|
# tags = [tag if tag.startswith('#') else f'#{tag}' for tag in tags]
|
||||||
|
|
||||||
if not tags:
|
# if not tags:
|
||||||
return ["#HigherEd", "#Hiring", "#UniversityJobs"]
|
# return ["#HigherEd", "#Hiring", "#UniversityJobs"]
|
||||||
|
|
||||||
return tags
|
# return tags
|
||||||
|
|
||||||
def _build_post_message(self, job_posting):
|
# def _build_post_message(self, job_posting):
|
||||||
"""
|
# """
|
||||||
Constructs the final text message.
|
# Constructs the final text message.
|
||||||
Includes a unique suffix for duplicate content prevention (422 fix).
|
# Includes a unique suffix for duplicate content prevention (422 fix).
|
||||||
"""
|
# """
|
||||||
message_parts = [
|
# message_parts = [
|
||||||
f"🔥 *Job Alert!* We’re looking for a talented professional to join our team.",
|
# f"🔥 *Job Alert!* We’re looking for a talented professional to join our team.",
|
||||||
f"👉 **{job_posting.title}** 👈",
|
# f"👉 **{job_posting.title}** 👈",
|
||||||
]
|
# ]
|
||||||
|
|
||||||
if job_posting.department:
|
# if job_posting.department:
|
||||||
message_parts.append(f"*{job_posting.department}*")
|
# message_parts.append(f"*{job_posting.department}*")
|
||||||
|
|
||||||
message_parts.append("\n" + "=" * 25 + "\n")
|
# message_parts.append("\n" + "=" * 25 + "\n")
|
||||||
|
|
||||||
# KEY DETAILS SECTION
|
# # KEY DETAILS SECTION
|
||||||
details_list = []
|
# details_list = []
|
||||||
if job_posting.job_type:
|
# if job_posting.job_type:
|
||||||
details_list.append(f"💼 Type: {job_posting.get_job_type_display()}")
|
# details_list.append(f"💼 Type: {job_posting.get_job_type_display()}")
|
||||||
if job_posting.get_location_display() != 'Not specified':
|
# if job_posting.get_location_display() != 'Not specified':
|
||||||
details_list.append(f"📍 Location: {job_posting.get_location_display()}")
|
# details_list.append(f"📍 Location: {job_posting.get_location_display()}")
|
||||||
if job_posting.workplace_type:
|
# if job_posting.workplace_type:
|
||||||
details_list.append(f"🏠 Workplace: {job_posting.get_workplace_type_display()}")
|
# details_list.append(f"🏠 Workplace: {job_posting.get_workplace_type_display()}")
|
||||||
if job_posting.salary_range:
|
# if job_posting.salary_range:
|
||||||
details_list.append(f"💰 Salary: {job_posting.salary_range}")
|
# details_list.append(f"💰 Salary: {job_posting.salary_range}")
|
||||||
|
|
||||||
if details_list:
|
# if details_list:
|
||||||
message_parts.append("*Key Information*:")
|
# message_parts.append("*Key Information*:")
|
||||||
message_parts.extend(details_list)
|
# message_parts.extend(details_list)
|
||||||
message_parts.append("\n")
|
# message_parts.append("\n")
|
||||||
|
|
||||||
# DESCRIPTION SECTION
|
# # DESCRIPTION SECTION
|
||||||
clean_description = self.clean_html_for_social_post(job_posting.description)
|
# clean_description = self.clean_html_for_social_post(job_posting.description)
|
||||||
if clean_description:
|
# if clean_description:
|
||||||
message_parts.append(f"🔎 *About the Role:*\n{clean_description}")
|
# message_parts.append(f"🔎 *About the Role:*\n{clean_description}")
|
||||||
|
# clean_
|
||||||
|
|
||||||
# CALL TO ACTION
|
# # CALL TO ACTION
|
||||||
if job_posting.application_url:
|
# if job_posting.application_url:
|
||||||
message_parts.append(f"\n\n---")
|
# message_parts.append(f"\n\n---")
|
||||||
# CRITICAL: Include the URL explicitly in the text body.
|
# # CRITICAL: Include the URL explicitly in the text body.
|
||||||
# When media_category is NONE, LinkedIn often makes these URLs clickable.
|
# # When media_category is NONE, LinkedIn often makes these URLs clickable.
|
||||||
message_parts.append(f"🔗 **APPLY NOW:** {job_posting.application_url}")
|
# message_parts.append(f"🔗 **APPLY NOW:** {job_posting.application_url}")
|
||||||
|
|
||||||
# HASHTAGS
|
# # HASHTAGS
|
||||||
hashtags = self.hashtags_list(job_posting.hash_tags)
|
# hashtags = self.hashtags_list(job_posting.hash_tags)
|
||||||
if job_posting.department:
|
# if job_posting.department:
|
||||||
dept_hashtag = f"#{job_posting.department.replace(' ', '')}"
|
# dept_hashtag = f"#{job_posting.department.replace(' ', '')}"
|
||||||
hashtags.insert(0, dept_hashtag)
|
# hashtags.insert(0, dept_hashtag)
|
||||||
|
|
||||||
message_parts.append("\n" + " ".join(hashtags))
|
# message_parts.append("\n" + " ".join(hashtags))
|
||||||
|
|
||||||
final_message = "\n".join(message_parts)
|
# final_message = "\n".join(message_parts)
|
||||||
|
|
||||||
# --- FIX: ADD UNIQUE SUFFIX AND HANDLE LENGTH (422 fix) ---
|
# # --- FIX: ADD UNIQUE SUFFIX AND HANDLE LENGTH (422 fix) ---
|
||||||
unique_suffix = f"\n\n| Ref: {int(time.time())}"
|
# unique_suffix = f"\n\n| Ref: {int(time.time())}"
|
||||||
|
|
||||||
available_length = MAX_POST_CHARS - len(unique_suffix)
|
# available_length = MAX_POST_CHARS - len(unique_suffix)
|
||||||
|
|
||||||
if len(final_message) > available_length:
|
# if len(final_message) > available_length:
|
||||||
logger.warning("Post message truncated due to character limit.")
|
# logger.warning("Post message truncated due to character limit.")
|
||||||
final_message = final_message[:available_length - 3] + "..."
|
# final_message = final_message[:available_length - 3] + "..."
|
||||||
|
|
||||||
return final_message + unique_suffix
|
# return final_message + unique_suffix
|
||||||
|
|
||||||
|
|
||||||
# ---------------- MAIN POSTING METHODS ----------------
|
# ---------------- MAIN POSTING METHODS ----------------
|
||||||
@ -279,7 +279,9 @@ class LinkedInService:
|
|||||||
CRITICAL FIX: Avoids ARTICLE category if not using an image to prevent 402 errors.
|
CRITICAL FIX: Avoids ARTICLE category if not using an image to prevent 402 errors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message = self._build_post_message(job_posting)
|
message = job_posting.linkedin_post_formated_data
|
||||||
|
if len(message)>=3000:
|
||||||
|
message=message[:2900]+"...."
|
||||||
|
|
||||||
# --- FIX FOR 402: Force NONE if no image is present. ---
|
# --- FIX FOR 402: Force NONE if no image is present. ---
|
||||||
if media_category != "IMAGE":
|
if media_category != "IMAGE":
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-27 10:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('recruitment', '0002_candidate_retry'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='jobposting',
|
||||||
|
name='linkedin_post_formated_data',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-27 11:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('recruitment', '0003_jobposting_linkedin_post_formated_data'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='jobposting',
|
||||||
|
name='linkedin_post_formated_data',
|
||||||
|
field=models.CharField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-27 11:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('recruitment', '0004_alter_jobposting_linkedin_post_formated_data'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='jobposting',
|
||||||
|
name='linkedin_post_formated_data',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -129,6 +129,7 @@ class JobPosting(Base):
|
|||||||
max_length=50, blank=True, help_text="Status of LinkedIn posting"
|
max_length=50, blank=True, help_text="Status of LinkedIn posting"
|
||||||
)
|
)
|
||||||
linkedin_posted_at = models.DateTimeField(null=True, blank=True)
|
linkedin_posted_at = models.DateTimeField(null=True, blank=True)
|
||||||
|
linkedin_post_formated_data=models.TextField(null=True,blank=True)
|
||||||
|
|
||||||
published_at = models.DateTimeField(db_index=True, null=True, blank=True) # Added index
|
published_at = models.DateTimeField(db_index=True, null=True, blank=True) # Added index
|
||||||
# University Specific Fields
|
# University Specific Fields
|
||||||
|
|||||||
@ -45,6 +45,15 @@ def format_job(sender, instance, created, **kwargs):
|
|||||||
# If the instance is no longer active, delete the scheduled task
|
# If the instance is no longer active, delete the scheduled task
|
||||||
existing_schedule.delete()
|
existing_schedule.delete()
|
||||||
|
|
||||||
|
# @receiver(post_save, sender=JobPosting)
|
||||||
|
# def update_form_template_status(sender, instance, created, **kwargs):
|
||||||
|
# if not created:
|
||||||
|
# if instance.status == "Active":
|
||||||
|
# instance.form_template.is_active = True
|
||||||
|
# else:
|
||||||
|
# instance.form_template.is_active = False
|
||||||
|
# instance.save()
|
||||||
|
|
||||||
@receiver(post_save, sender=Candidate)
|
@receiver(post_save, sender=Candidate)
|
||||||
def score_candidate_resume(sender, instance, created, **kwargs):
|
def score_candidate_resume(sender, instance, created, **kwargs):
|
||||||
if not instance.is_resume_parsed:
|
if not instance.is_resume_parsed:
|
||||||
|
|||||||
@ -116,25 +116,55 @@ def format_job_description(pk):
|
|||||||
job_posting = JobPosting.objects.get(pk=pk)
|
job_posting = JobPosting.objects.get(pk=pk)
|
||||||
print(job_posting)
|
print(job_posting)
|
||||||
prompt = f"""
|
prompt = f"""
|
||||||
Can you please organize and format this unformatted job description and qualifications into clear, readable sections using headings and bullet points?
|
You are a dual-purpose AI assistant specializing in content formatting and social media copywriting for job announcements.
|
||||||
Format the Content: You need to convert the clear, formatted job description and qualifications into a 2 blocks of HTML code.
|
|
||||||
**JOB DESCRIPTION:**
|
|
||||||
{job_posting.description}
|
|
||||||
|
|
||||||
**QUALIFICATIONS:**
|
**JOB POSTING DATA (Raw Input):**
|
||||||
{job_posting.qualifications}
|
---
|
||||||
|
**JOB DESCRIPTION:**
|
||||||
|
{job_posting.description}
|
||||||
|
|
||||||
**STRICT JSON OUTPUT INSTRUCTIONS:**
|
**QUALIFICATIONS:**
|
||||||
Output a single, valid JSON object with ONLY the following two top-level keys:
|
{job_posting.qualifications}
|
||||||
|
|
||||||
'job_description': 'A HTML containing the formatted job description',
|
**BENEFITS:**
|
||||||
'job_qualifications': 'A HTML containing the formatted job qualifications',
|
{job_posting.benefits}
|
||||||
|
|
||||||
|
**APPLICATION INSTRUCTIONS:**
|
||||||
|
{job_posting.application_instructions}
|
||||||
|
|
||||||
Do not include any other text except for the JSON output.
|
**APPLICATION DEADLINE:**
|
||||||
|
{job_posting.application_deadline}
|
||||||
|
|
||||||
|
**HASHTAGS: for search and reach:**
|
||||||
|
{job_posting.hash_tags}
|
||||||
|
---
|
||||||
|
|
||||||
|
**TASK 1: HTML Formatting (Two Blocks)**
|
||||||
|
1. **Format the Job Description:** Organize and format the raw JOB DESCRIPTION and BENEFITS data into clear, readable sections using `<h2>` headings and `<ul>`/`<li>` bullet points. Encapsulate the entire formatted block within a single `<div>`.
|
||||||
|
2. **Format the Qualifications:** Organize and format the raw QUALIFICATIONS data into clear, readable sections using `<h2>` headings and `<ul>`/`<li>` bullet points. Encapsulate the entire formatted block within a single `<div>`.
|
||||||
|
2. **Format the Requirements:** Organize and format the raw Requirements data into clear, readable sections using `<h2>` headings and `<ul>`/`<li>` bullet points. Encapsulate the entire formatted block within a single `<div>`.
|
||||||
|
|
||||||
|
**TASK 2: LinkedIn Post Creation**
|
||||||
|
1. **Write the Post:** Create an engaging, professional, and concise LinkedIn post (maximum 1300 characters) summarizing the opportunity.
|
||||||
|
2. **Encourage Action:** The post must have a strong call-to-action (CTA) encouraging applications.
|
||||||
|
3. **Use Hashtags:** Integrate relevant industry, role, and company hashtags (including any provided in the raw input) naturally at the end of the post.
|
||||||
|
|
||||||
|
**STRICT JSON OUTPUT INSTRUCTIONS:**
|
||||||
|
Output a **single, valid JSON object** with **ONLY** the following three top-level key-value pairs.
|
||||||
|
|
||||||
|
* The values for `html_job_description` and `html_qualifications` MUST be the complete, formatted HTML strings (including all tags).
|
||||||
|
* The value for `linkedin_post` MUST be the complete, final LinkedIn post as a single string not greater than 3000 characters.
|
||||||
|
|
||||||
|
**Output Keys:**
|
||||||
|
1. `html_job_description`
|
||||||
|
2. `html_qualifications`
|
||||||
|
3 `html_job_requirements`
|
||||||
|
4. `linkedin_post_data`
|
||||||
|
|
||||||
|
**Do not include any other text, explanation, or markdown outside of the final JSON object.**
|
||||||
"""
|
"""
|
||||||
result = ai_handler(prompt)
|
result = ai_handler(prompt)
|
||||||
|
print(f"REsults: {result}")
|
||||||
if result['status'] == 'error':
|
if result['status'] == 'error':
|
||||||
logger.error(f"AI handler returned error for candidate {job_posting.pk}")
|
logger.error(f"AI handler returned error for candidate {job_posting.pk}")
|
||||||
print(f"AI handler returned error for candidate {job_posting.pk}")
|
print(f"AI handler returned error for candidate {job_posting.pk}")
|
||||||
@ -144,9 +174,10 @@ def format_job_description(pk):
|
|||||||
data = json.loads(data)
|
data = json.loads(data)
|
||||||
print(data)
|
print(data)
|
||||||
|
|
||||||
job_posting.description = data.get('job_description')
|
job_posting.description = data.get('html_job_description')
|
||||||
job_posting.qualifications = data.get('job_qualifications')
|
job_posting.qualifications = data.get('html_qualifications')
|
||||||
job_posting.save(update_fields=['description', 'qualifications'])
|
job_posting.linkedin_post_formated_data=data.get('linkedin_post_data')
|
||||||
|
job_posting.save(update_fields=['description', 'qualifications','linkedin_post_formated_data'])
|
||||||
|
|
||||||
|
|
||||||
def ai_handler(prompt):
|
def ai_handler(prompt):
|
||||||
@ -400,6 +431,8 @@ def handle_reume_parsing_and_scoring(pk):
|
|||||||
logger.info(f"Successfully scored and saved analysis for candidate {instance.id}")
|
logger.info(f"Successfully scored and saved analysis for candidate {instance.id}")
|
||||||
print(f"Successfully scored and saved analysis for candidate {instance.id}")
|
print(f"Successfully scored and saved analysis for candidate {instance.id}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_interview_and_meeting(
|
def create_interview_and_meeting(
|
||||||
candidate_id,
|
candidate_id,
|
||||||
job_id,
|
job_id,
|
||||||
|
|||||||
@ -613,3 +613,7 @@ def update_meeting(instance, updated_data):
|
|||||||
|
|
||||||
logger.warning(f"Failed to update Zoom meeting {instance.meeting_id}. Error: {result.get('message', 'Unknown error')}")
|
logger.warning(f"Failed to update Zoom meeting {instance.meeting_id}. Error: {result.get('message', 'Unknown error')}")
|
||||||
return {"status": "error", "message": result.get("message", "Zoom meeting update failed.")}
|
return {"status": "error", "message": result.get("message", "Zoom meeting update failed.")}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -357,6 +357,15 @@ def job_detail(request, slug):
|
|||||||
status_form = JobPostingStatusForm(request.POST, instance=job)
|
status_form = JobPostingStatusForm(request.POST, instance=job)
|
||||||
|
|
||||||
if status_form.is_valid():
|
if status_form.is_valid():
|
||||||
|
job_status=status_form.cleaned_data['status']
|
||||||
|
form_template=job.form_template
|
||||||
|
if job_status=='ACTIVE':
|
||||||
|
form_template.is_active=True
|
||||||
|
form_template.save(update_fields=['is_active'])
|
||||||
|
else:
|
||||||
|
form_template.is_active=False
|
||||||
|
form_template.save(update_fields=['is_active'])
|
||||||
|
|
||||||
status_form.save()
|
status_form.save()
|
||||||
|
|
||||||
# Add a success message
|
# Add a success message
|
||||||
|
|||||||
@ -347,9 +347,14 @@
|
|||||||
<i class="fas fa-plus-circle me-1"></i> {% trans "Create New Form Template" %}
|
<i class="fas fa-plus-circle me-1"></i> {% trans "Create New Form Template" %}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
{% if job.form_template.is_active %}
|
||||||
<a href="{% url 'application_submit_form' job.form_template.slug %}" class="btn btn-outline-secondary w-100">
|
<a href="{% url 'application_submit_form' job.form_template.slug %}" class="btn btn-outline-secondary w-100">
|
||||||
<i class="fas fa-list-alt me-1"></i> {% trans "View Form Template" %}
|
<i class="fas fa-list-alt me-1"></i> {% trans "View Form Template" %}
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans "This job status is not active, the form will appear once the job is made active"%}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user