isssue resolved 7

This commit is contained in:
Faheed 2025-12-04 12:08:35 +03:00
parent de9c3153d5
commit 934d03b5bb
14 changed files with 221 additions and 46 deletions

View File

@ -492,3 +492,42 @@ AUTH_USER_MODEL = "recruitment.CustomUser"
ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB" ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB"
#logger:
LOGGING={
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": os.path.join(BASE_DIR, "general.log"),
"level": "DEBUG",
"formatter": "verbose",
},
"console":{
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "simple"
}
},
"loggers": {
"": {
"handlers": ["file", "console"],
"level": "DEBUG",
"propagate": True,
},
},
"formatters": {
"verbose": {
"format": "[{asctime}] {levelname} [{name}:{lineno}] {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
}
}

View File

@ -18,7 +18,7 @@ from .validators import validate_hash_tags, validate_image_size
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import F, Value, IntegerField, CharField from django.db.models import F, Value, IntegerField, CharField,Q
from django.db.models.functions import Coalesce, Cast from django.db.models.functions import Coalesce, Cast
from django.db.models.fields.json import KeyTransform, KeyTextTransform from django.db.models.fields.json import KeyTransform, KeyTextTransform
@ -70,6 +70,15 @@ class CustomUser(AbstractUser):
verbose_name = _("User") verbose_name = _("User")
verbose_name_plural = _("Users") verbose_name_plural = _("Users")
@property
def get_unread_message_count(self):
message_list = (
Message.objects.filter(Q(sender=self) | Q(recipient=self), is_read=False)
)
return message_list.count() or 0
User = get_user_model() User = get_user_model()
@ -2110,6 +2119,7 @@ class HiringAgency(Base):
super().delete(*args, **kwargs) super().delete(*args, **kwargs)
class AgencyJobAssignment(Base): class AgencyJobAssignment(Base):
"""Assigns specific jobs to agencies with limits and deadlines""" """Assigns specific jobs to agencies with limits and deadlines"""
@ -2267,6 +2277,15 @@ class AgencyJobAssignment(Base):
# self.save(update_fields=['status']) # self.save(update_fields=['status'])
return True return True
return False return False
@property
def applications_submited_count(self):
"""Return the number of applications submitted by the agency for this job"""
return Application.objects.filter(
hiring_agency=self.agency,
job=self.job
).count()
def extend_deadline(self, new_deadline): def extend_deadline(self, new_deadline):
"""Extend the deadline for this assignment""" """Extend the deadline for this assignment"""

View File

