password reset
This commit is contained in:
parent
2f02f10c16
commit
7ae8c16db2
Binary file not shown.
@ -132,24 +132,24 @@ WSGI_APPLICATION = 'NorahUniversity.wsgi.application'
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
# 'NAME': 'norahuniversity',
|
||||
# 'USER': 'norahuniversity',
|
||||
# 'PASSWORD': 'norahuniversity',
|
||||
# 'HOST': '127.0.0.1',
|
||||
# 'PORT': '5432',
|
||||
# }
|
||||
# }
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'haikal_db',
|
||||
'USER': 'faheed',
|
||||
'PASSWORD': 'Faheed@215',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '5432',
|
||||
}
|
||||
}
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
||||
# }
|
||||
# }
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||
|
||||
@ -178,6 +178,7 @@ ACCOUNT_SIGNUP_FIELDS = ['email*', 'password1*', 'password2*']
|
||||
ACCOUNT_UNIQUE_EMAIL = True
|
||||
ACCOUNT_EMAIL_VERIFICATION = 'none'
|
||||
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||
ACCOUNT_EMAIL_REQUIRED = True
|
||||
|
||||
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
|
||||
|
||||
@ -197,6 +198,10 @@ CRISPY_BS5 = {
|
||||
'use_css_helpers': True,
|
||||
}
|
||||
|
||||
ACCOUNT_RATE_LIMITS = {
|
||||
'send_email_confirmation': None, # Disables the limit
|
||||
}
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -693,3 +693,7 @@ class StaffUserCreationForm(UserCreationForm):
|
||||
|
||||
|
||||
|
||||
class ToggleAccountForm(forms.Form):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,9 @@ class Profile(models.Model):
|
||||
profile_image = models.ImageField(null=True, blank=True, upload_to="profile_pic/")
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
|
||||
|
||||
def __str__(self):
|
||||
return f"image for user {self.user}"
|
||||
|
||||
class JobPosting(Base):
|
||||
# Basic Job Information
|
||||
JOB_TYPES = [
|
||||
@ -302,6 +305,26 @@ class JobPosting(Base):
|
||||
def offer_candidates(self):
|
||||
return self.all_candidates.filter(stage="Offer")
|
||||
|
||||
|
||||
#counts
|
||||
@property
|
||||
def all_candidates_count(self):
|
||||
return self.candidates.annotate(sortable_score=Cast('ai_analysis_data__match_score',output_field=CharField())).order_by('-sortable_score').count()
|
||||
@property
|
||||
def screening_candidates_count(self):
|
||||
return self.all_candidates.filter(stage="Applied").count()
|
||||
|
||||
@property
|
||||
def exam_candidates_count(self):
|
||||
return self.all_candidates.filter(stage="Exam").count()
|
||||
@property
|
||||
def interview_candidates_count(self):
|
||||
return self.all_candidates.filter(stage="Interview").count()
|
||||
|
||||
@property
|
||||
def offer_candidates_count(self):
|
||||
return self.all_candidates.filter(stage="Offer").count()
|
||||
|
||||
class JobPostingImage(models.Model):
|
||||
job=models.OneToOneField('JobPosting',on_delete=models.CASCADE,related_name='post_images')
|
||||
post_image = models.ImageField(upload_to='post/',validators=[validate_image_size])
|
||||
|
||||
@ -108,6 +108,7 @@ urlpatterns = [
|
||||
path('jobs/<slug:slug>/candidates/<int:candidate_pk>/schedule-meeting-page/', views.schedule_meeting_for_candidate, name='schedule_meeting_for_candidate'),
|
||||
path('jobs/<slug:slug>/candidates/<int:candidate_pk>/delete_meeting_for_candidate/<int:meeting_id>/', views.delete_meeting_for_candidate, name='delete_meeting_for_candidate'),
|
||||
|
||||
|
||||
# users urls
|
||||
path('user/<int:pk>',views.user_detail,name='user_detail'),
|
||||
path('user/user_profile_image_update/<int:pk>',views.user_profile_image_update,name='user_profile_image_update'),
|
||||
@ -115,6 +116,10 @@ urlpatterns = [
|
||||
path('settings/',views.admin_settings,name='admin_settings'),
|
||||
path('staff/create',views.create_staff_user,name='create_staff_user'),
|
||||
path('set_staff_password/<int:pk>/',views.set_staff_password,name='set_staff_password'),
|
||||
path('account_toggle_status/<int:pk>',views.account_toggle_status,name='account_toggle_status'),
|
||||
|
||||
|
||||
|
||||
|
||||
# Meeting Comments URLs
|
||||
path('meetings/<slug:slug>/comments/add/', views.add_meeting_comment, name='add_meeting_comment'),
|
||||
|
||||
@ -26,8 +26,10 @@ from .forms import (
|
||||
BreakTimeFormSet,
|
||||
JobPostingImageForm,
|
||||
ProfileImageUploadForm,
|
||||
StaffUserCreationForm
|
||||
,MeetingCommentForm
|
||||
StaffUserCreationForm,
|
||||
MeetingCommentForm,
|
||||
ToggleAccountForm,
|
||||
|
||||
)
|
||||
from easyaudit.models import CRUDEvent, LoginEvent, RequestEvent
|
||||
from rest_framework import viewsets
|
||||
@ -1940,37 +1942,51 @@ def schedule_meeting_for_candidate(request, slug, candidate_pk):
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
def user_profile_image_update(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
try:
|
||||
instance =user.profile
|
||||
|
||||
except ObjectDoesNotExist as e:
|
||||
Profile.objects.create(user=user)
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
|
||||
# 2. Ensure Profile exists and get the instance
|
||||
try:
|
||||
|
||||
profile_instance = user.profile
|
||||
except ObjectDoesNotExist:
|
||||
|
||||
profile_instance = Profile.objects.create(user=user)
|
||||
|
||||
if request.method == 'POST':
|
||||
profile_form = ProfileImageUploadForm(request.POST, request.FILES, instance=user.profile)
|
||||
|
||||
profile_form = ProfileImageUploadForm(
|
||||
request.POST,
|
||||
request.FILES,
|
||||
instance=profile_instance # <--- USE profile_instance HERE
|
||||
)
|
||||
|
||||
if profile_form.is_valid():
|
||||
profile_form.save()
|
||||
messages.success(request, 'Image uploaded successfully')
|
||||
messages.success(request, 'Image uploaded successfully.')
|
||||
return redirect('user_detail', pk=user.pk)
|
||||
else:
|
||||
messages.error(request, 'An error occurred while uploading the image')
|
||||
messages.error(request, 'An error occurred while uploading the image. Please check the errors below.')
|
||||
else:
|
||||
profile_form = ProfileImageUploadForm(instance=user.profile)
|
||||
|
||||
#
|
||||
profile_form = ProfileImageUploadForm(instance=profile_instance)
|
||||
context = {
|
||||
'profile_form': profile_form,
|
||||
'user': user,
|
||||
}
|
||||
return render(request, 'user/profile.html', context)
|
||||
|
||||
|
||||
|
||||
def user_detail(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
|
||||
|
||||
profile_form = ProfileImageUploadForm()
|
||||
|
||||
try:
|
||||
profile_instance = user.profile
|
||||
profile_form = ProfileImageUploadForm(instance=profile_instance)
|
||||
except:
|
||||
profile_form = ProfileImageUploadForm()
|
||||
|
||||
if request.method == 'POST':
|
||||
first_name=request.POST.get('first_name')
|
||||
last_name=request.POST.get('last_name')
|
||||
@ -2068,15 +2084,17 @@ def create_staff_user(request):
|
||||
@user_passes_test(is_superuser_check)
|
||||
def admin_settings(request):
|
||||
staffs=User.objects.filter(is_superuser=False)
|
||||
form = ToggleAccountForm()
|
||||
context={
|
||||
'staffs':staffs
|
||||
'staffs':staffs,
|
||||
'form':form
|
||||
}
|
||||
return render(request,'user/admin_settings.html',context)
|
||||
|
||||
|
||||
from django.contrib.auth.forms import SetPasswordForm
|
||||
|
||||
|
||||
@user_passes_test(is_superuser_check)
|
||||
def set_staff_password(request,pk):
|
||||
user=get_object_or_404(User,pk=pk)
|
||||
print(request.POST)
|
||||
@ -2085,10 +2103,11 @@ def set_staff_password(request,pk):
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request,f'Password successfully changed')
|
||||
return redirect('admin_settings')
|
||||
else:
|
||||
form=SetPasswordForm(user=user)
|
||||
messages.error(request,f'Password does not match please try again.')
|
||||
return redirect('set_staff_password',user=user)
|
||||
return redirect('admin_settings')
|
||||
|
||||
else:
|
||||
form=SetPasswordForm(user=user)
|
||||
@ -2096,6 +2115,28 @@ def set_staff_password(request,pk):
|
||||
|
||||
|
||||
|
||||
@user_passes_test(is_superuser_check)
|
||||
def account_toggle_status(request,pk):
|
||||
user=get_object_or_404(User,pk=pk)
|
||||
if request.method=='POST':
|
||||
print(user.is_active)
|
||||
form=ToggleAccountForm(request.POST)
|
||||
if form.is_valid():
|
||||
if user.is_active:
|
||||
user.is_active=False
|
||||
user.save()
|
||||
messages.success(request,f'Staff with email: {user.email} deactivated successfully')
|
||||
return redirect('admin_settings')
|
||||
else:
|
||||
user.is_active=True
|
||||
user.save()
|
||||
messages.success(request,f'Staff with email: {user.email} activated successfully')
|
||||
return redirect('admin_settings')
|
||||
else:
|
||||
messages.error(f'Please correct the error below')
|
||||
|
||||
|
||||
|
||||
|
||||
# @login_required
|
||||
# def user_detail(requests,pk):
|
||||
|
||||
155
templates/account/account_inactive.html
Normal file
155
templates/account/account_inactive.html
Normal file
@ -0,0 +1,155 @@
|
||||
{% load static i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% translate "Account Inactive" %} - KAAUH ATS</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
{# Include Font Awesome for icons #}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" crossorigin="anonymous">
|
||||
|
||||
|
||||
<style>
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* CUSTOM TEAL THEME OVERRIDES FOR BOOTSTRAP (Copied from your Sign In page) */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
:root {
|
||||
--bs-primary: #00636e; /* Dark Teal */
|
||||
--bs-primary-rgb: 0, 99, 110;
|
||||
--bs-primary-light: #007a88;
|
||||
--bs-body-bg: #f8f9fa;
|
||||
--bs-body-color: #212529;
|
||||
--bs-border-color: #dee2e6;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
/* Custom Left Panel */
|
||||
.left-panel {
|
||||
flex: 1;
|
||||
background: url("{% static 'image/kaauh_banner.png' %}") no-repeat center center;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 3rem;
|
||||
color: white;
|
||||
z-index: 1;
|
||||
}
|
||||
.left-panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 50%);
|
||||
z-index: 0;
|
||||
}
|
||||
.left-panel-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Right Panel Styling */
|
||||
.right-panel {
|
||||
background-color: white;
|
||||
padding: 3rem;
|
||||
}
|
||||
.form-fields {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Component Overrides to use Teal Theme */
|
||||
.btn-primary {
|
||||
background-color: var(--bs-primary);
|
||||
border-color: var(--bs-primary);
|
||||
font-weight: 600;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 8px rgba(0, 99, 110, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: var(--bs-primary-light);
|
||||
border-color: var(--bs-primary-light);
|
||||
box-shadow: 0 6px 10px rgba(0, 99, 110, 0.3);
|
||||
}
|
||||
.text-accent {
|
||||
color: var(--bs-primary) !important;
|
||||
}
|
||||
|
||||
/* ADJUSTED: Custom size adjustment for right panel on desktop */
|
||||
@media (min-width: 992px) {
|
||||
.right-panel-col {
|
||||
flex: 0 0 450px;
|
||||
}
|
||||
.right-panel-col > .d-flex {
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.right-panel-content-wrapper {
|
||||
max-width: 350px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="d-flex vh-100 w-100">
|
||||
|
||||
<div class="left-panel d-none d-lg-flex flex-grow-1">
|
||||
<div class="left-panel-content">
|
||||
<h1 class="text-4xl font-weight-bold mb-4" style="font-size: 1.5rem;">
|
||||
<span class="text-white">
|
||||
<div class="hospital-text text-center text-md-start me-3">
|
||||
<div class="ar small">{% translate "جامعة الأميرة نورة بنت عبدالرحمن الأكاديمية" %}</div>
|
||||
<div class="ar small">{% translate "ومستشفى الملك عبدالله بن عبدالعزيز التخصصي" %}</div>
|
||||
<div class="en small">{% translate "Princess Nourah bint Abdulrahman University" %}</div>
|
||||
<div class="en small">{% translate "King Abdullah bin Abdulaziz University Hospital" %}</div>
|
||||
</div>
|
||||
</span>
|
||||
</h1>
|
||||
<small>Powered By TENHAL | تنحل</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column right-panel right-panel-col flex-grow-1 align-items-center justify-content-center">
|
||||
|
||||
<div class="right-panel-content-wrapper text-center">
|
||||
|
||||
<i class="fas fa-user-slash text-danger mb-4" style="font-size: 3rem;"></i>
|
||||
|
||||
<h2 id="form-title" class="h3 fw-bold mb-3 text-danger">{% translate "Account Inactive" %}</h2>
|
||||
|
||||
<div class="form-fields">
|
||||
<p class="lead text-muted mb-4">
|
||||
{% translate "Access denied. This account has been marked as inactive by an administrator." %}
|
||||
</p>
|
||||
<p class="text-muted small">
|
||||
{% translate "If you believe this is an error, please contact the system administrator for assistance." %}
|
||||
</p>
|
||||
|
||||
<div class="d-grid mt-4">
|
||||
<a href="{% url 'account_login' %}" class="btn btn-outline-secondary w-100">
|
||||
<i class="fas fa-sign-in-alt me-2"></i> {% translate "Return to Sign In" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
125
templates/account/email.html
Normal file
125
templates/account/email.html
Normal file
@ -0,0 +1,125 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}{% translate "Email Addresses" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<h3 class="fw-bold">{% translate "Account Settings" %}</h3>
|
||||
<p class="text-muted">{% translate "Manage your personal details and security." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
{# ------------------- LEFT COLUMN: ACCOUNT MENU (New Card Style) ------------------- #}
|
||||
<div class="col-md-4 col-lg-3 mb-4">
|
||||
<div class="card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush rounded-4">
|
||||
{# Assuming a main 'Profile' or 'Personal Information' page exists #}
|
||||
<a href="{% url 'user_detail' user.pk %}" class="list-group-item list-group-item-action border-0 rounded-top-4 py-3">
|
||||
<i class="fas fa-user-circle me-2"></i> {% translate "Personal Information" %}
|
||||
</a>
|
||||
|
||||
{# Highlight the current page (Email) as active #}
|
||||
<a href="{% url 'account_email' %}" class="list-group-item list-group-item-action active border-0 py-3" style="background-color: #e6f3f3; color: #008080; font-weight: 500;" aria-current="true">
|
||||
<i class="fas fa-envelope me-2"></i> {% translate "Email Addresses" %}
|
||||
</a>
|
||||
<a href="{% url 'account_change_password' %}" class="list-group-item list-group-item-action border-0 py-3">
|
||||
<i class="fas fa-lock me-2"></i> {% translate "Change Password" %}
|
||||
</a>
|
||||
|
||||
<a href="{% url 'account_logout' %}" class="list-group-item list-group-item-action border-0 rounded-bottom-4 text-danger py-3">
|
||||
<i class="fas fa-sign-out-alt me-2"></i> {% translate "Sign Out" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ------------------- RIGHT COLUMN: EMAIL MANAGEMENT ------------------- #}
|
||||
<div class="col-md-8 col-lg-9">
|
||||
<div class="card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h5 class="fw-bold mb-3">{% translate "Email Addresses" %}</h5>
|
||||
<p class="text-muted border-bottom pb-3">{% translate "These email addresses are linked to your account. You can set the primary address, resend verification, or remove an address." %}</p>
|
||||
|
||||
{% if emailaddresses %}
|
||||
{% for emailaddress in emailaddresses %}
|
||||
<div class="d-flex flex-column flex-sm-row justify-content-between align-items-sm-center py-3 {% if not forloop.last %}border-bottom{% endif %}">
|
||||
|
||||
<p class="mb-2 mb-sm-0 me-3">
|
||||
<span class="fw-bold text-dark">{{ emailaddress.email }}</span>
|
||||
|
||||
{# Status Badges: Using rounded-pill and appropriate colors #}
|
||||
{% if emailaddress.primary %}
|
||||
<span class="badge rounded-pill bg-info text-dark ms-2">{% translate "Primary" %}</span>
|
||||
{% endif %}
|
||||
{% if emailaddress.verified %}
|
||||
<span class="badge rounded-pill bg-success ms-2">{% translate "Verified" %}</span>
|
||||
{% else %}
|
||||
<span class="badge rounded-pill bg-warning text-dark ms-2">{% translate "Unverified" %}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
|
||||
{# 1. MAKE PRIMARY ACTION #}
|
||||
{% if not emailaddress.primary %}
|
||||
<form method="post" action="{% url 'account_email' %}" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="email" value="{{ emailaddress.email }}" />
|
||||
<input type="hidden" name="action" value="set_primary" />
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">{% translate "Make Primary" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{# 2. RESEND VERIFICATION ACTION #}
|
||||
{% if not emailaddress.verified %}
|
||||
<form method="post" action="{% url 'account_email' %}" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="email" value="{{ emailaddress.email }}" />
|
||||
<input type="hidden" name="action" value="send" />
|
||||
<button type="submit" class="btn btn-sm btn-outline-warning">{% translate "Re-send Verification" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{# 3. REMOVE ACTION #}
|
||||
{% if not emailaddress.primary %}
|
||||
<form method="post" action="{% url 'account_email' %}" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="email" value="{{ emailaddress.email }}" />
|
||||
<input type="hidden" name="action" value="remove" />
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">{% translate "Remove" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="alert alert-info mt-3">{% translate "No email addresses found." %}</p>
|
||||
{% endif %}
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
{# ------------------- ADD EMAIL FORM ------------------- #}
|
||||
<h5 class="fw-bold mb-3">{% translate "Add Email Address" %}</h5>
|
||||
<form method="post" action="{% url 'account_email' %}">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{# Teal/Dark Green button consistent with "Save Changes" #}
|
||||
<button class="btn btn-success mt-3" type="submit" style="background-color: #008080; border-color: #008080;">{% translate "Add Email" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
39
templates/account/email/password_reset_key_message.html
Normal file
39
templates/account/email/password_reset_key_message.html
Normal file
@ -0,0 +1,39 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% autoescape off %}
|
||||
|
||||
<div style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: auto; border: 1px solid #ddd; border-radius: 8px; overflow: hidden;">
|
||||
|
||||
<div style="background-color: #00636e; padding: 20px; color: white; text-align: center;">
|
||||
<h1 style="margin: 0; font-size: 24px;">{% trans "Password Reset Request" %}</h1>
|
||||
</div>
|
||||
|
||||
<div style="padding: 20px;">
|
||||
<p>{% trans "Hello," %}</p>
|
||||
|
||||
<p>{% trans "You are receiving this email because you or someone else has requested a password reset for your account at" %} <strong>{{ current_site.name }}</strong>.</p>
|
||||
|
||||
<p style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ password_reset_url }}"
|
||||
style="display: inline-block; padding: 10px 20px; color: white; background-color: #00636e; border-radius: 5px; text-decoration: none; font-weight: bold;">
|
||||
{% trans "Click Here to Reset Your Password" %}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>{% trans "This link is only valid for a limited time." %}</p>
|
||||
|
||||
<p>{% trans "If you did not request a password reset, please ignore this email. Your password will remain unchanged." %}</p>
|
||||
|
||||
<p>
|
||||
{% trans "Thank you," %}<br>
|
||||
{% trans "KAAUH ATS Team" %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="background-color: #f4f4f4; padding: 15px; font-size: 12px; color: #777; text-align: center;">
|
||||
{% trans "If the button above does not work, copy and paste the following link into your browser:" %}<br>
|
||||
<a href="{{ password_reset_url }}" style="color: #00636e; word-break: break-all;">{{ password_reset_url }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endautoescape %}
|
||||
71
templates/account/email_confirm.html
Normal file
71
templates/account/email_confirm.html
Normal file
@ -0,0 +1,71 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
|
||||
{% block title %}{% translate "Confirm Email Address" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<h3 class="fw-bold">{% translate "Account Verification" %}</h3>
|
||||
<p class="text-muted">{% translate "Verify your email to secure your account and unlock full features." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 col-lg-6">
|
||||
<div class="card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-5 text-center">
|
||||
|
||||
{% with emailaddress.email as email %}
|
||||
|
||||
{% if confirmation %}
|
||||
|
||||
{# ------------------- CONFIRMATION REQUEST (GET) ------------------- #}
|
||||
{% user_display confirmation.email_address.user as user_display %}
|
||||
|
||||
<i class="fas fa-envelope-open-text mb-4" style="font-size: 3rem; color: #008080;"></i>
|
||||
<h4 class="fw-bold mb-3">{% translate "Confirm Your Email Address" %}</h4>
|
||||
|
||||
<p class="lead text-muted">
|
||||
{% blocktrans with email as email %}Please confirm that **{{ email }}** is an email address for user **{{ user_display }}**.{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
{# Confirmation Form #}
|
||||
<form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
|
||||
{% csrf_token %}
|
||||
|
||||
{# Teal/Dark Green button consistent with the UI theme #}
|
||||
<button class="btn btn-lg mt-4 px-5" type="submit" style="background-color: #008080; border-color: #008080; color: white;">
|
||||
{% translate "Confirm" %}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% else %}
|
||||
|
||||
{# ------------------- CONFIRMATION FAILED (Error) ------------------- #}
|
||||
<i class="fas fa-exclamation-triangle text-danger mb-4" style="font-size: 3rem;"></i>
|
||||
<h4 class="fw-bold mb-3 text-danger">{% translate "Invalid Link" %}</h4>
|
||||
|
||||
<p class="lead">
|
||||
{% translate "The email confirmation link has expired or is invalid." %}
|
||||
</p>
|
||||
<p class="text-muted">
|
||||
{% translate "Please request a new verification email from your account settings page." %}
|
||||
</p>
|
||||
|
||||
<a href="{% url 'account_email' %}" class="btn btn-outline-secondary mt-3 px-5">
|
||||
{% translate "Go to Settings" %}
|
||||
</a>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
80
templates/account/logout.html
Normal file
80
templates/account/logout.html
Normal file
@ -0,0 +1,80 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
|
||||
{% block title %}{% translate "Sign Out" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<h3 class="fw-bold">{% translate "Account Settings" %}</h3>
|
||||
<p class="text-muted">{% translate "Manage your personal details and security." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
{# ------------------- LEFT COLUMN: ACCOUNT MENU (New Card Style) ------------------- #}
|
||||
<div class="col-md-4 col-lg-3 mb-4">
|
||||
<div class="card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush rounded-4">
|
||||
{# Assuming a main 'Profile' or 'Personal Information' page exists #}
|
||||
<a href="{% url 'user_detail' user.pk %}" class="list-group-item list-group-item-action border-0 rounded-top-4 py-3">
|
||||
<i class="fas fa-user-circle me-2"></i> {% translate "Personal Information" %}
|
||||
</a>
|
||||
<a href="{% url 'account_email' %}" class="list-group-item list-group-item-action border-0 py-3">
|
||||
<i class="fas fa-envelope me-2"></i> {% translate "Email Addresses" %}
|
||||
</a>
|
||||
<a href="{% url 'account_change_password' %}" class="list-group-item list-group-item-action border-0 py-3">
|
||||
<i class="fas fa-lock me-2"></i> {% translate "Change Password" %}
|
||||
</a>
|
||||
|
||||
{# Highlight the current page (Sign Out) as active #}
|
||||
<a href="{% url 'account_logout' %}" class="list-group-item list-group-item-action active border-0 rounded-bottom-4 py-3" style="background-color: #fce8e8; color: #dc3545; font-weight: 500;" aria-current="true">
|
||||
<i class="fas fa-sign-out-alt me-2"></i> {% translate "Sign Out" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ------------------- RIGHT COLUMN: LOGOUT CONFIRMATION ------------------- #}
|
||||
<div class="col-md-8 col-lg-9">
|
||||
<div class="card shadow-sm border-0 rounded-4">
|
||||
<div class="card-body p-4 text-center">
|
||||
|
||||
<i class="fas fa-sign-out-alt text-danger mb-4" style="font-size: 3rem;"></i>
|
||||
<h4 class="fw-bold mb-3">{% translate "Confirm Sign Out" %}</h4>
|
||||
|
||||
<p class="lead mb-4">{% translate "Are you sure you want to sign out of your account?" %}</p>
|
||||
|
||||
<form method="post" action="{% url 'account_logout' %}">
|
||||
{% csrf_token %}
|
||||
|
||||
{% if redirect_field_value %}
|
||||
<input type="hidden"
|
||||
name="{{ redirect_field_name }}"
|
||||
value="{{ redirect_field_value }}" />
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-center gap-3 mt-4">
|
||||
{# Sign Out button in danger color #}
|
||||
<button class="btn btn-danger btn-lg px-5" type="submit">
|
||||
{% translate "Sign Out" %}
|
||||
</button>
|
||||
|
||||
{# Cancel/Go Back button with outline #}
|
||||
<a class="btn btn-outline-secondary btn-lg px-5" href="{% url 'account_email' %}">
|
||||
{% translate "Cancel" %}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@ -7,7 +7,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex vh-80 w-100 justify-content-center align-items-center">
|
||||
<div class="d-flex vh-80 w-100 justify-content-center align-items-center mt-5">
|
||||
|
||||
<div class="form-card">
|
||||
|
||||
|
||||
@ -7,120 +7,39 @@
|
||||
<title>{% trans "Set New Password" %} - KAAUH ATS</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" crossorigin="anonymous">
|
||||
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
|
||||
<style>
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* CUSTOM TEAL THEME OVERRIDES FOR BOOTSTRAP (Copied from provided login page) */
|
||||
/* CUSTOM TEAL THEME OVERRIDES FOR BOOTSTRAP (Consistent with your UI) */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
:root {
|
||||
/* Define TEAL as the primary color for Bootstrap overrides */
|
||||
--bs-primary: #00636e; /* Dark Teal */
|
||||
--bs-primary-rgb: 0, 99, 110;
|
||||
--bs-primary-light: #007a88; /* Lighter Teal for hover */
|
||||
|
||||
/* Background and Text Colors */
|
||||
--bs-body-bg: #f8f9fa; /* Light gray background */
|
||||
--bs-body-color: #212529; /* Dark text */
|
||||
|
||||
/* Utility colors */
|
||||
--bs-border-color: #dee2e6; /* Bootstrap default border */
|
||||
--bs-body-bg: #f8f9fa;
|
||||
--bs-body-color: #212529;
|
||||
--bs-border-color: #dee2e6;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
/* Custom Left Panel (Replicating the original look) */
|
||||
.left-panel {
|
||||
flex: 1;
|
||||
/* NOTE: Static image URL is included here. Ensure 'image/kaauh_banner.png' exists in your static files. */
|
||||
background: url("{% static 'image/kaauh_banner.png' %}") no-repeat center center;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 3rem;
|
||||
color: white;
|
||||
z-index: 1;
|
||||
}
|
||||
.left-panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 50%);
|
||||
z-index: 0;
|
||||
}
|
||||
.left-panel-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Right Panel Styling */
|
||||
.right-panel {
|
||||
background-color: white;
|
||||
padding: 3rem;
|
||||
}
|
||||
.form-fields {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Component Overrides to use Teal Theme */
|
||||
.btn-primary {
|
||||
background-color: var(--bs-primary);
|
||||
border-color: var(--bs-primary);
|
||||
font-weight: 600;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 8px rgba(0, 99, 110, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: var(--bs-primary-light);
|
||||
border-color: var(--bs-primary-light);
|
||||
box-shadow: 0 6px 10px rgba(0, 99, 110, 0.3);
|
||||
}
|
||||
.form-control:focus {
|
||||
border-color: var(--bs-primary);
|
||||
box-shadow: 0 0 0 0.25rem rgba(0, 99, 110, 0.25);
|
||||
}
|
||||
.text-accent {
|
||||
color: var(--bs-primary) !important;
|
||||
}
|
||||
.text-accent:hover {
|
||||
color: var(--bs-primary-light) !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.alert-info-custom {
|
||||
background-color: #f0f8ff; /* Very light blue */
|
||||
border-left: 5px solid var(--bs-primary);
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
/* ADJUSTED: Custom size adjustment for right panel on desktop */
|
||||
body { font-family: 'Inter', sans-serif; background-color: var(--bs-body-bg); }
|
||||
.left-panel { flex: 1; background: url("{% static 'image/kaauh_banner.png' %}") no-repeat center center; background-size: cover; position: relative; display: flex; align-items: flex-end; padding: 3rem; color: white; z-index: 1; }
|
||||
.left-panel::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 50%); z-index: 0; }
|
||||
.left-panel-content { position: relative; z-index: 2; }
|
||||
.right-panel { background-color: white; padding: 3rem; }
|
||||
.form-fields { max-height: 100%; overflow-y: auto; }
|
||||
.btn-primary { background-color: var(--bs-primary); border-color: var(--bs-primary); font-weight: 600; border-radius: 0.5rem; box-shadow: 0 4px 8px rgba(0, 99, 110, 0.2); transition: all 0.2s ease; }
|
||||
.btn-primary:hover { background-color: var(--bs-primary-light); border-color: var(--bs-primary-light); box-shadow: 0 6px 10px rgba(0, 99, 110, 0.3); }
|
||||
.form-control:focus { border-color: var(--bs-primary); box-shadow: 0 0 0 0.25rem rgba(0, 99, 110, 0.25); }
|
||||
.text-accent { color: var(--bs-primary) !important; }
|
||||
.text-accent:hover { color: var(--bs-primary-light) !important; text-decoration: underline; }
|
||||
.alert-info-custom { background-color: #f0f8ff; border-left: 5px solid var(--bs-primary); color: var(--bs-primary); }
|
||||
@media (min-width: 992px) {
|
||||
/* 1. Set a NARROWER fixed width for the right panel container */
|
||||
.right-panel-col {
|
||||
flex: 0 0 450px; /* Width of the panel */
|
||||
}
|
||||
/* 2. Vertically and horizontally center the content within the narrow panel */
|
||||
.right-panel-col > .d-flex {
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
/* 3. Ensure the form container doesn't exceed a smaller size and is centered */
|
||||
.right-panel-content-wrapper {
|
||||
max-width: 350px; /* Max width of the form elements inside the panel */
|
||||
width: 100%;
|
||||
}
|
||||
.right-panel-col { flex: 0 0 450px; }
|
||||
.right-panel-col > .d-flex { height: 100%; justify-content: center; align-items: center; padding-top: 0; padding-bottom: 0; }
|
||||
.right-panel-content-wrapper { max-width: 350px; width: 100%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@ -153,14 +72,17 @@
|
||||
<div class="form-fields">
|
||||
|
||||
{% if form %}
|
||||
<p class="text-muted small mb-1 text-center">
|
||||
{% trans 'Please enter your new password below.' %}
|
||||
</p>
|
||||
<p class="text-muted small mb-4 text-center">
|
||||
{% trans 'Please enter your new password below. You can then log in.' %}
|
||||
{% trans 'You can then log in.' %}
|
||||
</p>
|
||||
|
||||
<form method="post" action="{{ action_url }}">
|
||||
<form method="post" action=".">
|
||||
{% csrf_token %}
|
||||
|
||||
{# Display any general form errors #}
|
||||
{# Non-Field Errors (General errors like tokens or passwords not matching) #}
|
||||
{% if form.non_field_errors %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{% for error in form.non_field_errors %}
|
||||
@ -173,9 +95,12 @@
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.password.id_for_label }}" class="form-label fw-semibold">{% trans "New Password" %} *</label>
|
||||
|
||||
{# **CRITICAL FIX:** Iterate over the errors to display them correctly #}
|
||||
{% if form.password.errors %}
|
||||
<div class="alert alert-danger p-2 small">
|
||||
{{ form.password.errors }}
|
||||
{% for error in form.password.errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@ -187,9 +112,12 @@
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.password2.id_for_label }}" class="form-label fw-semibold">{% trans "Confirm New Password" %} *</label>
|
||||
|
||||
{# **CRITICAL FIX:** Iterate over the errors to display them correctly #}
|
||||
{% if form.password2.errors %}
|
||||
<div class="alert alert-danger p-2 small">
|
||||
{{ form.password2.errors }}
|
||||
{% for error in form.password2.errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@ -197,12 +125,12 @@
|
||||
class="form-control" placeholder="{% trans 'Confirm new password' %}" required>
|
||||
</div>
|
||||
|
||||
{# Hidden fields, if any (like uidb64, token/key) #}
|
||||
{# Hidden fields MUST be present for the POST request to be valid #}
|
||||
{{ form.uid }}
|
||||
{{ form.token }}
|
||||
|
||||
{# Submit Button #}
|
||||
<button type="submit" name="action" class="btn btn-primary w-100 mt-4">
|
||||
<button type="submit" class="btn btn-primary w-100 mt-4">
|
||||
{% trans "Change Password" %}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
87
templates/account/password_reset_from_key_done.html
Normal file
87
templates/account/password_reset_from_key_done.html
Normal file
@ -0,0 +1,87 @@
|
||||
{% load static i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% trans "Password Changed" %} - KAAUH ATS</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" crossorigin="anonymous">
|
||||
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
|
||||
<style>
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* CUSTOM TEAL THEME OVERRIDES (Consistent with your UI) */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
:root {
|
||||
--bs-primary: #00636e; /* Dark Teal */
|
||||
--bs-primary-rgb: 0, 99, 110;
|
||||
--bs-primary-light: #007a88; /* Lighter Teal for hover */
|
||||
--bs-body-bg: #f8f9fa;
|
||||
--bs-body-color: #212529;
|
||||
}
|
||||
|
||||
body { font-family: 'Inter', sans-serif; background-color: var(--bs-body-bg); }
|
||||
.left-panel { flex: 1; background: url("{% static 'image/kaauh_banner.png' %}") no-repeat center center; background-size: cover; position: relative; display: flex; align-items: flex-end; padding: 3rem; color: white; z-index: 1; }
|
||||
.left-panel::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 50%); z-index: 0; }
|
||||
.left-panel-content { position: relative; z-index: 2; }
|
||||
.right-panel { background-color: white; padding: 3rem; }
|
||||
.btn-primary { background-color: var(--bs-primary); border-color: var(--bs-primary); font-weight: 600; border-radius: 0.5rem; box-shadow: 0 4px 8px rgba(0, 99, 110, 0.2); transition: all 0.2s ease; }
|
||||
.btn-primary:hover { background-color: var(--bs-primary-light); border-color: var(--bs-primary-light); box-shadow: 0 6px 10px rgba(0, 99, 110, 0.3); }
|
||||
.text-accent { color: var(--bs-primary) !important; }
|
||||
.text-success-accent { color: #28a745 !important; } /* Standard green for success */
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.right-panel-col { flex: 0 0 450px; }
|
||||
.right-panel-col > .d-flex { height: 100%; justify-content: center; align-items: center; padding-top: 0; padding-bottom: 0; }
|
||||
.right-panel-content-wrapper { max-width: 350px; width: 100%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="d-flex vh-100 w-100">
|
||||
|
||||
<div class="left-panel d-none d-lg-flex flex-grow-1">
|
||||
<div class="left-panel-content">
|
||||
<h1 class="text-4xl font-weight-bold mb-4" style="font-size: 1.5rem;">
|
||||
<span class="text-white">
|
||||
<div class="hospital-text text-center text-md-start me-3">
|
||||
<div class="ar small">{% trans "جامعة الأميرة نورة بنت عبدالرحمن الأكاديمية" %}</div>
|
||||
<div class="ar small">{% trans "ومستشفى الملك عبدالله بن عبدالعزيز التخصصي" %}</div>
|
||||
<div class="en small">{% trans "Princess Nourah bint Abdulrahman University" %}</div>
|
||||
<div class="en small">{% trans "King Abdullah bin Abdulaziz University Hospital" %}</div>
|
||||
</div>
|
||||
</span>
|
||||
</h1>
|
||||
<small>Powered By TENHAL | تنحل</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column right-panel right-panel-col flex-grow-1 align-items-center justify-content-center">
|
||||
|
||||
<div class="right-panel-content-wrapper text-center">
|
||||
|
||||
<i class="fas fa-check-circle text-success-accent mb-4" style="font-size: 3rem;"></i>
|
||||
|
||||
<h2 class="h3 fw-bold mb-3 text-accent">{% trans "Password Changed Successfully" %}</h2>
|
||||
|
||||
<p class="text-muted mb-4">
|
||||
{% trans "Your password has been set. You can now use your new password to sign in." %}
|
||||
</p>
|
||||
|
||||
<div class="d-grid mt-4">
|
||||
<a href="{% url 'account_login' %}" class="btn btn-primary btn-lg">
|
||||
<i class="fas fa-sign-in-alt me-2"></i> {% trans "Go to Sign In" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -16,7 +16,9 @@
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
{% endif %}
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
||||
|
||||
<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' %}">
|
||||
|
||||
|
||||
@ -150,7 +152,7 @@
|
||||
{% if request.user.is_superuser %}
|
||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="{% url 'admin_settings' %}"><i class="fas fa-cog me-3 text-primary fs-5"></i> <span>{% trans "Settings" %}</span></a></li>
|
||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="{% url 'easy_logs' %}"><i class="fas fa-history me-3 text-primary fs-5"></i> <span>{% trans "Activity Log" %}</span></a></li>
|
||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li>
|
||||
{% comment %} <li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li> {% endcomment %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@ -275,7 +275,7 @@
|
||||
{% elif active_tab == 'request' %}
|
||||
<tr>
|
||||
<td>{{ log.datetime|date:"Y-m-d H:i:s" }}</td>
|
||||
<td>{{ log.user.get_full_name|default:log.user.username|default:"Anonymous" }}</td>
|
||||
<td>{{ log.user.get_full_name|default:log.user.email|default:"Anonymous" }}</td>
|
||||
<td>
|
||||
<span class="badge rounded-pill badge-request-method">{{ log.method }}</span>
|
||||
</td>
|
||||
|
||||
@ -326,11 +326,11 @@
|
||||
</td>
|
||||
|
||||
{# CANDIDATE MANAGEMENT DATA - URLS NEUTRALIZED #}
|
||||
<td class="candidate-data-cell text-primary-theme"><a href="#" class="text-primary-theme">{% if job.applying_count %}{{ job.applying_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-info"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-info">{% if job.screening_count %}{{ job.screening_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-success">{% if job.exam_count %}{{ job.exam_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_exam_view' job.slug %}" class="text-success">{% if job.interview_count %}{{ job.interview_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_interview_view' job.slug %}" class="text-success">{% if job.offer_count %}{{ job.offer_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-primary-theme"><a href="#" class="text-primary-theme">{% if job.all_candidates_count %}{{job.all_candidates_count}}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-info"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-info">{% if job.screening_candidates_count %}{{ job.screening_candidates_count }}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-success">{% if job.exam_candidates_count %}{{ job.exam_candidates_count}}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_exam_view' job.slug %}" class="text-success">{% if job.interview_candidates_count %}{{ job.interview_candidates_count}}{% else %}-{% endif %}</a></td>
|
||||
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_interview_view' job.slug %}" class="text-success">{% if job.offer_candidates_count%}{{ job.offer_candidates_count }}{% else %}-{% endif %}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@ -102,6 +102,19 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
button i.fa-solid {
|
||||
/* Re-enable display if it was hidden */
|
||||
display: inline-block;
|
||||
/* Ensure the correct font family is applied */
|
||||
font-family: "Font Awesome 6 Free";
|
||||
/* Inherit button color */
|
||||
color: inherit;
|
||||
}
|
||||
.text-primary{
|
||||
color:var(--kaauh-teal) !important;
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@ -175,20 +188,44 @@
|
||||
|
||||
<td class="text-center">
|
||||
<div class="action-btns">
|
||||
{# 1. Edit Button (Pencil Icon) #}
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit User' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
|
||||
|
||||
{# 2. Change Password Button (Key Icon) #}
|
||||
<a href="{% url 'set_staff_password' user.pk %}" class="btn btn-sm btn-outline-info" title="{% trans 'Change Password' %}">
|
||||
<i class="fas fa-key"></i>
|
||||
{% trans 'Change Password' %}
|
||||
</a>
|
||||
|
||||
{# 3. Delete Button (Trash Icon) #}
|
||||
<a href="#" class="btn btn-sm btn-outline-danger" title="{% trans 'Delete User' %}">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</a>
|
||||
|
||||
{% if user.is_active %}
|
||||
|
||||
|
||||
<form method="post" action="{% url 'account_toggle_status' user.pk %}">
|
||||
{% csrf_token %}
|
||||
|
||||
{# The button for DEACTIVATION #}
|
||||
<button type="submit" >
|
||||
<i class="fas fa-times-circle text-danger"></i> Deactivate
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% else %}
|
||||
|
||||
<form method="post" action="{% url 'account_toggle_status' user.pk %}">
|
||||
{% csrf_token %}
|
||||
|
||||
{# The button for REACTIVATION #}
|
||||
|
||||
|
||||
<button type="submit bg-primary" >
|
||||
<i class="fas fa-check-circle text-primary"></i> Activate
|
||||
</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -191,9 +191,11 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!--modal for image upload-->
|
||||
|
||||
<!--modal class for image upload-->
|
||||
<div class="modal fade mt-4" id="myModalForm" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@ -204,14 +206,51 @@
|
||||
<div class="modal-body">
|
||||
<form method="post" action="{% url 'user_profile_image_update' user.pk %}" enctype="multipart/form-data" >
|
||||
{% csrf_token %}
|
||||
{{ profile_form.as_p}}
|
||||
|
||||
{% if image_upload_form.instance.post_image %}
|
||||
<p>Current Image:</p>
|
||||
<img src="{{ image_upload_form.instance.post_image.url }}" alt="Post Image" style="max-width: 200px;">
|
||||
<div class="mb-3">
|
||||
<label for="{{ profile_form.profile_image.id_for_label }}" class="form-label">Profile Image</label>
|
||||
|
||||
{# 1. Check if an image currently exists on the bound instance #}
|
||||
{% if profile_form.instance.profile_image %}
|
||||
|
||||
<div class="mb-2">
|
||||
<small class="text-muted d-block">Current Image:</small>
|
||||
|
||||
{# Display Link to View Current Image #}
|
||||
<a href="{{ profile_form.instance.profile_image.url }}" target="_blank" class="d-inline-block me-3 text-info fw-bold">
|
||||
View/Download ({{ profile_form.instance.profile_image.name }})
|
||||
</a>
|
||||
|
||||
{# Image Preview #}
|
||||
<div class="mt-2">
|
||||
<img src="{{ profile_form.instance.profile_image.url }}"
|
||||
alt="Profile Image"
|
||||
style="max-width: 150px; height: auto; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# 2. Explicitly render the 'Clear' checkbox and the Change input #}
|
||||
<div class="form-check mt-3">
|
||||
{# The ClearableFileInput widget renders itself here. It provides the "Clear" checkbox and the "Change" input field. #}
|
||||
{{ profile_form.profile_image }}
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
{# If no image exists, just render the file input for upload #}
|
||||
<div class="form-control p-0 border-0">
|
||||
{{ profile_form.profile_image }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="modal-footer mt-2">
|
||||
<button type="button" class="btn btn-lg btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
|
||||
{# Display any validation errors #}
|
||||
{% for error in profile_form.profile_image.errors %}
|
||||
<div class="text-danger small mt-1">{{ error }}</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer mt-4">
|
||||
<button type="button" class="btn btn-lg btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -219,5 +258,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user