@ -1,3 +1,7 @@
#logger for recruitment views
import logging
logger = logging.getLogger(__name__)
import json import json
import io import io
import zipfile import zipfile
@ -433,7 +437,7 @@ def create_job(request):
job = form.save(commit=False) job = form.save(commit=False)
job.save() job.save()
job_apply_url_relative = reverse( job_apply_url_relative = reverse(
"application_detail", kwargs={"slug": job.slug} "job_application_detail", kwargs={"slug": job.slug}
) )
job_apply_url_absolute = request.build_absolute_uri( job_apply_url_absolute = request.build_absolute_uri(
job_apply_url_relative job_apply_url_relative
@ -712,7 +716,11 @@ def request_cvs_download(request, slug):
""" """
View to initiate the background task. View to initiate the background task.
""" """
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
if job.status != 'CLOSED':
messages.info('request',_("You can request bulk CV dowload only if the job status is changed to CLOSED"))
return redirect('job_detail',kwargs={slug:job.slug})
job.zip_created = False job.zip_created = False
job.save(update_fields=["zip_created"]) job.save(update_fields=["zip_created"])
# Use async_task to run the function in the background # Use async_task to run the function in the background
@ -732,6 +740,10 @@ def download_ready_cvs(request, slug):
View to serve the file once it is ready. View to serve the file once it is ready.
""" """
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
if job.status != 'CLOSED':
messages.info('request',_("You can request bulk CV dowload only if the job status is changed to CLOSED"))
return redirect('job_detail',kwargs={slug:job.slug})
if not job.applications.exists(): if not job.applications.exists():
messages.warning(request, _("No applications found for this job. ZIP file download unavailable.")) messages.warning(request, _("No applications found for this job. ZIP file download unavailable."))
return redirect('job_detail', slug=slug) return redirect('job_detail', slug=slug)
@ -3331,6 +3343,7 @@ def agency_detail(request, slug):
hired_applications = applications.filter(stage="Hired").count() hired_applications = applications.filter(stage="Hired").count()
rejected_applications = applications.filter(stage="Rejected").count() rejected_applications = applications.filter(stage="Rejected").count()
job_assignments=AgencyJobAssignment.objects.filter(agency=agency) job_assignments=AgencyJobAssignment.objects.filter(agency=agency)
total_job_assignments=job_assignments.count()
print(job_assignments) print(job_assignments)
context = { context = {
"agency": agency, "agency": agency,
@ -3342,7 +3355,8 @@ def agency_detail(request, slug):
"generated_password": agency.generated_password "generated_password": agency.generated_password
if agency.generated_password if agency.generated_password
else None, else None,
"job_assignments":job_assignments "job_assignments":job_assignments,
"total_job_assignments":total_job_assignments,
} }
return render(request, "recruitment/agency_detail.html", context) return render(request, "recruitment/agency_detail.html", context)
@ -3747,7 +3761,8 @@ def agency_assignment_list(request):
if search_query: if search_query:
assignments = assignments.filter( assignments = assignments.filter(
Q(agency__name__icontains=search_query) Q(agency__name__icontains=search_query)
| Q(job__title__icontains=search_query) | Q(job__title__icontains=search_query)|
Q(agency__contact_person__icontains=search_query)
) )
if status_filter: if status_filter:

View File

@ -20,6 +20,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="{% static 'css/main.css' %}"> <link rel="stylesheet" href="{% static 'css/main.css' %}">
<script src="{% static 'js/typo.js' %}"></script>
{% block customCSS %}{% endblock %} {% block customCSS %}{% endblock %}
@ -134,11 +135,22 @@
</form> </form>
{% endif %} {% endif %}
</li> </li>
<li class="nav-item me-2 d-none d-lg-block"> {% comment %} <li class="nav-item me-2 d-none d-lg-block">
<a class="nav-link text-white" href="{% url 'message_list' %}"> <a class="nav-link text-white" href="{% url 'message_list' %}">
<i class="fas fa-envelope"></i> <span>{% trans "Messages" %}</span> <i class="fas fa-envelope"></i> <span>{% trans "Messages" %}</span>
</a> </a>
</li> </li>
{% endcomment %}
<li class="nav-item mx-3 d-none d-lg-block mt-2">
<a href="{% url 'message_list' %}"
class=" btn btn-sm btn-outline-warning position-relative">
<i class="fas fa-envelope me-1"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
{{ request.user.get_unread_message_count }}
</span>
</a>
</li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<button <button

View File

@ -146,12 +146,12 @@
<div class="container-fluid py-4"> <div class="container-fluid py-4">
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item "><a href="{% url 'job_detail' submission.template.job.slug %}" class="text-secondary text-decoration-none">Job Detail</a></li> <li class="breadcrumb-item "><a href="{% url 'job_detail' submission.template.job.slug %}" class="text-secondary text-decoration-none">{% trans "Job Detail" %}</a></li>
<li class="breadcrumb-item"><a href="{% url 'form_builder' submission.template.pk%}" class="text-secondary">Form Template</a></li> <li class="breadcrumb-item"><a href="{% url 'form_builder' submission.template.pk%}" class="text-secondary text-decoration-none">{% trans "Form Template" %}</a></li>
<li class="breadcrumb-item active" aria-current="page" style=" <li class="breadcrumb-item active" aria-current="page" style="
color: #F43B5E; /* Rosy Accent Color */ color: #F43B5E; /* Rosy Accent Color */
font-weight: 600; font-weight: 600;
">Submission Details</li> ">{% trans "Submission Details" %}</li>
</ol> </ol>
</nav> </nav>
<div class="row"> <div class="row">

View File

@ -182,6 +182,39 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% comment %} <div class="container py-4">
<!-- Search and Filter Section -->
<div class="card shadow-sm mb-4">
<div class="card-body">
<form method="get" action="" class="w-100">
<div class="row g-3 align-items-end">
<div class="col-12 col-md-5">
<label for="search" class="form-label small text-muted">{% trans "Search by name or Email" %}</label>
<div class="input-group">
{% include 'includes/search_form.html' %}
</div>
</div>
<div class="col-12 col-md-2">
<label for="date_from" class="form-label small text-muted">{% trans "From Date" %}</label>
<input type="date" class="form-control" id="date_from" name="date_from" value="{{ request.GET.date_from }}">
</div>
<div class="col-12 col-md-2">
<label for="date_to" class="form-label small text-muted">{% trans "To Date" %}</label>
<input type="date" class="form-control" id="date_to" name="date_to" value="{{ request.GET.date_to }}">
</div>
<div class="col-12 col-md-3 d-flex gap-2">
<button type="submit" class="btn btn-main-action flex-grow-1">
<i class="fas fa-search me-1"></i> {% trans "Filter" %}
</button>
<a href="?" class="btn btn-outline-secondary flex-grow-1">
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a>
</div>
</div>
</form>
</div>
</div>
{% endcomment %}
<div class="container py-4"> <div class="container py-4">
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
@ -254,7 +287,7 @@
<div class="card-view"> <div class="card-view">
<div class="row g-4"> <div class="row g-4">
{% for submission in page_obj %} {% for submission in page_obj %}
<div class="col-12"> <div class="col-md-6 col-lg-6">
<div class="card h-100"> <div class="card h-100">
<div class="card-header"> <div class="card-header">
<h3 class="h5 mb-2">{% trans "Submission" %} #{{ submission.id }}</h3> <h3 class="h5 mb-2">{% trans "Submission" %} #{{ submission.id }}</h3>

View File

@ -32,11 +32,17 @@
{% trans "To" %} {% trans "To" %}
</label> </label>
<div class="border rounded p-3 bg-light" style="max-height: 200px; overflow-y: auto;"> <div class="border rounded p-3 bg-light" style="max-height: 200px; overflow-y: auto;">
{% for choice in form.to %} {% for choice in form.to|slice:":1" %}
<div class="form-check mb-2"> <div class="form-check mb-2">
{{ choice }} {{ choice }}
</div> </div>
{% endfor %} {% endfor %}
{% if form.to|length > 0 %}
<div class="text-muted small mt-2">
<i class="fas fa-info-circle me-1"></i>
{% blocktrans count total=form.to|length %}{{ total }} recipient selected{% plural %}{{ total }} recipients selected{% endblocktrans %}
</div>
{% endif %}
</div> </div>
{% if form.to.errors %} {% if form.to.errors %}
<div class="text-danger small mt-1"> <div class="text-danger small mt-1">

View File

@ -218,7 +218,9 @@
<div class="card-body"> <div class="card-body">
<h5 class="text-muted mb-3">{% trans "Administrative & Location" %} <h5 class="text-muted mb-3">{% trans "Administrative & Location" %}
{% if job.status == 'DRAFT'%}
<a href="{% url 'job_update' job.slug %}" class="btn btn-main-action btn-sm"><li class="fa fa-edit"></li>{% trans "Edit Job" %}</a> <a href="{% url 'job_update' job.slug %}" class="btn btn-main-action btn-sm"><li class="fa fa-edit"></li>{% trans "Edit Job" %}</a>
{% endif %}
<div class="float-end"> <div class="float-end">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<i class="fas fa-user-tie me-2 text-primary"></i> <strong>{% trans "Assigned to :" %} </strong> {{ job.assigned_to|default:"" }} <i class="fas fa-user-tie me-2 text-primary"></i> <strong>{% trans "Assigned to :" %} </strong> {{ job.assigned_to|default:"" }}
@ -332,13 +334,20 @@
<i class="fas fa-layer-group me-1"></i> {% trans "Manage Applications" %} <i class="fas fa-layer-group me-1"></i> {% trans "Manage Applications" %}
</a> </a>
<a href="{% url 'request_cvs_download' job.slug %}" class="btn btn-main-action"> {% if not job.form_template.is_active %}
<i class="fa-solid fa-download me-1"></i> {% trans "Generate All CVs" %} {% if not jobzip_created %}
</a> <a href="{% url 'request_cvs_download' job.slug %}" class="btn btn-main-action">
<i class="fa-solid fa-download me-1"></i> {% trans "Generate All CVs" %}
<a href="{% url 'download_ready_cvs' job.slug %}" class="btn btn-outline-primary"> </a>
<i class="fa-solid fa-eye me-1"></i> {% trans "View All CVs" %} {% endif %}
</a> {% if job.zip_created %}
<a href="{% url 'download_ready_cvs' job.slug %}" class="btn btn-outline-primary">
<i class="fa-solid fa-eye me-1"></i> {% trans "View All CVs" %}
</a>
{% endif %}
{% else %}
<p>{% trans "Bulk CV dowload is inactive. To activate please change the status of the job to CLOSED." %}</p>
{% endif %}
</div> </div>
</div> </div>

View File

@ -257,13 +257,52 @@
<form method="post" action="{% url 'person_update' person.slug %}" enctype="multipart/form-data" id="person-form"> <form method="post" action="{% url 'person_update' person.slug %}" enctype="multipart/form-data" id="person-form">
{% csrf_token %} {% csrf_token %}
{{form|crispy}} <div class="row">
<div class="col-md-6">
<label for="{{ form.first_name.id_for_label }}">{{ form.first_name.label }}</label>
{% include "bootstrap5/field.html" with field=form.first_name %}
</div>
<div class="col-md-6">
<label for="{{ form.middle_name.id_for_label }}">{{ form.middle_name.label }}</label>
{% include "bootstrap5/field.html" with field=form.middle_name %}
</div>
<div class="col-md-6">
<label for="{{ form.last_name.id_for_label }}">{{ form.last_name.label }}</label>
{% include "bootstrap5/field.html" with field=form.last_name %}
</div>
<div class="col-md-6">
<label for="{{ form.email.id_for_label }}">{{ form.email.label }}</label>
{% include "bootstrap5/field.html" with field=form.email %}
</div>
<div class="col-md-6">
<label for="{{ form.phone.id_for_label }}">{{ form.phone.label }}</label>
{% include "bootstrap5/field.html" with field=form.phone %}
</div>
<div class="col-md-6">
<label for="{{ form.date_of_birth.id_for_label }}">{{ form.date_of_birth.label }}</label>
{% include "bootstrap5/field.html" with field=form.date_of_birth %}
</div>
<div class="col-md-6">
<label for="{{ form.nationality.id_for_label }}">{{ form.nationality.label }}</label>
{% include "bootstrap5/field.html" with field=form.nationality %}
</div>
<div class="col-md-6">
<label for="{{ form.gender.id_for_label }}">{{ form.gender.label }}</label>
{% include "bootstrap5/field.html" with field=form.gender %}
</div>
<div class="col-md-12">
<label for="{{ form.address.id_for_label }}">{{ form.address.label }}</label>
{% include "bootstrap5/field.html" with field=form.address %}
</div>
</div>
</form> </form>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<button form="person-form" type="submit" class="btn btn-main-action"> <button form="person-form" type="submit" class="btn btn-main-action">
<i class="fas fa-save me-1"></i> {% trans "Update" %} <i class="fas fa-save me-1"></i> {% trans "Update" %}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -152,10 +152,15 @@
<a class="nav-link text-white" href="{% url 'user_detail' request.user.pk %}"> <a class="nav-link text-white" href="{% url 'user_detail' request.user.pk %}">
<i class="fas fa-user-circle me-1"></i> <span>{% trans "My Profile" %}</span></a></li> <i class="fas fa-user-circle me-1"></i> <span>{% trans "My Profile" %}</span></a></li>
{% endif %} {% endif %}
<li class="nav-item me-2"> <li class="nav-item mx-2 mt-2">
<a class="nav-link text-white" href="{% url 'message_list' %}"> <a href="{% url 'message_list' %}"
<i class="fas fa-envelope"></i> <span>{% trans "Messages" %}</span> class=" btn btn-sm btn-outline-warning position-relative">
</a> <i class="fas fa-envelope me-1"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
{{ request.user.get_unread_message_count }}
</span>
</a>
</li> </li>
<li class="nav-item ms-3"> <li class="nav-item ms-3">

View File

@ -136,7 +136,7 @@
<div class="mb-3"> <div class="mb-3">
<label class="text-muted small">{% trans "Status" %}</label> <label class="text-muted small">{% trans "Status" %}</label>
<div> <div>
<span class="status-badge status-{{ assignment.status }}"> <span class="status-badge bg-primary-theme text-white">
{{ assignment.get_status_display }} {{ assignment.get_status_display }}
</span> </span>
</div> </div>
@ -261,7 +261,7 @@
</div> </div>
</td> </td>
<td> <td>
<span class="badge bg-info">{{ application.get_stage_display }}</span> <span class="badge bg-primary-theme">{{ application.get_stage_display }}</span>
</td> </td>
<td> <td>
<div class="small text-muted"> <div class="small text-muted">
@ -271,7 +271,7 @@
</div> </div>
</td> </td>
<td class="px-4"> <td class="px-4">
<span class="badge bg-soft-info text-info rounded-pill px-3"> <span class="badge bg-primary-theme px-3">
{{application.get_stage_display }}</span> {{application.get_stage_display }}</span>
</td> </td>
<td class="px-4"> <td class="px-4">
@ -339,9 +339,9 @@
<div class="text-muted">/ {{ assignment.max_candidates }} {% trans "applications" %}</div> <div class="text-muted">/ {{ assignment.max_candidates }} {% trans "applications" %}</div>
</div> </div>
<div class="progress mt-3" style="height: 8px;"> <div class="progress mt-3 " style="height: 8px;">
{% widthratio total_applications assignment.max_candidates 100 as progress %} {% widthratio total_applications assignment.max_candidates 100 as progress %}
<div class="progress-bar" style="width: {{ progress }}%"></div> <div class="progress-bar bg-primary-theme" style="width: {{ progress }}%"></div>
</div> </div>
</div> </div>
@ -354,7 +354,7 @@
</h5> </h5>
<div class="d-grid gap-2"> <div class="d-grid gap-2">
<a href="{}" <a href="{% url "message_list" %}"
class="btn btn-outline-primary"> class="btn btn-outline-primary">
<i class="fas fa-envelope me-1"></i> {% trans "Send Message" %} <i class="fas fa-envelope me-1"></i> {% trans "Send Message" %}
</a> </a>

View File

@ -43,10 +43,10 @@
border-radius: 0.35rem; border-radius: 0.35rem;
font-weight: 700; font-weight: 700;
} }
.status-ACTIVE { background-color: var(--kaauh-success); color: white; } {% comment %} .status-ACTIVE { background-color: var(--kaauh-success); color: white; }
.status-EXPIRED { background-color: var(--kaauh-danger); color: white; } .status-EXPIRED { background-color: var(--kaauh-danger); color: white; }
.status-COMPLETED { background-color: var(--kaauh-info); color: white; } .status-COMPLETED { background-color: var(--kaauh-info); color: white; }
.status-CANCELLED { background-color: var(--kaauh-warning); color: #856404; } .status-CANCELLED { background-color: var(--kaauh-warning); color: #856404; } {% endcomment %}
</style> </style>
{% endblock %} {% endblock %}
@ -130,7 +130,7 @@
</td> </td>
<td> <td>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="badge bg-primary me-2">{{ assignment.submitted_count }}</span> <span class="badge bg-primary-theme text-white me-2">{{ assignment.applications_submited_count}}</span>
<span class="text-muted">/ {{ assignment.max_candidates }}</span> <span class="text-muted">/ {{ assignment.max_candidates }}</span>
</div> </div>
<div class="progress mt-1" style="height: 4px;"> <div class="progress mt-1" style="height: 4px;">
@ -150,7 +150,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<span class="status-badge status-{{ assignment.status }}"> <span class="status-badge bg-primary-theme text-white">
{{ assignment.get_status_display }} {{ assignment.get_status_display }}
</span> </span>
</td> </td>

View File

@ -531,6 +531,7 @@
aria-selected="true" aria-selected="true"
> >
<i class="fas fa-users me-1"></i> <i class="fas fa-users me-1"></i>
<span>({{total_applications}})</span>
{% trans "Recent Applications" %} {% trans "Recent Applications" %}
</button> </button>
</li> </li>
@ -546,6 +547,7 @@
aria-selected="false" aria-selected="false"
> >
<i class="fas fa-briefcase me-1"></i> <i class="fas fa-briefcase me-1"></i>
<span>({{total_job_assignments}})</span>
{% trans "Assigned Jobs" %} {% trans "Assigned Jobs" %}
</button> </button>
</li> </li>

View File

@ -52,12 +52,8 @@
{% comment %} <a href="{% url 'agency_portal_submit_application' %}" class="btn btn-main-action me-2"> {% comment %} <a href="{% url 'agency_portal_submit_application' %}" class="btn btn-main-action me-2">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit Application" %} <i class="fas fa-user-plus me-1"></i> {% trans "Submit Application" %}
</a> </a>
<a href="#" class="btn btn-outline-secondary position-relative">
<i class="fas fa-envelope me-1"></i> {% trans "Messages" %} >
{% if total_unread_messages > 0 %}
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
{{ total_unread_messages }}
</span>
{% endif %} {% endif %}
</a> {% endcomment %} </a> {% endcomment %}
</div> </div>
@ -207,15 +203,15 @@
class="btn btn-sm btn-main-action"> class="btn btn-sm btn-main-action">
<i class="fas fa-eye me-1"></i> {% trans "View Details" %} <i class="fas fa-eye me-1"></i> {% trans "View Details" %}
</a> </a>
{% if stats.unread_messages > 0 %} {% comment %} {% if stats.unread_messages > 0 %}
<a href="{% url 'agency_portal_assignment_detail' stats.assignment.slug %}#messages" <a href="{% url 'message_list' %}"
class="btn btn-sm btn-outline-warning position-relative"> class="btn btn-sm btn-outline-warning position-relative">
<i class="fas fa-envelope me-1"></i> <i class="fas fa-envelope me-1"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"> <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
{{ stats.unread_messages }} {{ stats.unread_messages }}
</span> </span>
</a> </a>
{% endif %} {% endif %} {% endcomment %}
</div> </div>
</div> </div>
</div> </div>