merge main with person update

This commit is contained in:
ismail 2025-11-13 16:14:59 +03:00
parent 9497bf102e
commit 5285335498
92 changed files with 249 additions and 11983 deletions

View File

@ -471,7 +471,7 @@ CKEDITOR_5_CONFIGS = {
# Define a constant in settings.py to specify file upload permissions
CKEDITOR_5_FILE_UPLOAD_PERMISSION = (
"staff" # Possible values: "staff", "authenticated", "any"
)
@ -479,7 +479,7 @@ from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.ERROR: 'danger',
}
)
# Custom User Model
AUTH_USER_MODEL = "recruitment.CustomUser"

View File

@ -1,119 +0,0 @@
#!/usr/bin/env python3
"""
Script to apply all batch translations to the main django.po file
"""
import re
def apply_all_translations():
"""
Apply all translations to the main django.po file
"""
# All translations from batches 02-35
translations = {
"The date and time this notification is scheduled to be sent.": "التاريخ والوقت المحدد لإرسال هذا الإشعار.",
"Send Attempts": "محاولات الإرسال",
"Failed to start the job posting process. Please try again.": "فشل في بدء عملية نشر الوظيفة. يرجى المحاولة مرة أخرى.",
"You don't have permission to view this page.": "ليس لديك إذن لعرض هذه الصفحة.",
"Account Inactive": "الحساب غير نشط",
"Princess Nourah bint Abdulrahman University": "جامعة الأميرة نورة بنت عبدالرحمن",
"Manage your personal details and security.": "إدارة تفاصيلك الشخصية والأمان.",
"Primary": "أساسي",
"Verified": "موثق",
"Unverified": "غير موثق",
"Make Primary": "جعل أساسي",
"Remove": "إزالة",
"Add Email Address": "إضافة عنوان بريد إلكتروني",
"Hello,": "مرحباً،",
"Confirm My KAAUH ATS Email": "تأكيد بريدي الإلكتروني في نظام توظيف جامعة نورة",
"Alternatively, copy and paste this link into your browser:": "بدلاً من ذلك، انسخ والصق هذا الرابط في متصفحك:",
"Password Reset Request": "طلب إعادة تعيين كلمة المرور",
"Click Here to Reset Your Password": "اضغط هنا لإعادة تعيين كلمة المرور",
"This link is only valid for a limited time.": "هذا الرابط صالح لفترة محدودة فقط.",
"Thank you,": "شكراً لك،",
"KAAUH ATS Team": "فريق نظام توظيف جامعة نورة",
"Confirm Email Address": "تأكيد عنوان البريد الإلكتروني",
"Account Verification": "التحقق من الحساب",
"Verify your email to secure your account and unlock full features.": "تحقق من بريدك الإلكتروني لتأمين حسابك وإلغاء قفل جميع الميزات.",
"Confirm Your Email Address": "تأكيد عنوان بريدك الإلكتروني",
"Verification Failed": "فشل التحقق",
"The email confirmation link is expired or invalid.": "رابط تأكيد البريد الإلكتروني منتهي الصلاحية أو غير صالح.",
"Keep me signed in": "ابق مسجلاً للدخول",
"Return to Profile": "العودة إلى الملف الشخصي",
"Enter your e-mail address to reset your password.": "أدخل عنوان بريدك الإلكتروني لإعادة تعيين كلمة المرور.",
"Remember your password?": "تتذكر كلمة المرور؟",
"Log In": "تسجيل الدخول",
"Password Reset Sent": "تم إرسال إعادة تعيين كلمة المرور",
"Return to Login": "العودة إلى تسجيل الدخول",
"Please enter your new password below.": "يرجى إدخال كلمة المرور الجديدة أدناه.",
"Logout": "تسجيل الخروج",
"Yes": "نعم",
"No": "لا",
"Success": "نجح",
"Login": "تسجيل الدخول",
"Link": "ربط",
"Clear": "مسح",
"All": "الكل",
"Comments": "التعليقات",
"Save": "حفظ",
"Notes": "ملاحظات",
"New": "جديد",
"Users": "المستخدمون",
"Filter": "تصفية",
"Home": "الرئيسية",
"Username": "اسم المستخدم",
"Modified": "تم التعديل",
"Unlink": "فك الربط",
"Group": "تجميع",
"Export": "تصدير",
"Import": "استيراد",
"None": "لا شيء",
"Add": "إضافة",
"True": "صحيح",
"False": "خطأ",
}
main_po_file = "locale/ar/LC_MESSAGES/django.po"
# Read the main django.po file
with open(main_po_file, 'r', encoding='utf-8') as f:
main_content = f.read()
# Apply translations to main file
updated_content = main_content
applied_count = 0
for english, arabic in translations.items():
# Pattern to find msgid followed by empty msgstr
pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""'
replacement = rf'\1 "{arabic}"'
if re.search(pattern, updated_content):
updated_content = re.sub(pattern, replacement, updated_content)
applied_count += 1
print(f"✓ Applied: '{english}' -> '{arabic}'")
else:
print(f"✗ Not found: '{english}'")
# Write updated content back to main file
with open(main_po_file, 'w', encoding='utf-8') as f:
f.write(updated_content)
print(f"\nApplied {applied_count} translations to {main_po_file}")
return applied_count
def main():
"""Main function to apply all translations"""
print("Applying all batch translations to main django.po file...")
applied_count = apply_all_translations()
if applied_count > 0:
print(f"\n✅ Successfully applied {applied_count} translations!")
print("Next steps:")
print("1. Run: python manage.py compilemessages")
print("2. Test the translations in the application")
else:
print("\n❌ No translations were applied.")
if __name__ == "__main__":
main()

View File

@ -1,85 +0,0 @@
#!/usr/bin/env python3
"""
Script to apply completed batch translations back to the main django.po file
"""
import re
def apply_batch_to_main_po(batch_file_path, main_po_path):
"""
Apply translations from a completed batch file to the main django.po file
"""
# Read the completed batch file
with open(batch_file_path, 'r', encoding='utf-8') as f:
batch_content = f.read()
# Extract translations from batch file
translations = {}
current_msgid = None
lines = batch_content.split('\n')
i = 0
while i < len(lines):
line = lines[i].strip()
if line.startswith('msgid: "'):
current_msgid = line[7:-1] # Extract msgid content
# Look for the Arabic translation line (next non-empty line after "Arabic Translation:")
j = i + 1
while j < len(lines) and not lines[j].strip().startswith('msgstr: "'):
j += 1
if j < len(lines) and lines[j].strip().startswith('msgstr: "'):
translation = lines[j].strip()[8:-1] # Extract msgstr content
if translation and current_msgid and translation != '""': # Only add non-empty translations
translations[current_msgid] = translation
print(f"Extracted: '{current_msgid}' -> '{translation}'")
current_msgid = None
i += 1
print(f"Found {len(translations)} translations to apply")
# Read the main django.po file
with open(main_po_path, 'r', encoding='utf-8') as f:
main_content = f.read()
# Apply translations to main file
updated_content = main_content
applied_count = 0
for english, arabic in translations.items():
# Pattern to find msgid followed by empty msgstr
pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""'
replacement = rf'\1 "{arabic}"'
if re.search(pattern, updated_content):
updated_content = re.sub(pattern, replacement, updated_content)
applied_count += 1
print(f"✓ Applied: '{english}' -> '{arabic}'")
else:
print(f"✗ Not found: '{english}'")
# Write updated content back to main file
with open(main_po_path, 'w', encoding='utf-8') as f:
f.write(updated_content)
print(f"\nApplied {applied_count} translations to {main_po_path}")
return applied_count
def main():
"""Main function to apply batch 01 translations"""
batch_file = "translation_batch_01_completed.txt"
main_po_file = "locale/ar/LC_MESSAGES/django.po"
print("Applying Batch 01 translations to main django.po file...")
applied_count = apply_batch_to_main_po(batch_file, main_po_file)
if applied_count > 0:
print(f"\n✅ Successfully applied {applied_count} translations!")
print("Next steps:")
print("1. Run: python manage.py compilemessages")
print("2. Test the translations in the application")
print("3. Continue with the next batch")
else:
print("\n❌ No translations were applied. Please check the batch file format.")
if __name__ == "__main__":
main()

View File

@ -1,84 +0,0 @@
#!/usr/bin/env python3
"""
Script to directly apply Arabic translations to the main django.po file
"""
import re
def apply_translations_direct():
"""
Apply translations directly to the main django.po file
"""
# Arabic translations for batch 01
translations = {
"Website": "الموقع الإلكتروني",
"Admin Notes": "ملاحظات المسؤول",
"Save Assignment": "حفظ التكليف",
"Assignment": "التكليف",
"Expires At": "ينتهي في",
"Access Token": "رمز الوصول",
"Subject": "الموضوع",
"Recipients": "المستلمون",
"Internal staff involved in the recruitment process for this job": "الموظفون الداخليون المشاركون في عملية التوظيف لهذه الوظيفة",
"External Participant": "مشارك خارجي",
"External participants involved in the recruitment process for this job": "المشاركون الخارجيون المشاركون في عملية التوظيف لهذه الوظيفة",
"Reason for canceling the job posting": "سبب إلغاء نشر الوظيفة",
"Name of person who cancelled this job": "اسم الشخص الذي ألغى هذه الوظيفة",
"Hired": "تم التوظيف",
"Author": "المؤلف",
"Endpoint URL for sending candidate data (for outbound sync)": "عنوان URL لنقطة النهاية لإرسال بيانات المرشح (للمزامنة الصادرة)",
"HTTP method for outbound sync requests": "طريقة HTTP لطلبات المزامنة الصادرة",
"HTTP method for connection testing": "طريقة HTTP لاختبار الاتصال",
"Custom Headers": "رؤوس مخصصة",
"JSON object with custom HTTP headers for sync requests": "كائن JSON يحتوي على رؤوس HTTP مخصصة لطلبات المزامنة",
"Supports Outbound Sync": "يدعم المزامنة الصادرة",
"Whether this source supports receiving candidate data from ATS": "ما إذا كان هذا المصدر يدعم استقبال بيانات المرشح من نظام تتبع المتقدمين",
"Expired": "منتهي الصلاحية",
"Maximum candidates agency can submit for this job": "الحد الأقصى للمرشحين الذين يمكن للوكالة تقديمهم لهذه الوظيفة"
}
main_po_file = "locale/ar/LC_MESSAGES/django.po"
# Read the main django.po file
with open(main_po_file, 'r', encoding='utf-8') as f:
main_content = f.read()
# Apply translations to main file
updated_content = main_content
applied_count = 0
for english, arabic in translations.items():
# Pattern to find msgid followed by empty msgstr
pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""'
replacement = rf'\1 "{arabic}"'
if re.search(pattern, updated_content):
updated_content = re.sub(pattern, replacement, updated_content)
applied_count += 1
print(f"✓ Applied: '{english}' -> '{arabic}'")
else:
print(f"✗ Not found: '{english}'")
# Write updated content back to main file
with open(main_po_file, 'w', encoding='utf-8') as f:
f.write(updated_content)
print(f"\nApplied {applied_count} translations to {main_po_file}")
return applied_count
def main():
"""Main function to apply batch 01 translations"""
print("Applying Batch 01 translations directly to main django.po file...")
applied_count = apply_translations_direct()
if applied_count > 0:
print(f"\n✅ Successfully applied {applied_count} translations!")
print("Next steps:")
print("1. Run: python manage.py compilemessages")
print("2. Test the translations in the application")
print("3. Continue with the next batch")
else:
print("\n❌ No translations were applied.")
if __name__ == "__main__":
main()

View File

@ -1,173 +0,0 @@
#!/usr/bin/env python3
"""
Script to find empty msgstr entries in django.po file and organize them into batches
for systematic Arabic translation work.
"""
import re
import os
from typing import List, Tuple
def find_empty_translations(po_file_path: str) -> List[Tuple[int, str, str]]:
"""
Find all entries with empty msgstr in the django.po file.
Returns:
List of tuples: (line_number, msgid, context_before)
"""
empty_translations = []
with open(po_file_path, 'r', encoding='utf-8') as file:
lines = file.readlines()
i = 0
while i < len(lines):
line = lines[i].strip()
# Look for msgid
if line.startswith('msgid '):
msgid = line[7:-1] # Remove 'msgid "' and ending '"'
# Check next few lines for msgstr
j = i + 1
msgstr_found = False
msgstr_empty = False
while j < len(lines) and j < i + 5: # Look ahead max 5 lines
next_line = lines[j].strip()
if next_line.startswith('msgstr '):
msgstr_found = True
if next_line == 'msgstr ""':
msgstr_empty = True
break
elif next_line.startswith('msgid ') or next_line.startswith('#'):
# Found next entry or comment, no msgstr for current msgid
break
j += 1
if msgstr_found and msgstr_empty:
# Get context (previous 2-3 lines)
context_start = max(0, i - 3)
context = ''.join(lines[context_start:i])
empty_translations.append((i + 1, msgid, context))
i = j # Skip to after msgstr
else:
i += 1
return empty_translations
def create_batch_files(empty_translations: List[Tuple[int, str, str]], batch_size: int = 25):
"""
Create batch files with empty translations for systematic work.
"""
total_batches = (len(empty_translations) + batch_size - 1) // batch_size
print(f"Found {len(empty_translations)} empty translations")
print(f"Creating {total_batches} batches of ~{batch_size} translations each")
for batch_num in range(total_batches):
start_idx = batch_num * batch_size
end_idx = min(start_idx + batch_size, len(empty_translations))
batch_translations = empty_translations[start_idx:end_idx]
batch_filename = f"translation_batch_{batch_num + 1:02d}.txt"
with open(batch_filename, 'w', encoding='utf-8') as batch_file:
batch_file.write(f"=== TRANSLATION BATCH {batch_num + 1:02d} ===\n")
batch_file.write(f"Translations {start_idx + 1}-{end_idx} of {len(empty_translations)}\n")
batch_file.write("=" * 60 + "\n\n")
for line_num, msgid, context in batch_translations:
batch_file.write(f"Line {line_num}:\n")
batch_file.write(f"msgid: \"{msgid}\"\n")
batch_file.write(f"msgstr: \"\"\n")
batch_file.write(f"\nArabic Translation: \n")
batch_file.write(f"msgstr: \"\"\n")
batch_file.write("-" * 40 + "\n\n")
print(f"Created {batch_filename} with {len(batch_translations)} translations")
def create_summary_report(empty_translations: List[Tuple[int, str, str]]):
"""
Create a summary report of all empty translations.
"""
with open("empty_translations_summary.txt", 'w', encoding='utf-8') as report:
report.write("EMPTY TRANSLATIONS SUMMARY REPORT\n")
report.write("=" * 50 + "\n\n")
report.write(f"Total empty translations: {len(empty_translations)}\n\n")
# Group by type/pattern for better organization
ui_elements = []
form_fields = []
messages = []
navigation = []
other = []
for line_num, msgid, context in empty_translations:
msgid_lower = msgid.lower()
if any(word in msgid_lower for word in ['button', 'btn', 'click', 'select']):
ui_elements.append((line_num, msgid))
elif any(word in msgid_lower for word in ['field', 'form', 'input', 'enter']):
form_fields.append((line_num, msgid))
elif any(word in msgid_lower for word in ['error', 'success', 'warning', 'message']):
messages.append((line_num, msgid))
elif any(word in msgid_lower for word in ['menu', 'nav', 'page', 'dashboard']):
navigation.append((line_num, msgid))
else:
other.append((line_num, msgid))
report.write(f"UI Elements (Buttons, Links): {len(ui_elements)}\n")
report.write(f"Form Fields & Inputs: {len(form_fields)}\n")
report.write(f"Messages (Error/Success/Warning): {len(messages)}\n")
report.write(f"Navigation & Pages: {len(navigation)}\n")
report.write(f"Other: {len(other)}\n\n")
report.write("SAMPLE ENTRIES:\n")
report.write("-" * 30 + "\n")
for category, name, sample_count in [
(ui_elements, "UI Elements", 5),
(form_fields, "Form Fields", 5),
(messages, "Messages", 5),
(navigation, "Navigation", 5),
(other, "Other", 5)
]:
if category:
report.write(f"\n{name} (showing first {min(len(category), sample_count)}):\n")
for line_num, msgid in category[:sample_count]:
report.write(f" Line {line_num}: \"{msgid}\"\n")
def main():
"""Main function to process the django.po file."""
po_file_path = "locale/ar/LC_MESSAGES/django.po"
if not os.path.exists(po_file_path):
print(f"Error: {po_file_path} not found!")
return
print("Scanning for empty translations...")
empty_translations = find_empty_translations(po_file_path)
if not empty_translations:
print("No empty translations found! All msgstr entries have translations.")
return
# Create batch files
create_batch_files(empty_translations, batch_size=25)
# Create summary report
create_summary_report(empty_translations)
print(f"\nProcess completed!")
print(f"Check the generated batch files: translation_batch_*.txt")
print(f"Summary report: empty_translations_summary.txt")
print(f"\nNext steps:")
print(f"1. Work through each batch file systematically")
print(f"2. Add Arabic translations to each empty msgstr")
print(f"3. Update the main django.po file with completed translations")
if __name__ == "__main__":
main()

View File

@ -1,91 +0,0 @@
#!/usr/bin/env python3
"""
Fix duplicate message definitions in .po files
"""
import re
import os
def fix_po_duplicates(po_file):
"""Remove duplicate message definitions from a .po file"""
print(f"Processing {po_file}...")
with open(po_file, 'r', encoding='utf-8') as f:
content = f.read()
# Split into entries
entries = []
current_entry = []
lines = content.split('\n')
i = 0
while i < len(lines):
line = lines[i]
if line.startswith('msgid '):
# Start of new entry
if current_entry:
entries.append('\n'.join(current_entry))
current_entry = [line]
elif line.startswith('msgstr ') and current_entry:
# End of entry
current_entry.append(line)
entries.append('\n'.join(current_entry))
current_entry = []
else:
if current_entry:
current_entry.append(line)
i += 1
# Add the last entry if it exists
if current_entry:
entries.append('\n'.join(current_entry))
# Remove duplicates, keeping the first occurrence
seen_msgids = set()
unique_entries = []
for entry in entries:
# Extract msgid
msgid_match = re.search(r'msgid\s+"([^"]*)"', entry)
if msgid_match:
msgid = msgid_match.group(1)
if msgid not in seen_msgids:
seen_msgids.add(msgid)
unique_entries.append(entry)
else:
print(f" Removing duplicate: {msgid}")
else:
# Header or other entry, keep it
unique_entries.append(entry)
# Rebuild content
new_content = '\n\n'.join(unique_entries)
# Write back to file
with open(po_file, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f" Fixed {po_file} - removed {len(entries) - len(unique_entries)} duplicates")
def main():
"""Fix duplicates in both English and Arabic .po files"""
po_files = [
'locale/ar/LC_MESSAGES/django.po',
'locale/en/LC_MESSAGES/django.po'
]
for po_file in po_files:
if os.path.exists(po_file):
fix_po_duplicates(po_file)
else:
print(f"File not found: {po_file}")
print("\n✅ Duplicate fixing completed!")
print("Now run: python manage.py compilemessages")
if __name__ == "__main__":
main()

View File

@ -1469,8 +1469,8 @@ class ParticipantsForm(forms.ModelForm):
}
# class ParticipantsSelectForm(forms.ModelForm):
# """Form for selecting Participants"""
class ParticipantsSelectForm(forms.ModelForm):
"""Form for selecting Participants"""
participants = forms.ModelMultipleChoiceField(
queryset=Participants.objects.all(),
@ -1863,4 +1863,169 @@ class OnsiteMeetingForm(forms.ModelForm):
'location': forms.TextInput(attrs={'placeholder': 'Physical location', 'class': 'form-control'}),
'timezone': forms.TextInput(attrs={'class': 'form-control'}),
'status': forms.Select(attrs={'class': 'form-control'}),
}
}
class MessageForm(forms.ModelForm):
"""Form for creating and editing messages between users"""
class Meta:
model = Message
fields = ["recipient", "job", "subject", "content", "message_type"]
widgets = {
"recipient": forms.Select(
attrs={"class": "form-select", "placeholder": "Select recipient"}
),
"job": forms.Select(
attrs={"class": "form-select", "placeholder": "Select job (optional)"}
),
"subject": forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Enter message subject",
"required": True,
}
),
"content": forms.Textarea(
attrs={
"class": "form-control",
"rows": 6,
"placeholder": "Enter your message here...",
"required": True,
}
),
"message_type": forms.Select(attrs={"class": "form-select"}),
}
labels = {
"recipient": _("Recipient"),
"job": _("Related Job"),
"subject": _("Subject"),
"content": _("Message"),
"message_type": _("Message Type"),
}
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
self.helper = FormHelper()
self.helper.form_method = "post"
self.helper.form_class = "g-3"
# Filter job options based on user type
self._filter_job_field()
# Filter recipient options based on user type
self._filter_recipient_field()
self.helper.layout = Layout(
Row(
Column("recipient", css_class="col-md-6"),
Column("job", css_class="col-md-6"),
css_class="g-3 mb-3",
),
Field("subject", css_class="form-control"),
Field("message_type", css_class="form-control"),
Field("content", css_class="form-control"),
Div(
Submit("submit", _("Send Message"), css_class="btn btn-main-action"),
css_class="col-12 mt-4",
),
)
def _filter_job_field(self):
"""Filter job options based on user type"""
if self.user.user_type == "agency":
# Agency users can only see jobs assigned to their agency
self.fields["job"].queryset = JobPosting.objects.filter(
hiring_agency__user=self.user,
status="ACTIVE"
).order_by("-created_at")
elif self.user.user_type == "candidate":
# Candidates can only see jobs they applied for
self.fields["job"].queryset = JobPosting.objects.filter(
candidates__user=self.user
).distinct().order_by("-created_at")
else:
# Staff can see all jobs
self.fields["job"].queryset = JobPosting.objects.filter(
status="ACTIVE"
).order_by("-created_at")
def _filter_recipient_field(self):
"""Filter recipient options based on user type"""
if self.user.user_type == "staff":
# Staff can message anyone
self.fields["recipient"].queryset = User.objects.all().order_by("username")
elif self.user.user_type == "agency":
# Agency can message staff and their candidates
from django.db.models import Q
self.fields["recipient"].queryset = User.objects.filter(
Q(user_type="staff") |
Q(candidate_profile__job__hiring_agency__user=self.user)
).distinct().order_by("username")
elif self.user.user_type == "candidate":
# Candidates can only message staff
self.fields["recipient"].queryset = User.objects.filter(
user_type="staff"
).order_by("username")
def clean(self):
"""Validate message form data"""
cleaned_data = super().clean()
job = cleaned_data.get("job")
recipient = cleaned_data.get("recipient")
# If job is selected but no recipient, auto-assign to job.assigned_to
if job and not recipient:
if job.assigned_to:
cleaned_data["recipient"] = job.assigned_to
# Set message type to job_related
cleaned_data["message_type"] = Message.MessageType.JOB_RELATED
else:
raise forms.ValidationError(
_("Selected job is not assigned to any user. Please assign the job first.")
)
# Validate messaging permissions
if self.user and cleaned_data.get("recipient"):
self._validate_messaging_permissions(cleaned_data)
return cleaned_data
def _validate_messaging_permissions(self, cleaned_data):
"""Validate if user can message the recipient"""
recipient = cleaned_data.get("recipient")
job = cleaned_data.get("job")
# Staff can message anyone
if self.user.user_type == "staff":
return
# Agency users validation
if self.user.user_type == "agency":
if recipient.user_type not in ["staff", "candidate"]:
raise forms.ValidationError(
_("Agencies can only message staff or candidates.")
)
# If messaging a candidate, ensure candidate is from their agency
if recipient.user_type == "candidate" and job:
if not job.hiring_agency.filter(user=self.user).exists():
raise forms.ValidationError(
_("You can only message candidates from your assigned jobs.")
)
# Candidate users validation
if self.user.user_type == "candidate":
if recipient.user_type != "staff":
raise forms.ValidationError(
_("Candidates can only message staff.")
)
# If job-related, ensure candidate applied for the job
if job:
if not Candidate.objects.filter(job=job, user=self.user).exists():
raise forms.ValidationError(
_("You can only message about jobs you have applied for.")
)

View File

@ -1,4 +1,4 @@
# Generated by Django 5.2.6 on 2025-11-10 14:13
# Generated by Django 5.2.6 on 2025-11-13 13:12
import django.contrib.auth.models
import django.contrib.auth.validators
@ -19,6 +19,7 @@ class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
@ -47,6 +48,24 @@ class Migration(migrations.Migration):
'ordering': ['order'],
},
),
migrations.CreateModel(
name='OnsiteMeeting',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('topic', models.CharField(max_length=255, verbose_name='Topic')),
('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')),
('duration', models.PositiveIntegerField(verbose_name='Duration')),
('timezone', models.CharField(max_length=50, verbose_name='Timezone')),
('location', models.CharField(blank=True, null=True)),
('status', models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Participants',
fields=[
@ -145,51 +164,6 @@ class Migration(migrations.Migration):
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='Application',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')),
('cover_letter', models.FileField(blank=True, null=True, upload_to='cover_letters/', verbose_name='Cover Letter')),
('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')),
('parsed_summary', models.TextField(blank=True, verbose_name='Parsed Summary')),
('applied', models.BooleanField(default=False, verbose_name='Applied')),
('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Offer', 'Offer'), ('Hired', 'Hired'), ('Rejected', 'Rejected')], db_index=True, default='Applied', max_length=20, verbose_name='Stage')),
('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=20, null=True, verbose_name='Applicant Status')),
('exam_date', models.DateTimeField(blank=True, null=True, verbose_name='Exam Date')),
('exam_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Exam Status')),
('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Interview Date')),
('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Interview Status')),
('offer_date', models.DateField(blank=True, null=True, verbose_name='Offer Date')),
('offer_status', models.CharField(blank=True, choices=[('Accepted', 'Accepted'), ('Rejected', 'Rejected'), ('Pending', 'Pending')], max_length=20, null=True, verbose_name='Offer Status')),
('hired_date', models.DateField(blank=True, null=True, verbose_name='Hired Date')),
('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')),
('ai_analysis_data', models.JSONField(blank=True, default=dict, help_text='Full JSON output from the resume scoring model.', null=True, verbose_name='AI Analysis Data')),
('retry', models.SmallIntegerField(default=3, verbose_name='Resume Parsing Retry')),
('hiring_source', models.CharField(blank=True, choices=[('Public', 'Public'), ('Internal', 'Internal'), ('Agency', 'Agency')], default='Public', max_length=255, null=True, verbose_name='Hiring Source')),
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='application_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')),
],
options={
'verbose_name': 'Application',
'verbose_name_plural': 'Applications',
},
),
migrations.CreateModel(
name='Candidate',
fields=[
],
options={
'verbose_name': 'Candidate (Legacy)',
'verbose_name_plural': 'Candidates (Legacy)',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('recruitment.application',),
),
migrations.CreateModel(
name='FormField',
fields=[
@ -281,10 +255,37 @@ class Migration(migrations.Migration):
'ordering': ['name'],
},
),
migrations.AddField(
model_name='application',
name='hiring_agency',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='recruitment.hiringagency', verbose_name='Hiring Agency'),
migrations.CreateModel(
name='Application',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')),
('cover_letter', models.FileField(blank=True, null=True, upload_to='cover_letters/', verbose_name='Cover Letter')),
('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')),
('parsed_summary', models.TextField(blank=True, verbose_name='Parsed Summary')),
('applied', models.BooleanField(default=False, verbose_name='Applied')),
('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Offer', 'Offer'), ('Hired', 'Hired'), ('Rejected', 'Rejected')], db_index=True, default='Applied', max_length=20, verbose_name='Stage')),
('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=20, null=True, verbose_name='Applicant Status')),
('exam_date', models.DateTimeField(blank=True, null=True, verbose_name='Exam Date')),
('exam_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Exam Status')),
('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Interview Date')),
('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Interview Status')),
('offer_date', models.DateField(blank=True, null=True, verbose_name='Offer Date')),
('offer_status', models.CharField(blank=True, choices=[('Accepted', 'Accepted'), ('Rejected', 'Rejected'), ('Pending', 'Pending')], max_length=20, null=True, verbose_name='Offer Status')),
('hired_date', models.DateField(blank=True, null=True, verbose_name='Hired Date')),
('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')),
('ai_analysis_data', models.JSONField(blank=True, default=dict, help_text='Full JSON output from the resume scoring model.', null=True, verbose_name='AI Analysis Data')),
('retry', models.SmallIntegerField(default=3, verbose_name='Resume Parsing Retry')),
('hiring_source', models.CharField(blank=True, choices=[('Public', 'Public'), ('Internal', 'Internal'), ('Agency', 'Agency')], default='Public', max_length=255, null=True, verbose_name='Hiring Source')),
('hiring_agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='recruitment.hiringagency', verbose_name='Hiring Agency')),
],
options={
'verbose_name': 'Application',
'verbose_name_plural': 'Applications',
},
),
migrations.CreateModel(
name='JobPosting',
@ -327,8 +328,6 @@ class Migration(migrations.Migration):
('cancelled_at', models.DateTimeField(blank=True, null=True)),
('assigned_to', models.ForeignKey(blank=True, help_text='The user who has been assigned to this job', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_jobs', to=settings.AUTH_USER_MODEL, verbose_name='Assigned To')),
('hiring_agency', models.ManyToManyField(blank=True, help_text='External agency responsible for sourcing candidates for this role', related_name='jobs', to='recruitment.hiringagency', verbose_name='Hiring Agency')),
('users', models.ManyToManyField(blank=True, help_text='Internal staff involved in the recruitment process for this job', related_name='jobs_assigned', to=settings.AUTH_USER_MODEL, verbose_name='Internal Participant')),
('participants', models.ManyToManyField(blank=True, help_text='External participants involved in the recruitment process for this job', related_name='jobs_participating', to='recruitment.participants', verbose_name='External Participant')),
('source', models.ForeignKey(blank=True, help_text='The system or channel from which this job posting originated or was first published.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='job_postings', to='recruitment.source')),
],
options={
@ -344,6 +343,7 @@ class Migration(migrations.Migration):
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('interview_type', models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type')),
('start_date', models.DateField(db_index=True, verbose_name='Start Date')),
('end_date', models.DateField(db_index=True, verbose_name='End Date')),
('working_days', models.JSONField(verbose_name='Working Days')),
@ -353,7 +353,7 @@ class Migration(migrations.Migration):
('break_end_time', models.TimeField(blank=True, null=True, verbose_name='Break End Time')),
('interview_duration', models.PositiveIntegerField(verbose_name='Interview Duration (minutes)')),
('buffer_time', models.PositiveIntegerField(default=0, verbose_name='Buffer Time (minutes)')),
('candidates', models.ManyToManyField(blank=True, null=True, related_name='interview_schedules', to='recruitment.application')),
('applications', models.ManyToManyField(blank=True, null=True, related_name='interview_schedules', to='recruitment.application')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_schedules', to='recruitment.jobposting')),
],
@ -441,6 +441,7 @@ class Migration(migrations.Migration):
('address', models.TextField(blank=True, null=True, verbose_name='Address')),
('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')),
('linkedin_profile', models.URLField(blank=True, null=True, verbose_name='LinkedIn Profile URL')),
('agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency')),
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')),
],
options={
@ -448,25 +449,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'People',
},
),
migrations.CreateModel(
name='Document',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('file', models.FileField(upload_to='candidate_documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File')),
('document_type', models.CharField(choices=[('resume', 'Resume'), ('cover_letter', 'Cover Letter'), ('certificate', 'Certificate'), ('id_document', 'ID Document'), ('passport', 'Passport'), ('education', 'Education Document'), ('experience', 'Experience Letter'), ('other', 'Other')], default='other', max_length=20, verbose_name='Document Type')),
('description', models.CharField(blank=True, max_length=200, verbose_name='Description')),
('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Uploaded By')),
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='recruitment.person', verbose_name='Person')),
],
options={
'verbose_name': 'Document',
'verbose_name_plural': 'Documents',
'ordering': ['-created_at'],
},
),
migrations.AddField(
model_name='application',
name='person',
@ -553,8 +535,11 @@ class Migration(migrations.Migration):
('updated_at', models.DateTimeField(auto_now=True)),
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.application')),
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.jobposting')),
('onsite_meeting', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='onsite_interview', to='recruitment.onsitemeeting')),
('participants', models.ManyToManyField(blank=True, to='recruitment.participants')),
('schedule', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interviews', to='recruitment.interviewschedule')),
('zoom_meeting', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting')),
('system_users', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL)),
('zoom_meeting', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting')),
],
),
migrations.CreateModel(
@ -617,6 +602,27 @@ class Migration(migrations.Migration):
'indexes': [models.Index(fields=['unique_token'], name='recruitment_unique__f91e76_idx'), models.Index(fields=['expires_at'], name='recruitment_expires_954ed9_idx'), models.Index(fields=['is_active'], name='recruitment_is_acti_4b0804_idx')],
},
),
migrations.CreateModel(
name='Document',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('object_id', models.PositiveIntegerField(verbose_name='Object ID')),
('file', models.FileField(upload_to='documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File')),
('document_type', models.CharField(choices=[('resume', 'Resume'), ('cover_letter', 'Cover Letter'), ('certificate', 'Certificate'), ('id_document', 'ID Document'), ('passport', 'Passport'), ('education', 'Education Document'), ('experience', 'Experience Letter'), ('other', 'Other')], default='other', max_length=20, verbose_name='Document Type')),
('description', models.CharField(blank=True, max_length=200, verbose_name='Description')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Content Type')),
('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Uploaded By')),
],
options={
'verbose_name': 'Document',
'verbose_name_plural': 'Documents',
'ordering': ['-created_at'],
'indexes': [models.Index(fields=['content_type', 'object_id', 'document_type', 'created_at'], name='recruitment_content_547650_idx')],
},
),
migrations.CreateModel(
name='FieldResponse',
fields=[
@ -707,10 +713,6 @@ class Migration(migrations.Migration):
model_name='person',
index=models.Index(fields=['created_at'], name='recruitment_created_33495a_idx'),
),
migrations.AddIndex(
model_name='document',
index=models.Index(fields=['person', 'document_type', 'created_at'], name='recruitment_person__0a6844_idx'),
),
migrations.AddIndex(
model_name='application',
index=models.Index(fields=['person', 'job'], name='recruitment_person__34355c_idx'),

View File

@ -1,25 +0,0 @@
# Generated by Django 5.2.6 on 2025-11-11 10:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0001_initial'),
]
operations = [
migrations.DeleteModel(
name='Candidate',
),
migrations.RenameField(
model_name='interviewschedule',
old_name='candidates',
new_name='applications',
),
migrations.RemoveField(
model_name='application',
name='user',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-06 15:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='scheduledinterview',
name='participants',
field=models.ManyToManyField(blank=True, to='recruitment.participants'),
),
]

View File

@ -1,45 +0,0 @@
# Generated by Django 5.2.6 on 2025-11-11 12:13
import django.db.models.deletion
import recruitment.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('recruitment', '0002_delete_candidate_and_more'),
]
operations = [
migrations.RemoveIndex(
model_name='document',
name='recruitment_person__0a6844_idx',
),
migrations.RemoveField(
model_name='document',
name='person',
),
migrations.AddField(
model_name='document',
name='content_type',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Content Type'),
preserve_default=False,
),
migrations.AddField(
model_name='document',
name='object_id',
field=models.PositiveIntegerField(default=1, verbose_name='Object ID'),
preserve_default=False,
),
migrations.AlterField(
model_name='document',
name='file',
field=models.FileField(upload_to='documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File'),
),
migrations.AddIndex(
model_name='document',
index=models.Index(fields=['content_type', 'object_id', 'document_type', 'created_at'], name='recruitment_content_547650_idx'),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-06 15:37
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0002_scheduledinterview_participants'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='scheduledinterview',
name='system_users',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.6 on 2025-11-12 20:22
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0003_convert_document_to_generic_fk'),
]
operations = [
migrations.AddField(
model_name='person',
name='agency',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-06 15:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0003_scheduledinterview_system_users'),
]
operations = [
migrations.RemoveField(
model_name='jobposting',
name='participants',
),
migrations.RemoveField(
model_name='jobposting',
name='users',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 11:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0004_remove_jobposting_participants_and_more'),
]
operations = [
migrations.AddField(
model_name='scheduledinterview',
name='meeting_type',
field=models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type'),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 11:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0005_scheduledinterview_meeting_type'),
]
operations = [
migrations.RemoveField(
model_name='scheduledinterview',
name='meeting_type',
),
migrations.AddField(
model_name='interviewschedule',
name='meeting_type',
field=models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 11:30
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0006_remove_scheduledinterview_meeting_type_and_more'),
]
operations = [
migrations.RenameField(
model_name='interviewschedule',
old_name='meeting_type',
new_name='interview_type',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 12:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0007_rename_meeting_type_interviewschedule_interview_type'),
]
operations = [
migrations.AddField(
model_name='interviewschedule',
name='location',
field=models.CharField(blank=True, default='Remote', null=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 13:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0008_interviewschedule_location'),
]
operations = [
migrations.AlterField(
model_name='zoommeeting',
name='meeting_id',
field=models.CharField(blank=True, db_index=True, max_length=20, null=True, unique=True, verbose_name='Meeting ID'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 13:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0009_alter_zoommeeting_meeting_id'),
]
operations = [
migrations.AlterField(
model_name='zoommeeting',
name='meeting_id',
field=models.CharField(db_index=True, default=1, max_length=20, unique=True, verbose_name='Meeting ID'),
preserve_default=False,
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-09 13:50
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0010_alter_zoommeeting_meeting_id'),
]
operations = [
migrations.AlterField(
model_name='scheduledinterview',
name='zoom_meeting',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-10 09:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0011_alter_scheduledinterview_zoom_meeting'),
]
operations = [
migrations.AddField(
model_name='interviewschedule',
name='interview_topic',
field=models.CharField(blank=True, null=True),
),
]

View File

@ -1,45 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-10 13:00
import django.db.models.deletion
import django_extensions.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0012_interviewschedule_interview_topic'),
]
operations = [
migrations.CreateModel(
name='OnsiteMeeting',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
('topic', models.CharField(max_length=255, verbose_name='Topic')),
('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')),
('duration', models.PositiveIntegerField(verbose_name='Duration')),
('timezone', models.CharField(max_length=50, verbose_name='Timezone')),
('location', models.CharField(blank=True, null=True)),
],
options={
'abstract': False,
},
),
migrations.RemoveField(
model_name='interviewschedule',
name='interview_topic',
),
migrations.RemoveField(
model_name='interviewschedule',
name='location',
),
migrations.AddField(
model_name='scheduledinterview',
name='onsite_meeting',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.onsitemeeting'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-10 13:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0013_onsitemeeting_and_more'),
]
operations = [
migrations.AddField(
model_name='onsitemeeting',
name='status',
field=models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-10 13:55
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0014_onsitemeeting_status'),
]
operations = [
migrations.AlterField(
model_name='scheduledinterview',
name='onsite_meeting',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='onsite_interview', to='recruitment.onsitemeeting'),
),
]

View File

@ -1,67 +0,0 @@
#!/usr/bin/env python
import os
import sys
import django
# Add project root to Python path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Set Django settings module
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
# Initialize Django
django.setup()
def test_agency_access_links():
"""Test agency access link functionality"""
print("Testing agency access links...")
# Test 1: Check if URLs exist
try:
from recruitment.urls import urlpatterns
print("✅ URL patterns loaded successfully")
# Check if our new URLs are in patterns
url_patterns = [str(pattern.pattern) for pattern in urlpatterns]
# Look for our specific URL patterns
deactivate_found = any('agency-access-links' in pattern and 'deactivate' in pattern for pattern in url_patterns)
reactivate_found = any('agency-access-links' in pattern and 'reactivate' in pattern for pattern in url_patterns)
if deactivate_found:
print("✅ Found URL pattern for agency_access_link_deactivate")
else:
print("❌ Missing URL pattern for agency_access_link_deactivate")
if reactivate_found:
print("✅ Found URL pattern for agency_access_link_reactivate")
else:
print("❌ Missing URL pattern for agency_access_link_reactivate")
# Test 2: Check if views exist
try:
from recruitment.views import agency_access_link_deactivate, agency_access_link_reactivate
print("✅ View functions imported successfully")
# Test that functions are callable
if callable(agency_access_link_deactivate):
print("✅ agency_access_link_deactivate is callable")
else:
print("❌ agency_access_link_deactivate is not callable")
if callable(agency_access_link_reactivate):
print("✅ agency_access_link_reactivate is callable")
else:
print("❌ agency_access_link_reactivate is not callable")
except ImportError as e:
print(f"❌ Import error: {e}")
print("Agency access link functionality test completed!")
return True
except Exception as e:
print(f"❌ Test failed: {e}")
return False
if __name__ == "__main__":
test_agency_access_links()

View File

@ -1,98 +0,0 @@
#!/usr/bin/env python
"""
Test script to verify agency assignment functionality
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.test import Client
from django.urls import reverse
from django.contrib.auth.models import User
from recruitment.models import HiringAgency, JobPosting, AgencyJobAssignment
def test_agency_assignments():
"""Test agency assignment functionality"""
print("🧪 Testing Agency Assignment Functionality")
print("=" * 50)
# Create test client
client = Client()
# Test URLs
urls_to_test = [
('agency_list', '/recruitment/agencies/'),
('agency_assignment_list', '/recruitment/agency-assignments/'),
]
print("\n📋 Testing URL Accessibility:")
for url_name, expected_path in urls_to_test:
try:
url = reverse(url_name)
print(f"{url_name}: {url}")
except Exception as e:
print(f"{url_name}: Error - {e}")
print("\n🔍 Testing Views:")
# Test agency list view (without authentication - should redirect)
try:
response = client.get(reverse('agency_list'))
if response.status_code == 302: # Redirect to login
print("✅ Agency list view redirects unauthenticated users (as expected)")
else:
print(f"⚠️ Agency list view status: {response.status_code}")
except Exception as e:
print(f"❌ Agency list view error: {e}")
# Test agency assignment list view (without authentication - should redirect)
try:
response = client.get(reverse('agency_assignment_list'))
if response.status_code == 302: # Redirect to login
print("✅ Agency assignment list view redirects unauthenticated users (as expected)")
else:
print(f"⚠️ Agency assignment list view status: {response.status_code}")
except Exception as e:
print(f"❌ Agency assignment list view error: {e}")
print("\n📊 Testing Database Models:")
# Test if models exist and can be created
try:
# Check if we can query the models
agency_count = HiringAgency.objects.count()
job_count = JobPosting.objects.count()
assignment_count = AgencyJobAssignment.objects.count()
print(f"✅ HiringAgency model: {agency_count} agencies in database")
print(f"✅ JobPosting model: {job_count} jobs in database")
print(f"✅ AgencyJobAssignment model: {assignment_count} assignments in database")
except Exception as e:
print(f"❌ Database model error: {e}")
print("\n🎯 Navigation Menu Test:")
print("✅ Agency Assignments link added to navigation menu")
print("✅ Navigation includes both 'Agencies' and 'Agency Assignments' links")
print("\n📝 Summary:")
print("✅ Agency assignment functionality is fully implemented")
print("✅ All required views are present in views.py")
print("✅ URL patterns are configured in urls.py")
print("✅ Navigation menu has been updated")
print("✅ Templates are created and functional")
print("\n🚀 Ready for use!")
print("Users can now:")
print(" - View agencies at /recruitment/agencies/")
print(" - Manage agency assignments at /recruitment/agency-assignments/")
print(" - Create, update, and delete assignments")
print(" - Generate access links for external agencies")
print(" - Send messages to agencies")
if __name__ == '__main__':
test_agency_assignments()

View File

@ -1,204 +0,0 @@
#!/usr/bin/env python
"""
Test script to verify Agency CRUD functionality
"""
import os
import sys
import django
# Add the project directory to the Python path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Set up Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.test import Client
from django.contrib.auth.models import User
from recruitment.models import HiringAgency
def test_agency_crud():
"""Test Agency CRUD operations"""
print("🧪 Testing Agency CRUD Functionality")
print("=" * 50)
# Create a test user
user, created = User.objects.get_or_create(
username='testuser',
defaults={'email': 'test@example.com', 'is_staff': True, 'is_superuser': True}
)
if created:
user.set_password('testpass123')
user.save()
print("✅ Created test user")
else:
print(" Using existing test user")
# Create test client
client = Client()
# Login the user
client.login(username='testuser', password='testpass123')
print("✅ Logged in test user")
# Test 1: Agency List View
print("\n1. Testing Agency List View...")
response = client.get('/recruitment/agencies/')
if response.status_code == 200:
print("✅ Agency list view works")
else:
print(f"❌ Agency list view failed: {response.status_code}")
return False
# Test 2: Agency Create View (GET)
print("\n2. Testing Agency Create View (GET)...")
response = client.get('/recruitment/agencies/create/')
if response.status_code == 200:
print("✅ Agency create view works")
else:
print(f"❌ Agency create view failed: {response.status_code}")
return False
# Test 3: Agency Create (POST)
print("\n3. Testing Agency Create (POST)...")
agency_data = {
'name': 'Test Agency',
'contact_person': 'John Doe',
'email': 'test@agency.com',
'phone': '+1234567890',
'country': 'SA',
'city': 'Riyadh',
'address': 'Test Address',
'website': 'https://testagency.com',
'description': 'Test agency description'
}
response = client.post('/recruitment/agencies/create/', agency_data)
if response.status_code == 302: # Redirect after successful creation
print("✅ Agency creation works")
# Get the created agency
agency = HiringAgency.objects.filter(name='Test Agency').first()
if agency:
print(f"✅ Agency created with ID: {agency.id}")
# Test 4: Agency Detail View
print("\n4. Testing Agency Detail View...")
response = client.get(f'/recruitment/agencies/{agency.slug}/')
if response.status_code == 200:
print("✅ Agency detail view works")
else:
print(f"❌ Agency detail view failed: {response.status_code}")
return False
# Test 5: Agency Update View (GET)
print("\n5. Testing Agency Update View (GET)...")
response = client.get(f'/recruitment/agencies/{agency.slug}/update/')
if response.status_code == 200:
print("✅ Agency update view works")
else:
print(f"❌ Agency update view failed: {response.status_code}")
return False
# Test 6: Agency Update (POST)
print("\n6. Testing Agency Update (POST)...")
update_data = agency_data.copy()
update_data['name'] = 'Updated Test Agency'
response = client.post(f'/recruitment/agencies/{agency.slug}/update/', update_data)
if response.status_code == 302:
print("✅ Agency update works")
# Verify the update
agency.refresh_from_db()
if agency.name == 'Updated Test Agency':
print("✅ Agency data updated correctly")
else:
print("❌ Agency data not updated correctly")
return False
else:
print(f"❌ Agency update failed: {response.status_code}")
return False
# Test 7: Agency Delete View (GET)
print("\n7. Testing Agency Delete View (GET)...")
response = client.get(f'/recruitment/agencies/{agency.slug}/delete/')
if response.status_code == 200:
print("✅ Agency delete view works")
else:
print(f"❌ Agency delete view failed: {response.status_code}")
return False
# Test 8: Agency Delete (POST)
print("\n8. Testing Agency Delete (POST)...")
delete_data = {
'confirm_name': 'Updated Test Agency',
'confirm_delete': 'on'
}
response = client.post(f'/recruitment/agencies/{agency.slug}/delete/', delete_data)
if response.status_code == 302:
print("✅ Agency deletion works")
# Verify deletion
if not HiringAgency.objects.filter(name='Updated Test Agency').exists():
print("✅ Agency deleted successfully")
else:
print("❌ Agency not deleted")
return False
else:
print(f"❌ Agency deletion failed: {response.status_code}")
return False
else:
print("❌ Agency not found after creation")
return False
else:
print(f"❌ Agency creation failed: {response.status_code}")
print(f"Response content: {response.content.decode()}")
return False
# Test 9: URL patterns
print("\n9. Testing URL patterns...")
try:
from django.urls import reverse
print(f"✅ Agency list URL: {reverse('agency_list')}")
print(f"✅ Agency create URL: {reverse('agency_create')}")
print("✅ All URL patterns resolved correctly")
except Exception as e:
print(f"❌ URL pattern error: {e}")
return False
# Test 10: Model functionality
print("\n10. Testing Model functionality...")
try:
# Test model creation
test_agency = HiringAgency.objects.create(
name='Model Test Agency',
contact_person='Jane Smith',
email='model@test.com',
phone='+9876543210',
country='SA'
)
print(f"✅ Model creation works: {test_agency.name}")
print(f"✅ Slug generation works: {test_agency.slug}")
print(f"✅ String representation works: {str(test_agency)}")
# Test model methods
print(f"✅ Country display: {test_agency.get_country_display()}")
# Clean up
test_agency.delete()
print("✅ Model deletion works")
except Exception as e:
print(f"❌ Model functionality error: {e}")
return False
print("\n" + "=" * 50)
print("🎉 All Agency CRUD tests passed!")
return True
if __name__ == '__main__':
success = test_agency_crud()
sys.exit(0 if success else 1)

View File

@ -1,278 +0,0 @@
#!/usr/bin/env python
"""
Test script to verify agency user isolation and all fixes are working properly.
This tests:
1. Agency login functionality (AttributeError fix)
2. Agency portal template isolation (agency_base.html usage)
3. Agency user access restrictions
4. JavaScript fixes in submit candidate form
"""
import os
import sys
import django
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from unittest.mock import patch, MagicMock
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from recruitment.models import Agency, AgencyJobAssignment, AgencyAccessLink, Candidate, Job
class AgencyIsolationTest(TestCase):
"""Test agency user isolation and functionality"""
def setUp(self):
"""Set up test data"""
# Create internal staff user
self.staff_user = User.objects.create_user(
username='staff_user',
email='staff@example.com',
password='testpass123',
is_staff=True
)
# Create agency user
self.agency_user = User.objects.create_user(
username='agency_user',
email='agency@example.com',
password='testpass123',
is_staff=False
)
# Create agency
self.agency = Agency.objects.create(
name='Test Agency',
contact_email='agency@example.com',
contact_phone='+1234567890',
address='Test Address',
is_active=True
)
# Create job
self.job = Job.objects.create(
title='Test Job',
department='IT',
description='Test job description',
status='active'
)
# Create agency assignment
self.assignment = AgencyJobAssignment.objects.create(
agency=self.agency,
job=self.job,
max_candidates=10,
deadline_date='2024-12-31',
status='active'
)
# Create access link
self.access_link = AgencyAccessLink.objects.create(
assignment=self.assignment,
unique_token='test-token-123',
access_password='testpass123',
expires_at='2024-12-31'
)
# Create test candidate
self.candidate = Candidate.objects.create(
first_name='Test',
last_name='Candidate',
email='candidate@example.com',
phone='+1234567890',
job=self.job,
source='agency',
hiring_agency=self.agency
)
def test_agency_login_form_attribute_error_fix(self):
"""Test that AgencyLoginForm handles missing validated_access_link attribute"""
from recruitment.forms import AgencyLoginForm
# Test form with valid data
form_data = {
'access_token': 'test-token-123',
'password': 'testpass123'
}
form = AgencyLoginForm(data=form_data)
# This should not raise AttributeError anymore
try:
is_valid = form.is_valid()
print(f"✓ AgencyLoginForm validation works: {is_valid}")
except AttributeError as e:
if 'validated_access_link' in str(e):
self.fail("AttributeError 'validated_access_link' not fixed!")
else:
raise
def test_agency_portal_templates_use_agency_base(self):
"""Test that agency portal templates use agency_base.html"""
agency_portal_templates = [
'recruitment/agency_portal_login.html',
'recruitment/agency_portal_dashboard.html',
'recruitment/agency_portal_submit_candidate.html',
'recruitment/agency_portal_messages.html',
'recruitment/agency_access_link_detail.html'
]
for template_name in agency_portal_templates:
template_path = f'templates/{template_name}'
if os.path.exists(template_path):
with open(template_path, 'r') as f:
content = f.read()
self.assertIn("{% extends 'agency_base.html' %}", content,
f"{template_name} should use agency_base.html")
print(f"{template_name} uses agency_base.html")
else:
print(f"⚠ Template {template_name} not found")
def test_agency_base_template_isolation(self):
"""Test that agency_base.html properly isolates agency users"""
agency_base_path = 'templates/agency_base.html'
if os.path.exists(agency_base_path):
with open(agency_base_path, 'r') as f:
content = f.read()
# Check that it extends base.html
self.assertIn("{% extends 'base.html' %}", content)
# Check that it has agency-specific navigation
self.assertIn('agency_portal_dashboard', content)
self.assertIn('agency_portal_logout', content)
# Check that it doesn't include admin navigation
self.assertNotIn('admin:', content)
print("✓ agency_base.html properly configured")
else:
self.fail("agency_base.html not found")
def test_agency_login_view(self):
"""Test agency login functionality"""
client = Client()
# Test GET request
response = client.get(reverse('agency_portal_login'))
self.assertEqual(response.status_code, 200)
print("✓ Agency login page loads")
# Test POST with valid credentials
response = client.post(reverse('agency_portal_login'), {
'access_token': 'test-token-123',
'password': 'testpass123'
})
# Should redirect or show success (depending on implementation)
self.assertIn(response.status_code, [200, 302])
print("✓ Agency login POST request handled")
def test_agency_user_access_restriction(self):
"""Test that agency users can't access internal pages"""
client = Client()
# Log in as agency user
client.login(username='agency_user', password='testpass123')
# Try to access internal pages (should be restricted)
internal_urls = [
'/admin/',
reverse('agency_list'),
reverse('candidate_list'),
]
for url in internal_urls:
try:
response = client.get(url)
# Agency users should get redirected or forbidden
self.assertIn(response.status_code, [302, 403, 404])
print(f"✓ Agency user properly restricted from {url}")
except:
print(f"⚠ Could not test access to {url}")
def test_javascript_fixes_in_submit_candidate(self):
"""Test that JavaScript fixes are in place in submit candidate template"""
template_path = 'templates/recruitment/agency_portal_submit_candidate.html'
if os.path.exists(template_path):
with open(template_path, 'r') as f:
content = f.read()
# Check for safe element access patterns
self.assertIn('getElementValue', content)
self.assertIn('if (element)', content)
# Check for error handling
self.assertIn('console.error', content)
print("✓ JavaScript fixes present in submit candidate template")
else:
self.fail("agency_portal_submit_candidate.html not found")
def test_agency_portal_navigation(self):
"""Test agency portal navigation links"""
agency_portal_urls = [
'agency_portal_dashboard',
'agency_portal_login',
'agency_portal_logout',
]
for url_name in agency_portal_urls:
try:
url = reverse(url_name)
print(f"✓ Agency portal URL {url_name} resolves: {url}")
except:
print(f"⚠ Agency portal URL {url_name} not found")
def run_tests():
"""Run all tests"""
print("=" * 60)
print("AGENCY ISOLATION AND FIXES TEST")
print("=" * 60)
test_case = AgencyIsolationTest()
test_case.setUp()
tests = [
test_case.test_agency_login_form_attribute_error_fix,
test_case.test_agency_portal_templates_use_agency_base,
test_case.test_agency_base_template_isolation,
test_case.test_agency_login_view,
test_case.test_agency_user_access_restriction,
test_case.test_javascript_fixes_in_submit_candidate,
test_case.test_agency_portal_navigation,
]
passed = 0
failed = 0
for test in tests:
try:
test()
passed += 1
except Exception as e:
print(f"{test.__name__} failed: {e}")
failed += 1
print("=" * 60)
print(f"TEST RESULTS: {passed} passed, {failed} failed")
print("=" * 60)
if failed == 0:
print("🎉 All tests passed! Agency isolation is working properly.")
else:
print("⚠️ Some tests failed. Please review the issues above.")
return failed == 0
if __name__ == '__main__':
success = run_tests()
sys.exit(0 if success else 1)

View File

@ -1,105 +0,0 @@
#!/usr/bin/env python
"""
Test script for async email functionality
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.contrib.auth.models import User
from recruitment.email_service import send_bulk_email
from recruitment.models import JobPosting, Candidate
def test_async_email():
"""Test async email sending functionality"""
print("🧪 Testing Async Email Functionality")
print("=" * 50)
try:
# Get a test user
test_user = User.objects.first()
if not test_user:
print("❌ No users found in database. Please create a user first.")
return
# Get a test job and candidate
test_job = JobPosting.objects.first()
test_candidate = Candidate.objects.first()
if not test_job or not test_candidate:
print("❌ No test job or candidate found. Please create some test data first.")
return
print(f"📧 Test User: {test_user.email}")
print(f"💼 Test Job: {test_job.title}")
print(f"👤 Test Candidate: {test_candidate.name}")
# Test synchronous email sending
print("\n1. Testing Synchronous Email Sending...")
try:
sync_result = send_bulk_email(
subject="Test Synchronous Email",
message="This is a test synchronous email from the ATS system.",
recipient_list=[test_user.email],
async_task=False
)
print(f" ✅ Sync result: {sync_result}")
except Exception as e:
print(f" ❌ Sync error: {e}")
# Test asynchronous email sending
print("\n2. Testing Asynchronous Email Sending...")
try:
async_result = send_bulk_email(
subject="Test Asynchronous Email",
message="This is a test asynchronous email from the ATS system.",
recipient_list=[test_user.email],
async_task=True
)
print(f" ✅ Async result: {async_result}")
except Exception as e:
print(f" ❌ Async error: {e}")
print("\n3. Testing Email Service Status...")
# Check Django Q configuration
try:
import django_q
from django_q.models import Task
pending_tasks = Task.objects.count()
print(f" 📊 Django Q Status: Installed, {pending_tasks} tasks in queue")
except ImportError:
print(" ⚠️ Django Q not installed")
except Exception as e:
print(f" 📊 Django Q Status: Installed but error checking status: {e}")
# Check email backend configuration
from django.conf import settings
email_backend = getattr(settings, 'EMAIL_BACKEND', 'not configured')
print(f" 📧 Email Backend: {email_backend}")
email_host = getattr(settings, 'EMAIL_HOST', 'not configured')
print(f" 🌐 Email Host: {email_host}")
email_port = getattr(settings, 'EMAIL_PORT', 'not configured')
print(f" 🔌 Email Port: {email_port}")
print("\n✅ Async email functionality test completed!")
print("💡 If emails are not being received, check:")
print(" - Email server configuration in settings.py")
print(" - Django Q cluster status (python manage.py qmonitor)")
print(" - Email logs and spam folders")
except Exception as e:
print(f"❌ Test failed with error: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
test_async_email()

View File

@ -1,131 +0,0 @@
#!/usr/bin/env python
"""
Test script to verify CSV export functionality with updated JSON structure
"""
import os
import sys
import django
# Setup Django environment
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from recruitment.models import Candidate, JobPosting
from recruitment.views_frontend import export_candidates_csv
from django.test import RequestFactory
from django.contrib.auth.models import User
def test_csv_export():
"""Test the CSV export function with sample data"""
print("🧪 Testing CSV Export Functionality")
print("=" * 50)
# Create a test request factory
factory = RequestFactory()
# Get or create a test user
user, created = User.objects.get_or_create(
username='testuser',
defaults={'email': 'test@example.com', 'is_staff': True}
)
# Get a sample job
job = JobPosting.objects.first()
if not job:
print("❌ No jobs found in database. Please create a job first.")
return False
print(f"📋 Using job: {job.title}")
# Test different stages
stages = ['screening', 'exam', 'interview', 'offer', 'hired']
for stage in stages:
print(f"\n🔍 Testing stage: {stage}")
# Create a mock request
request = factory.get(f'/export/{job.slug}/{stage}/')
request.user = user
request.GET = {'search': ''}
try:
# Call the export function
response = export_candidates_csv(request, job.slug, stage)
# Check if response is successful
if response.status_code == 200:
print(f"{stage} export successful")
# Read and analyze the CSV content
content = response.content.decode('utf-8-sig')
lines = content.split('\n')
if len(lines) > 1:
headers = lines[0].split(',')
print(f"📊 Headers: {len(headers)} columns")
print(f"📊 Data rows: {len(lines) - 1}")
# Check for AI score column
if 'Match Score' in headers:
print("✅ Match Score column found")
else:
print("⚠️ Match Score column not found")
# Check for other AI columns
ai_columns = ['Years Experience', 'Screening Rating', 'Professional Category', 'Top 3 Skills']
found_ai_columns = [col for col in ai_columns if col in headers]
print(f"🤖 AI columns found: {found_ai_columns}")
else:
print("⚠️ No data rows found")
else:
print(f"{stage} export failed with status: {response.status_code}")
except Exception as e:
print(f"{stage} export error: {str(e)}")
import traceback
traceback.print_exc()
# Test with actual candidate data
print(f"\n🔍 Testing with actual candidate data")
candidates = Candidate.objects.filter(job=job)
print(f"📊 Total candidates for job: {candidates.count()}")
if candidates.exists():
# Test AI data extraction for first candidate
candidate = candidates.first()
print(f"\n🧪 Testing AI data extraction for: {candidate.name}")
try:
# Test the model properties
print(f"📊 Match Score: {candidate.match_score}")
print(f"📊 Years Experience: {candidate.years_of_experience}")
print(f"📊 Screening Rating: {candidate.screening_stage_rating}")
print(f"📊 Professional Category: {candidate.professional_category}")
print(f"📊 Top 3 Skills: {candidate.top_3_keywords}")
print(f"📊 Strengths: {candidate.strengths}")
print(f"📊 Weaknesses: {candidate.weaknesses}")
# Test AI analysis data structure
if candidate.ai_analysis_data:
print(f"📊 AI Analysis Data keys: {list(candidate.ai_analysis_data.keys())}")
if 'analysis_data' in candidate.ai_analysis_data:
analysis_keys = list(candidate.ai_analysis_data['analysis_data'].keys())
print(f"📊 Analysis Data keys: {analysis_keys}")
else:
print("⚠️ 'analysis_data' key not found in ai_analysis_data")
else:
print("⚠️ No AI analysis data found")
except Exception as e:
print(f"❌ Error extracting AI data: {str(e)}")
import traceback
traceback.print_exc()
print("\n🎉 CSV Export Test Complete!")
return True
if __name__ == '__main__':
test_csv_export()

File diff suppressed because one or more lines are too long

View File

@ -1,267 +0,0 @@
#!/usr/bin/env python
"""
Clean test script for email attachment functionality
"""
import os
import sys
import django
from django.conf import settings
# Configure Django settings BEFORE importing any Django modules
if not settings.configured:
settings.configure(
DEBUG=True,
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
},
USE_TZ=True,
SECRET_KEY='test-secret-key',
INSTALLED_APPS=[
'django.contrib.contenttypes',
'django.contrib.auth',
'django.contrib.sessions',
'recruitment',
],
EMAIL_BACKEND='django.core.mail.backends.console.EmailBackend',
MEDIA_ROOT='/tmp/test_media',
FILE_UPLOAD_TEMP_DIR='/tmp/test_uploads',
)
# Setup Django
django.setup()
# Now import Django modules
from django.test import TestCase, Client
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files.base import ContentFile
import io
from unittest.mock import Mock
from recruitment.email_service import send_bulk_email
from recruitment.forms import CandidateEmailForm
from recruitment.models import JobPosting, Candidate
from django.test import RequestFactory
from django.contrib.auth.models import User
# Setup test database
from django.db import connection
from django.core.management import execute_from_command_line
def setup_test_data():
"""Create test data for email attachment testing"""
# Create test user
user = User.objects.create_user(
username='testuser',
email='test@example.com',
first_name='Test',
last_name='User'
)
# Create test job
job = JobPosting.objects.create(
title='Test Job Position',
description='This is a test job for email attachment testing.',
status='ACTIVE',
internal_job_id='TEST-001'
)
# Create test candidate
candidate = Candidate.objects.create(
first_name='John',
last_name='Doe',
email='john.doe@example.com',
phone='+1234567890',
address='123 Test Street',
job=job,
stage='Interview'
)
return user, job, candidate
def test_email_service_with_attachments():
"""Test the email service directly with attachments"""
print("Testing email service with attachments...")
# Create test files
test_files = []
# Test 1: Simple text file
text_content = "This is a test attachment content."
text_file = ContentFile(
text_content.encode('utf-8'),
name='test_document.txt'
)
test_files.append(('test_document.txt', text_file, 'text/plain'))
# Test 2: PDF content (simulated)
pdf_content = b'%PDF-1.4\n1 0 obj\n<<\n/Length 100\n>>stream\nxref\nstartxref\n1234\n5678\n/ModDate(D:20250101)\n'
pdf_file = ContentFile(
pdf_content,
name='test_document.pdf'
)
test_files.append(('test_document.pdf', pdf_file, 'application/pdf'))
# Test 3: Image file (simulated PNG header)
image_content = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01'
image_file = ContentFile(
image_content,
name='test_image.png'
)
test_files.append(('test_image.png', image_file, 'image/png'))
try:
# Test email service with attachments
result = send_bulk_email(
subject='Test Email with Attachments',
body='This is a test email with attachments.',
from_email='test@example.com',
recipient_list=['recipient@example.com'],
attachments=test_files
)
print(f"Email service result: {result}")
print("✓ Email service with attachments test passed")
return True
except Exception as e:
print(f"✗ Email service test failed: {e}")
return False
def test_candidate_email_form_with_attachments():
"""Test the CandidateEmailForm with attachments"""
print("\nTesting CandidateEmailForm with attachments...")
user, job, candidate = setup_test_data()
# Create test files for form
text_file = SimpleUploadedFile(
"test.txt",
b"This is test content for form attachment"
)
pdf_file = SimpleUploadedFile(
"test.pdf",
b"%PDF-1.4 test content"
)
form_data = {
'subject': 'Test Subject',
'body': 'Test body content',
'from_email': 'test@example.com',
'recipient_list': 'recipient@example.com',
}
files_data = {
'attachments': [text_file, pdf_file]
}
try:
form = CandidateEmailForm(data=form_data, files=files_data)
if form.is_valid():
print("✓ Form validation passed")
print(f"Form cleaned data: {form.cleaned_data}")
# Test form processing
try:
result = form.save()
print(f"✓ Form save result: {result}")
return True
except Exception as e:
print(f"✗ Form save failed: {e}")
return False
else:
print(f"✗ Form validation failed: {form.errors}")
return False
except Exception as e:
print(f"✗ Form test failed: {e}")
return False
def test_email_view_with_attachments():
"""Test the email view with attachments"""
print("\nTesting email view with attachments...")
user, job, candidate = setup_test_data()
factory = RequestFactory()
# Create a mock request with files
text_file = SimpleUploadedFile(
"test.txt",
b"This is test content for view attachment"
)
request = factory.post(
'/recruitment/send-candidate-email/',
data={
'subject': 'Test Subject',
'body': 'Test body content',
'from_email': 'test@example.com',
'recipient_list': 'recipient@example.com',
},
format='multipart'
)
request.FILES['attachments'] = [text_file]
request.user = user
try:
# Import and test the view
from recruitment.views import send_candidate_email
response = send_candidate_email(request)
print(f"View response status: {response.status_code}")
if response.status_code == 200:
print("✓ Email view test passed")
return True
else:
print(f"✗ Email view test failed with status: {response.status_code}")
return False
except Exception as e:
print(f"✗ Email view test failed: {e}")
return False
def main():
"""Run all email attachment tests"""
print("=" * 60)
print("EMAIL ATTACHMENT FUNCTIONALITY TESTS")
print("=" * 60)
# Initialize Django
django.setup()
# Create tables
from django.core.management import execute_from_command_line
execute_from_command_line(['manage.py', 'migrate', '--run-syncdb'])
results = []
# Run tests
results.append(test_email_service_with_attachments())
results.append(test_candidate_email_form_with_attachments())
results.append(test_email_view_with_attachments())
# Summary
print("\n" + "=" * 60)
print("TEST SUMMARY")
print("=" * 60)
passed = sum(results)
total = len(results)
print(f"Tests passed: {passed}/{total}")
if passed == total:
print("🎉 All email attachment tests passed!")
return True
else:
print("❌ Some email attachment tests failed!")
return False
if __name__ == '__main__':
success = main()
exit(0 if success else 1)

View File

@ -1,218 +0,0 @@
#!/usr/bin/env python3
"""
Test script to verify email composition functionality
"""
import os
import sys
import django
# Setup Django environment
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from django.utils import timezone
from recruitment.models import JobPosting, Candidate
from unittest.mock import patch, MagicMock
def test_email_composition_view():
"""Test the email composition view"""
print("Testing email composition view...")
# Create test user (delete if exists)
User.objects.filter(username='testuser').delete()
user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
# Create test job
job = JobPosting.objects.create(
title='Test Job',
internal_job_id='TEST001',
description='Test job description',
status='active',
application_deadline=timezone.now() + timezone.timedelta(days=30)
)
# Add user to job participants so they appear in recipient choices
job.users.add(user)
# Create test candidate
candidate = Candidate.objects.create(
first_name='Test Candidate',
last_name='',
email='candidate@example.com',
phone='1234567890',
job=job
)
# Create client and login
client = Client()
client.login(username='testuser', password='testpass123')
# Test GET request to email composition view
url = reverse('compose_candidate_email', kwargs={
'job_slug': job.slug,
'candidate_slug': candidate.slug
})
try:
response = client.get(url)
print(f"✓ GET request successful: {response.status_code}")
if response.status_code == 200:
print("✓ Email composition form rendered successfully")
# Check if form contains expected fields
content = response.content.decode('utf-8')
if 'subject' in content.lower():
print("✓ Subject field found in form")
if 'message' in content.lower():
print("✓ Message field found in form")
if 'recipients' in content.lower():
print("✓ Recipients field found in form")
else:
print(f"✗ Unexpected status code: {response.status_code}")
except Exception as e:
print(f"✗ Error testing GET request: {e}")
# Test POST request with mock email sending
post_data = {
'subject': 'Test Subject',
'message': 'Test message content',
'recipients': ['candidate@example.com'],
'include_candidate_info': True,
'include_meeting_details': False
}
with patch('django.core.mail.send_mass_mail') as mock_send_mail:
mock_send_mail.return_value = 1
try:
response = client.post(url, data=post_data)
print(f"✓ POST request successful: {response.status_code}")
if response.status_code == 200:
# Check if JSON response is correct
try:
json_data = response.json()
if json_data.get('success'):
print("✓ Email sent successfully")
print(f"✓ Success message: {json_data.get('message')}")
else:
print(f"✗ Email send failed: {json_data.get('error')}")
except:
print("✗ Invalid JSON response")
else:
print(f"✗ Unexpected status code: {response.status_code}")
except Exception as e:
print(f"✗ Error testing POST request: {e}")
# Clean up
user.delete()
job.delete()
candidate.delete()
print("Email composition test completed!")
def test_email_form():
"""Test the CandidateEmailForm"""
print("\nTesting CandidateEmailForm...")
from recruitment.forms import CandidateEmailForm
# Create test user for form (delete if exists)
User.objects.filter(username='formuser').delete()
form_user = User.objects.create_user(
username='formuser',
email='form@example.com',
password='formpass123'
)
# Create test job and candidate for form
job = JobPosting.objects.create(
title='Test Job Form',
internal_job_id='TEST002',
description='Test job description for form',
status='active',
application_deadline=timezone.now() + timezone.timedelta(days=30)
)
# Add user to job participants so they appear in recipient choices
job.users.add(form_user)
candidate = Candidate.objects.create(
first_name='Test Candidate',
last_name='Form',
email='candidate_form@example.com',
phone='1234567890',
job=job
)
try:
# Test valid form data - get available choices from form
form = CandidateEmailForm(job, candidate)
available_choices = [choice[0] for choice in form.fields['recipients'].choices]
# Use first available choice for testing
test_recipient = available_choices[0] if available_choices else None
if test_recipient:
form = CandidateEmailForm(job, candidate, data={
'subject': 'Test Subject',
'message': 'Test message content',
'recipients': [test_recipient],
'include_candidate_info': True,
'include_meeting_details': False
})
if form.is_valid():
print("✓ Form validation passed")
print(f"✓ Cleaned recipients: {form.cleaned_data['recipients']}")
else:
print(f"✗ Form validation failed: {form.errors}")
else:
print("✗ No recipient choices available for testing")
except Exception as e:
print(f"✗ Error testing form: {e}")
try:
# Test invalid form data (empty subject)
form = CandidateEmailForm(job, candidate, data={
'subject': '',
'message': 'Test message content',
'recipients': [],
'include_candidate_info': True,
'include_meeting_details': False
})
if not form.is_valid():
print("✓ Form correctly rejected empty subject")
if 'subject' in form.errors:
print("✓ Subject field has validation error")
else:
print("✗ Form should have failed validation")
except Exception as e:
print(f"✗ Error testing invalid form: {e}")
# Clean up
job.delete()
candidate.delete()
if __name__ == '__main__':
print("Running Email Composition Tests")
print("=" * 50)
test_email_form()
test_email_composition_view()
print("\n" + "=" * 50)
print("All tests completed!")

View File

@ -1,507 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Compose Form Test</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
<h1>Email Compose Form JavaScript Test</h1>
<!-- Mock form for testing JavaScript -->
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">
<i class="fas fa-envelope me-2"></i>
Compose Email
</h5>
</div>
<div class="card-body">
<form method="post" id="email-compose-form" action="/test/">
<input type="hidden" name="csrfmiddlewaretoken" value="test-token">
<!-- Subject Field -->
<div class="mb-3">
<label for="id_subject" class="form-label fw-bold">
Subject
</label>
<input type="text" class="form-control" id="id_subject" name="subject">
</div>
<!-- Recipients Field -->
<div class="mb-3">
<label class="form-label fw-bold">
Recipients
</label>
<div class="border rounded p-3 bg-light" style="max-height: 200px; overflow-y: auto;">
<div class="form-check mb-2">
<input type="checkbox" class="form-check-input" name="recipients" value="user1@example.com" id="recipient1">
<label class="form-check-label" for="recipient1">user1@example.com</label>
</div>
<div class="form-check mb-2">
<input type="checkbox" class="form-check-input" name="recipients" value="user2@example.com" id="recipient2">
<label class="form-check-label" for="recipient2">user2@example.com</label>
</div>
</div>
</div>
<!-- Message Field -->
<div class="mb-3">
<label for="id_message" class="form-label fw-bold">
Message
</label>
<textarea class="form-control" id="id_message" name="message" rows="5"></textarea>
</div>
<!-- Options Checkboxes -->
<div class="mb-4">
<div class="row">
<div class="col-md-6">
<div class="form-check">
<input type="checkbox" class="form-check-input" name="include_candidate_info" id="id_include_candidate_info">
<label class="form-check-label" for="id_include_candidate_info">
Include candidate information
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check">
<input type="checkbox" class="form-check-input" name="include_meeting_details" id="id_include_meeting_details">
<label class="form-check-label" for="id_include_meeting_details">
Include meeting details
</label>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between align-items-center">
<div class="text-muted small">
<i class="fas fa-info-circle me-1"></i>
Email will be sent to all selected recipients
</div>
<div>
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>
Cancel
</button>
<button type="submit" class="btn btn-primary" id="send-email-btn">
<i class="fas fa-paper-plane me-1"></i>
Send Email
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Loading Overlay -->
<div id="email-loading-overlay" class="d-none">
<div class="d-flex justify-content-center align-items-center" style="min-height: 200px;">
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div class="mt-2">
Sending email...
</div>
</div>
</div>
</div>
<!-- Success/Error Messages Container -->
<div id="email-messages-container"></div>
</div>
<!-- Test Results -->
<div class="mt-4">
<h3>Test Results</h3>
<div id="test-results"></div>
</div>
</div>
<style>
.card {
border: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
border-radius: 8px;
}
.card-header {
border-radius: 8px 8px 0 0 !important;
border-bottom: none;
}
.form-control:focus {
border-color: #00636e;
box-shadow: 0 0 0 0.2rem rgba(0,99,110,0.25);
}
.btn-primary {
background-color: #00636e;
border-color: #00636e;
}
.btn-primary:hover {
background-color: #004a53;
border-color: #004a53;
}
.form-check-input:checked {
background-color: #00636e;
border-color: #00636e;
}
.border {
border-color: #dee2e6 !important;
}
.bg-light {
background-color: #f8f9fa !important;
}
.text-danger {
color: #dc3545 !important;
}
.spinner-border {
width: 3rem;
height: 3rem;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('email-compose-form');
const sendBtn = document.getElementById('send-email-btn');
const loadingOverlay = document.getElementById('email-loading-overlay');
const messagesContainer = document.getElementById('email-messages-container');
const testResults = document.getElementById('test-results');
// Test results tracking
let tests = [];
function addTestResult(testName, passed, message) {
tests.push({ name: testName, passed, message });
updateTestResults();
}
function updateTestResults() {
const passedTests = tests.filter(t => t.passed).length;
const totalTests = tests.length;
testResults.innerHTML = `
<div class="alert alert-info">
<strong>Tests: ${passedTests}/${totalTests} passed</strong>
</div>
<ul class="list-group">
${tests.map(test => `
<li class="list-group-item ${test.passed ? 'list-group-item-success' : 'list-group-item-danger'}">
<i class="fas fa-${test.passed ? 'check' : 'times'} me-2"></i>
<strong>${test.name}:</strong> ${test.message}
</li>
`).join('')}
</ul>
`;
}
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
addTestResult('Form Submit Handler', true, 'Form submission intercepted successfully');
// Show loading state
if (sendBtn) {
sendBtn.disabled = true;
sendBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> Sending...';
addTestResult('Loading State', true, 'Button loading state activated');
}
if (loadingOverlay) {
loadingOverlay.classList.remove('d-none');
addTestResult('Loading Overlay', true, 'Loading overlay displayed');
}
// Clear previous messages
if (messagesContainer) {
messagesContainer.innerHTML = '';
}
// Mock form submission
setTimeout(() => {
// Hide loading state
if (sendBtn) {
sendBtn.disabled = false;
sendBtn.innerHTML = '<i class="fas fa-paper-plane me-1"></i> Send Email';
}
if (loadingOverlay) {
loadingOverlay.classList.add('d-none');
}
// Show success message
showMessage('Email sent successfully!', 'success');
addTestResult('Success Message', true, 'Success message displayed');
}, 2000);
});
}
function showMessage(message, type) {
if (!messagesContainer) return;
const alertClass = type === 'success' ? 'alert-success' : 'alert-danger';
const icon = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-triangle';
const messageHtml = `
<div class="alert ${alertClass} alert-dismissible fade show" role="alert">
<i class="fas ${icon} me-2"></i>
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
messagesContainer.innerHTML = messageHtml;
// Auto-hide success messages after 5 seconds
if (type === 'success') {
setTimeout(() => {
const alert = messagesContainer.querySelector('.alert');
if (alert) {
const bsAlert = bootstrap.Alert(alert);
bsAlert.close();
addTestResult('Auto-hide Message', true, 'Message auto-hidden after 5 seconds');
}
}, 5000);
}
}
// Form validation
function validateForm() {
let isValid = true;
const subject = form.querySelector('#id_subject');
const message = form.querySelector('#id_message');
const recipients = form.querySelectorAll('input[name="recipients"]:checked');
// Clear previous validation states
form.querySelectorAll('.is-invalid').forEach(field => {
field.classList.remove('is-invalid');
});
form.querySelectorAll('.invalid-feedback').forEach(feedback => {
feedback.remove();
});
// Validate subject
if (!subject || !subject.value.trim()) {
showFieldError(subject, 'Subject is required');
isValid = false;
addTestResult('Subject Validation', false, 'Subject validation triggered - field empty');
} else {
addTestResult('Subject Validation', true, 'Subject validation passed');
}
// Validate message
if (!message || !message.value.trim()) {
showFieldError(message, 'Message is required');
isValid = false;
addTestResult('Message Validation', false, 'Message validation triggered - field empty');
} else {
addTestResult('Message Validation', true, 'Message validation passed');
}
// Validate recipients
if (recipients.length === 0) {
const recipientsContainer = form.querySelector('.border.rounded.p-3.bg-light');
if (recipientsContainer) {
recipientsContainer.classList.add('border-danger');
showFieldError(recipientsContainer, 'Please select at least one recipient');
}
isValid = false;
addTestResult('Recipients Validation', false, 'Recipients validation triggered - none selected');
} else {
addTestResult('Recipients Validation', true, `Recipients validation passed - ${recipients.length} selected`);
}
return isValid;
}
function showFieldError(field, message) {
if (!field) return;
field.classList.add('is-invalid');
const feedback = document.createElement('div');
feedback.className = 'invalid-feedback';
feedback.textContent = message;
if (field.classList.contains('border')) {
// For container elements (like recipients)
field.parentNode.appendChild(feedback);
} else {
// For form fields
field.parentNode.appendChild(feedback);
}
}
// Character counter for message field
function setupCharacterCounter() {
const messageField = form.querySelector('#id_message');
if (!messageField) return;
const counter = document.createElement('div');
counter.className = 'text-muted small mt-1';
counter.id = 'message-counter';
messageField.parentNode.appendChild(counter);
function updateCounter() {
const length = messageField.value.length;
const maxLength = 5000; // Adjust as needed
counter.textContent = `${length} / ${maxLength} characters`;
if (length > maxLength * 0.9) {
counter.classList.add('text-warning');
counter.classList.remove('text-muted');
} else {
counter.classList.remove('text-warning');
counter.classList.add('text-muted');
}
}
messageField.addEventListener('input', updateCounter);
updateCounter(); // Initial count
addTestResult('Character Counter', true, 'Character counter initialized');
}
// Auto-save functionality
let autoSaveTimer;
function setupAutoSave() {
const subject = form.querySelector('#id_subject');
const message = form.querySelector('#id_message');
if (!subject || !message) return;
function saveDraft() {
const draftData = {
subject: subject.value,
message: message.value,
recipients: Array.from(form.querySelectorAll('input[name="recipients"]:checked')).map(cb => cb.value),
include_candidate_info: form.querySelector('#id_include_candidate_info').checked,
include_meeting_details: form.querySelector('#id_include_meeting_details').checked
};
localStorage.setItem('email_draft_test', JSON.stringify(draftData));
addTestResult('Auto-save', true, 'Draft saved to localStorage');
}
function autoSave() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(saveDraft, 2000); // Save after 2 seconds of inactivity
}
[subject, message].forEach(field => {
field.addEventListener('input', autoSave);
});
form.addEventListener('change', autoSave);
addTestResult('Auto-save Setup', true, 'Auto-save functionality initialized');
}
function loadDraft() {
const draftData = localStorage.getItem('email_draft_test');
if (!draftData) return;
try {
const draft = JSON.parse(draftData);
const subject = form.querySelector('#id_subject');
const message = form.querySelector('#id_message');
if (subject && draft.subject) subject.value = draft.subject;
if (message && draft.message) message.value = draft.message;
// Restore recipients
if (draft.recipients) {
form.querySelectorAll('input[name="recipients"]').forEach(cb => {
cb.checked = draft.recipients.includes(cb.value);
});
}
// Restore checkboxes
if (draft.include_candidate_info) {
form.querySelector('#id_include_candidate_info').checked = draft.include_candidate_info;
}
if (draft.include_meeting_details) {
form.querySelector('#id_include_meeting_details').checked = draft.include_meeting_details;
}
addTestResult('Draft Loading', true, 'Draft loaded from localStorage');
showMessage('Draft restored from local storage', 'success');
} catch (e) {
console.error('Error loading draft:', e);
addTestResult('Draft Loading', false, 'Error loading draft: ' + e.message);
}
}
function clearDraft() {
localStorage.removeItem('email_draft_test');
}
// Initialize form enhancements
setupCharacterCounter();
setupAutoSave();
// Load draft on page load
setTimeout(loadDraft, 100);
// Clear draft on successful submission
const originalSubmitHandler = form.onsubmit;
form.addEventListener('submit', function(e) {
const isValid = validateForm();
if (!isValid) {
e.preventDefault();
e.stopPropagation();
return false;
}
// Clear draft on successful submission
setTimeout(clearDraft, 2000);
});
// Add keyboard shortcuts
document.addEventListener('keydown', function(e) {
// Ctrl/Cmd + Enter to submit
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
const activeElement = document.activeElement;
if (activeElement && (activeElement.tagName === 'TEXTAREA' || activeElement.tagName === 'INPUT')) {
form.dispatchEvent(new Event('submit'));
addTestResult('Keyboard Shortcut', true, 'Ctrl+Enter shortcut triggered');
}
}
// Escape to cancel/close modal
if (e.key === 'Escape') {
addTestResult('Keyboard Shortcut', true, 'Escape key pressed');
}
});
// Test validation with empty form
setTimeout(() => {
addTestResult('Initial Validation Test', validateForm() === false, 'Empty form correctly rejected');
}, 500);
console.log('Email compose form initialized');
addTestResult('Initialization', true, 'Email compose form JavaScript initialized successfully');
});
</script>
</body>
</html>

View File

@ -1,176 +0,0 @@
#!/usr/bin/env python
"""
Test script for HTML email template functionality
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from recruitment.models import Candidate, JobPosting
from recruitment.email_service import send_interview_invitation_email
def test_html_template():
"""Test the HTML email template rendering"""
print("Testing HTML email template...")
# Create test context
context = {
'candidate_name': 'John Doe',
'candidate_email': 'john.doe@example.com',
'candidate_phone': '+966 50 123 4567',
'job_title': 'Senior Software Developer',
'department': 'Information Technology',
'company_name': 'Norah University',
'meeting_topic': 'Interview for Senior Software Developer',
'meeting_date_time': 'November 15, 2025 at 2:00 PM',
'meeting_duration': '60 minutes',
'join_url': 'https://zoom.us/j/123456789',
}
try:
# Test template rendering
html_content = render_to_string('emails/interview_invitation.html', context)
plain_content = strip_tags(html_content)
print("✅ HTML template rendered successfully!")
print(f"HTML content length: {len(html_content)} characters")
print(f"Plain text length: {len(plain_content)} characters")
# Save rendered HTML to file for inspection
with open('test_interview_email.html', 'w', encoding='utf-8') as f:
f.write(html_content)
print("✅ HTML content saved to 'test_interview_email.html'")
# Save plain text to file for inspection
with open('test_interview_email.txt', 'w', encoding='utf-8') as f:
f.write(plain_content)
print("✅ Plain text content saved to 'test_interview_email.txt'")
return True
except Exception as e:
print(f"❌ Error rendering template: {e}")
return False
def test_email_service_function():
"""Test the email service function with mock data"""
print("\nTesting email service function...")
try:
# Get a real candidate and job for testing
candidate = Candidate.objects.first()
job = JobPosting.objects.first()
if not candidate:
print("❌ No candidates found in database")
return False
if not job:
print("❌ No jobs found in database")
return False
print(f"Using candidate: {candidate.name}")
print(f"Using job: {job.title}")
# Test meeting details
meeting_details = {
'topic': f'Interview for {job.title}',
'date_time': 'November 15, 2025 at 2:00 PM',
'duration': '60 minutes',
'join_url': 'https://zoom.us/j/test123456',
}
# Test the email function (without actually sending)
result = send_interview_invitation_email(
candidate=candidate,
job=job,
meeting_details=meeting_details,
recipient_list=['test@example.com']
)
if result['success']:
print("✅ Email service function executed successfully!")
print(f"Recipients: {result.get('recipients_count', 'N/A')}")
print(f"Message: {result.get('message', 'N/A')}")
else:
print(f"❌ Email service function failed: {result.get('error', 'Unknown error')}")
return result['success']
except Exception as e:
print(f"❌ Error testing email service: {e}")
return False
def test_template_variables():
"""Test all template variables"""
print("\nTesting template variables...")
# Test with minimal data
minimal_context = {
'candidate_name': 'Test Candidate',
'candidate_email': 'test@example.com',
'job_title': 'Test Position',
}
try:
html_content = render_to_string('emails/interview_invitation.html', minimal_context)
print("✅ Template works with minimal data")
# Check for required variables
required_vars = ['candidate_name', 'candidate_email', 'job_title']
missing_vars = []
for var in required_vars:
if f'{{ {var} }}' in html_content:
missing_vars.append(var)
if missing_vars:
print(f"⚠️ Missing variables: {missing_vars}")
else:
print("✅ All required variables are present")
return True
except Exception as e:
print(f"❌ Error with minimal data: {e}")
return False
def main():
"""Run all tests"""
print("🧪 Testing HTML Email Template System")
print("=" * 50)
# Test 1: Template rendering
test1_passed = test_html_template()
# Test 2: Template variables
test2_passed = test_template_variables()
# Test 3: Email service function
test3_passed = test_email_service_function()
# Summary
print("\n" + "=" * 50)
print("📊 TEST SUMMARY")
print(f"Template Rendering: {'✅ PASS' if test1_passed else '❌ FAIL'}")
print(f"Template Variables: {'✅ PASS' if test2_passed else '❌ FAIL'}")
print(f"Email Service: {'✅ PASS' if test3_passed else '❌ FAIL'}")
overall_success = test1_passed and test2_passed and test3_passed
print(f"\nOverall Result: {'✅ ALL TESTS PASSED' if overall_success else '❌ SOME TESTS FAILED'}")
if overall_success:
print("\n🎉 HTML email template system is ready!")
print("You can now send professional interview invitations using the new template.")
else:
print("\n🔧 Please fix the issues before using the template system.")
if __name__ == '__main__':
main()

View File

@ -1,139 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Interview Invitation</title>
<style>
/* Basic reset and typography */
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333333;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
/* Container for the main content */
.container {
max-width: 600px;
margin: 20px auto;
background-color: #ffffff;
padding: 30px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Header styling */
.header {
text-align: center;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
margin-bottom: 20px;
}
.header h1 {
color: #007bff;
font-size: 24px;
margin: 0;
}
/* Section headings */
.section-header {
color: #007bff;
font-size: 18px;
margin-top: 25px;
margin-bottom: 10px;
border-left: 4px solid #007bff;
padding-left: 10px;
}
/* Key detail rows */
.detail-row {
margin-bottom: 10px;
}
.detail-row strong {
display: inline-block;
width: 120px;
color: #555555;
}
/* Button style for the Join URL */
.button {
display: block;
width: 80%;
margin: 25px auto;
padding: 12px 0;
background-color: #28a745; /* Success/Go color */
color: #ffffff;
text-align: center;
text-decoration: none;
border-radius: 5px;
font-weight: bold;
font-size: 16px;
}
/* Footer/closing section */
.footer {
margin-top: 30px;
padding-top: 15px;
border-top: 1px dashed #cccccc;
text-align: center;
font-size: 14px;
color: #777777;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Interview Confirmation</h1>
</div>
<p>Dear <strong>John Doe</strong>,</p>
<p>Thank you for your interest in the position. We are pleased to invite you to a virtual interview. Please find the details below.</p>
<h2 class="section-header">Interview Details</h2>
<div class="detail-row">
<strong>Topic:</strong> Interview for Senior Software Developer
</div>
<div class="detail-row">
<strong>Date & Time:</strong> <strong>November 15, 2025 at 2:00 PM</strong>
</div>
<div class="detail-row">
<strong>Duration:</strong> 60 minutes
</div>
<a href="https://zoom.us/j/123456789" class="button" target="_blank">
Join Interview Now
</a>
<p style="text-align: center; font-size: 14px; color: #777;">Please click the button above to join the meeting at the scheduled time.</p>
<h2 class="section-header">Your Information</h2>
<div class="detail-row">
<strong>Name:</strong> John Doe
</div>
<div class="detail-row">
<strong>Email:</strong> john.doe@example.com
</div>
<div class="detail-row">
<strong>Phone:</strong> +966 50 123 4567
</div>
<h2 class="section-header">Position Details</h2>
<div class="detail-row">
<strong>Position:</strong> Senior Software Developer
</div>
<div class="detail-row">
<strong>Department:</strong> Information Technology
</div>
<div class="footer">
<p>We look forward to speaking with you.</p>
<p>If you have any questions, please reply to this email.</p>
<p>Best regards,<br>The Norah University Team</p>
</div>
</div>
</body>
</html>

View File

@ -1,139 +0,0 @@
Interview Invitation
/* Basic reset and typography */
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333333;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
/* Container for the main content */
.container {
max-width: 600px;
margin: 20px auto;
background-color: #ffffff;
padding: 30px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Header styling */
.header {
text-align: center;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
margin-bottom: 20px;
}
.header h1 {
color: #007bff;
font-size: 24px;
margin: 0;
}
/* Section headings */
.section-header {
color: #007bff;
font-size: 18px;
margin-top: 25px;
margin-bottom: 10px;
border-left: 4px solid #007bff;
padding-left: 10px;
}
/* Key detail rows */
.detail-row {
margin-bottom: 10px;
}
.detail-row strong {
display: inline-block;
width: 120px;
color: #555555;
}
/* Button style for the Join URL */
.button {
display: block;
width: 80%;
margin: 25px auto;
padding: 12px 0;
background-color: #28a745; /* Success/Go color */
color: #ffffff;
text-align: center;
text-decoration: none;
border-radius: 5px;
font-weight: bold;
font-size: 16px;
}
/* Footer/closing section */
.footer {
margin-top: 30px;
padding-top: 15px;
border-top: 1px dashed #cccccc;
text-align: center;
font-size: 14px;
color: #777777;
}
Interview Confirmation
Dear John Doe,
Thank you for your interest in the position. We are pleased to invite you to a virtual interview. Please find the details below.
Interview Details
Topic: Interview for Senior Software Developer
Date & Time: November 15, 2025 at 2:00 PM
Duration: 60 minutes
Join Interview Now
Please click the button above to join the meeting at the scheduled time.
Your Information
Name: John Doe
Email: john.doe@example.com
Phone: +966 50 123 4567
Position Details
Position: Senior Software Developer
Department: Information Technology
We look forward to speaking with you.
If you have any questions, please reply to this email.
Best regards,The Norah University Team

View File

@ -1,239 +0,0 @@
#!/usr/bin/env python
"""
Simple test script for basic email functionality without attachments
"""
import os
import sys
import django
from django.conf import settings
# Configure Django settings BEFORE importing any Django modules
if not settings.configured:
settings.configure(
DEBUG=True,
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
},
USE_TZ=True,
SECRET_KEY='test-secret-key',
INSTALLED_APPS=[
'django.contrib.contenttypes',
'django.contrib.auth',
'django.contrib.sessions',
'recruitment',
],
EMAIL_BACKEND='django.core.mail.backends.console.EmailBackend',
)
# Setup Django
django.setup()
# Now import Django modules
from django.test import TestCase, Client
from django.test import RequestFactory
from django.contrib.auth.models import User
from recruitment.email_service import send_bulk_email
from recruitment.forms import CandidateEmailForm
from recruitment.models import JobPosting, Candidate, Participants
def setup_test_data():
"""Create test data for email testing"""
# Create test user (get or create to avoid duplicates)
user, created = User.objects.get_or_create(
username='testuser',
defaults={
'email': 'test@example.com',
'first_name': 'Test',
'last_name': 'User'
}
)
# Create test job
from datetime import datetime, timedelta
job = JobPosting.objects.create(
title='Test Job Position',
description='This is a test job for email testing.',
status='ACTIVE',
internal_job_id='TEST-001',
application_deadline=datetime.now() + timedelta(days=30)
)
# Create test candidate
candidate = Candidate.objects.create(
first_name='John',
last_name='Doe',
email='john.doe@example.com',
phone='+1234567890',
address='123 Test Street',
job=job,
stage='Interview'
)
# Create test participants
participant1 = Participants.objects.create(
name='Alice Smith',
email='alice@example.com',
phone='+1234567891',
designation='Interviewer'
)
participant2 = Participants.objects.create(
name='Bob Johnson',
email='bob@example.com',
phone='+1234567892',
designation='Hiring Manager'
)
# Add participants to job
job.participants.add(participant1, participant2)
return user, job, candidate, [participant1, participant2]
def test_email_service_basic():
"""Test the email service with basic functionality"""
print("Testing basic email service...")
try:
# Test email service without attachments
result = send_bulk_email(
subject='Test Basic Email',
message='This is a test email without attachments.',
recipient_list=['recipient1@example.com', 'recipient2@example.com']
)
print(f"Email service result: {result}")
print("✓ Basic email service test passed")
return True
except Exception as e:
print(f"✗ Basic email service test failed: {e}")
return False
def test_candidate_email_form_basic():
"""Test the CandidateEmailForm without attachments"""
print("\nTesting CandidateEmailForm without attachments...")
user, job, candidate, participants = setup_test_data()
form_data = {
'subject': 'Test Subject',
'message': 'Test body content',
'recipients': [f'participant_{p.id}' for p in participants],
'include_candidate_info': True,
'include_meeting_details': True,
}
try:
form = CandidateEmailForm(data=form_data, job=job, candidate=candidate)
if form.is_valid():
print("✓ Form validation passed")
print(f"Form cleaned data keys: {list(form.cleaned_data.keys())}")
# Test getting email addresses
email_addresses = form.get_email_addresses()
print(f"Email addresses: {email_addresses}")
# Test getting formatted message
formatted_message = form.get_formatted_message()
print(f"Formatted message length: {len(formatted_message)} characters")
return True
else:
print(f"✗ Form validation failed: {form.errors}")
return False
except Exception as e:
print(f"✗ Form test failed: {e}")
return False
def test_email_sending_workflow():
"""Test the complete email sending workflow"""
print("\nTesting complete email sending workflow...")
user, job, candidate, participants = setup_test_data()
form_data = {
'subject': 'Interview Update: John Doe - Test Job Position',
'message': 'Please find the interview update below.',
'recipients': [f'participant_{p.id}' for p in participants],
'include_candidate_info': True,
'include_meeting_details': True,
}
try:
# Create and validate form
form = CandidateEmailForm(data=form_data, job=job, candidate=candidate)
if not form.is_valid():
print(f"✗ Form validation failed: {form.errors}")
return False
# Get email data
subject = form.cleaned_data['subject']
message = form.get_formatted_message()
recipient_emails = form.get_email_addresses()
print(f"Subject: {subject}")
print(f"Recipients: {recipient_emails}")
print(f"Message preview: {message[:200]}...")
# Send email using service
result = send_bulk_email(
subject=subject,
message=message,
recipient_list=recipient_emails
)
print(f"Email sending result: {result}")
print("✓ Complete email workflow test passed")
return True
except Exception as e:
print(f"✗ Email workflow test failed: {e}")
return False
def main():
"""Run all simple email tests"""
print("=" * 60)
print("SIMPLE EMAIL FUNCTIONALITY TESTS")
print("=" * 60)
# Initialize Django
django.setup()
# Create tables
from django.core.management import execute_from_command_line
execute_from_command_line(['manage.py', 'migrate', '--run-syncdb'])
results = []
# Run tests
results.append(test_email_service_basic())
results.append(test_candidate_email_form_basic())
results.append(test_email_sending_workflow())
# Summary
print("\n" + "=" * 60)
print("TEST SUMMARY")
print("=" * 60)
passed = sum(results)
total = len(results)
print(f"Tests passed: {passed}/{total}")
if passed == total:
print("🎉 All simple email tests passed!")
return True
else:
print("❌ Some simple email tests failed!")
return False
if __name__ == '__main__':
success = main()
exit(0 if success else 1)

View File

@ -1,216 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 5px;
}
.connected {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.disconnected {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.notification {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
}
#notifications {
max-height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
padding: 10px;
margin: 10px 0;
}
button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 5px;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>SSE Notification Test</h1>
<div id="status" class="status disconnected">
Disconnected
</div>
<div>
<button id="connectBtn" onclick="connectSSE()">Connect</button>
<button id="disconnectBtn" onclick="disconnectSSE()" disabled>Disconnect</button>
<button onclick="clearNotifications()">Clear Notifications</button>
</div>
<h3>Notifications:</h3>
<div id="notifications">
<p>No notifications yet...</p>
</div>
<h3>Test Instructions:</h3>
<ol>
<li>Click "Connect" to start the SSE connection</li>
<li>Run the test script: <code>python test_sse_notifications.py</code></li>
<li>Watch for real-time notifications to appear below</li>
<li>Check the browser console for debug information</li>
</ol>
<script>
let eventSource = null;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
const reconnectDelay = 3000;
function updateStatus(message, isConnected) {
const statusDiv = document.getElementById('status');
statusDiv.textContent = message;
statusDiv.className = `status ${isConnected ? 'connected' : 'disconnected'}`;
document.getElementById('connectBtn').disabled = isConnected;
document.getElementById('disconnectBtn').disabled = !isConnected;
}
function addNotification(message) {
const notificationsDiv = document.getElementById('notifications');
const notification = document.createElement('div');
notification.className = 'notification';
notification.innerHTML = `
<strong>${new Date().toLocaleTimeString()}</strong><br>
${message}
`;
// Clear the "No notifications yet" message if it exists
if (notificationsDiv.querySelector('p')) {
notificationsDiv.innerHTML = '';
}
notificationsDiv.appendChild(notification);
notificationsDiv.scrollTop = notificationsDiv.scrollHeight;
}
function connectSSE() {
if (eventSource) {
eventSource.close();
}
updateStatus('Connecting...', false);
// Get CSRF token from cookies
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
eventSource = new EventSource('/api/notifications/stream/');
eventSource.onopen = function(event) {
console.log('SSE connection opened:', event);
updateStatus('Connected - Waiting for notifications...', true);
reconnectAttempts = 0;
addNotification('SSE connection established successfully!');
};
eventSource.onmessage = function(event) {
console.log('SSE message received:', event.data);
try {
const data = JSON.parse(event.data);
addNotification(`Notification: ${data.message || 'No message'}`);
} catch (e) {
addNotification(`Raw message: ${event.data}`);
}
};
eventSource.onerror = function(event) {
console.error('SSE error:', event);
updateStatus('Connection error', false);
if (eventSource.readyState === EventSource.CLOSED) {
addNotification('SSE connection closed');
} else {
addNotification('SSE connection error');
}
// Attempt to reconnect
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
addNotification(`Attempting to reconnect (${reconnectAttempts}/${maxReconnectAttempts})...`);
setTimeout(connectSSE, reconnectDelay);
} else {
addNotification('Max reconnection attempts reached');
}
};
eventSource.addEventListener('notification', function(event) {
console.log('Custom notification event:', event.data);
try {
const data = JSON.parse(event.data);
addNotification(`Custom Notification: ${data.message || 'No message'}`);
} catch (e) {
addNotification(`Custom notification: ${event.data}`);
}
});
}
function disconnectSSE() {
if (eventSource) {
eventSource.close();
eventSource = null;
}
updateStatus('Disconnected', false);
addNotification('SSE connection closed by user');
}
function clearNotifications() {
const notificationsDiv = document.getElementById('notifications');
notificationsDiv.innerHTML = '<p>No notifications yet...</p>';
}
// Auto-connect when page loads
window.addEventListener('load', function() {
addNotification('Page loaded. Click "Connect" to start SSE connection.');
});
</script>
</body>
</html>

View File

@ -1,57 +0,0 @@
#!/usr/bin/env python
"""
Test script to generate notifications and test SSE functionality
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.utils import timezone
from django.contrib.auth.models import User
from recruitment.models import Notification
def create_test_notification():
"""Create a test notification for admin user"""
try:
# Get first admin user
admin_user = User.objects.filter(is_staff=True).first()
if not admin_user:
print("No admin user found!")
return
# Create a test notification
notification = Notification.objects.create(
recipient=admin_user,
notification_type=Notification.NotificationType.IN_APP,
message="Test SSE Notification - Real-time update working!",
status=Notification.Status.PENDING,
scheduled_for=timezone.now() # Add required scheduled_for field
)
print(f"Created test notification: {notification.id}")
print(f"Recipient: {admin_user.username}")
print(f"Message: {notification.message}")
print(f"Status: {notification.status}")
return notification
except Exception as e:
print(f"Error creating notification: {e}")
return None
if __name__ == "__main__":
print("Testing SSE Notification System...")
print("=" * 50)
notification = create_test_notification()
if notification:
print("\n✅ Test notification created successfully!")
print("🔥 Check the browser console for SSE events")
print("📱 Open http://localhost:8000/ and look for real-time updates")
else:
print("\n❌ Failed to create test notification")

View File

@ -1,132 +0,0 @@
#!/usr/bin/env python3
"""
Test script for candidate sync functionality
"""
import os
import sys
import django
# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from recruitment.models import JobPosting, Candidate, Source
from recruitment.candidate_sync_service import CandidateSyncService
from django.utils import timezone
def test_sync_service():
"""Test the candidate sync service"""
print("🧪 Testing Candidate Sync Service")
print("=" * 50)
# Initialize sync service
sync_service = CandidateSyncService()
# Get test data
print("📊 Getting test data...")
jobs = JobPosting.objects.all()
sources = Source.objects.filter(supports_outbound_sync=True)
print(f"Found {jobs.count()} jobs")
print(f"Found {sources.count()} sources with outbound sync support")
if not jobs.exists():
print("❌ No jobs found. Creating test job...")
# Create a test job if none exists
job = JobPosting.objects.create(
title="Test Developer Position",
department="IT",
description="Test job for sync functionality",
application_deadline=timezone.now().date() + timezone.timedelta(days=30),
status="ACTIVE"
)
print(f"✅ Created test job: {job.title}")
else:
job = jobs.first()
print(f"✅ Using existing job: {job.title}")
if not sources.exists():
print("❌ No sources with outbound sync found. Creating test source...")
# Create a test source if none exists
source = Source.objects.create(
name="Test ERP System",
source_type="ERP",
sync_endpoint="https://httpbin.org/post", # Test endpoint that echoes back requests
sync_method="POST",
test_method="POST",
supports_outbound_sync=True,
is_active=True,
custom_headers='{"Content-Type": "application/json", "Authorization": "Bearer test-token"}'
)
print(f"✅ Created test source: {source.name}")
else:
source = sources.first()
print(f"✅ Using existing source: {source.name}")
# Test connection
print("\n🔗 Testing source connection...")
try:
connection_result = sync_service.test_source_connection(source)
print(f"✅ Connection test result: {connection_result}")
except Exception as e:
print(f"❌ Connection test failed: {str(e)}")
# Check for hired candidates
hired_candidates = job.candidates.filter(offer_status='Accepted')
print(f"\n👥 Found {hired_candidates.count()} hired candidates")
if hired_candidates.exists():
# Test sync for hired candidates
print("\n🔄 Testing sync for hired candidates...")
try:
results = sync_service.sync_hired_candidates_to_all_sources(job)
print("✅ Sync completed successfully!")
print(f"Results: {results}")
except Exception as e:
print(f"❌ Sync failed: {str(e)}")
else:
print(" No hired candidates to sync. Creating test candidate...")
# Create a test candidate if none exists
candidate = Candidate.objects.create(
job=job,
first_name="Test",
last_name="Candidate",
email="test@example.com",
phone="+1234567890",
address="Test Address",
stage="Offer",
offer_status="Accepted",
offer_date=timezone.now().date(),
ai_analysis_data={
'analysis_data': {
'match_score': 85,
'years_of_experience': 5,
'screening_stage_rating': 'A - Highly Qualified'
}
}
)
print(f"✅ Created test candidate: {candidate.name}")
# Test sync with the new candidate
print("\n🔄 Testing sync with new candidate...")
try:
results = sync_service.sync_hired_candidates_to_all_sources(job)
print("✅ Sync completed successfully!")
print(f"Results: {results}")
except Exception as e:
print(f"❌ Sync failed: {str(e)}")
print("\n🎯 Test Summary")
print("=" * 50)
print("✅ Candidate sync service is working correctly")
print("✅ Source connection testing works")
print("✅ Hired candidate sync functionality verified")
print("\n📝 Next Steps:")
print("1. Configure real source endpoints in the admin panel")
print("2. Test with actual external systems")
print("3. Monitor sync logs for production usage")
if __name__ == "__main__":
test_sync_service()

View File

@ -1,46 +0,0 @@
#!/usr/bin/env python
"""Test script to verify URL configuration"""
import os
import sys
import django
# Add the project directory to the Python path
sys.path.append('/home/ismail/projects/ats/kaauh_ats')
# Set up Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings')
django.setup()
from django.urls import reverse
from django.test import Client
def test_urls():
"""Test the agency access link URLs"""
print("Testing agency access link URLs...")
try:
# Test URL reverse lookup
deactivate_url = reverse('agency_access_link_deactivate', kwargs={'slug': 'test-slug'})
print(f"✓ Deactivate URL: {deactivate_url}")
reactivate_url = reverse('agency_access_link_reactivate', kwargs={'slug': 'test-slug'})
print(f"✓ Reactivate URL: {reactivate_url}")
# Test URL resolution
from django.urls import resolve
deactivate_view = resolve('/recruitment/agency-access-link/test-slug/deactivate/')
print(f"✓ Deactivate view: {deactivate_view.view_name}")
reactivate_view = resolve('/recruitment/agency-access-link/test-slug/reactivate/')
print(f"✓ Reactivate view: {reactivate_view.view_name}")
print("\n✅ All URL tests passed!")
return True
except Exception as e:
print(f"❌ Error testing URLs: {e}")
return False
if __name__ == '__main__':
test_urls()

View File

@ -1,123 +0,0 @@
#!/usr/bin/env python3
"""
Test script to verify Word document integration in recruitment/tasks.py
"""
import os
import sys
import tempfile
# Add the project directory to Python path
sys.path.insert(0, '/home/ismail/projects/ats/kaauh_ats')
# Import the tasks module
try:
from recruitment.tasks import extract_text_from_document, extract_text_from_pdf, extract_text_from_word
print("✓ Successfully imported text extraction functions")
except ImportError as e:
print(f"✗ Failed to import functions: {e}")
sys.exit(1)
def test_pdf_extraction():
"""Test PDF text extraction with a sample PDF"""
print("\n--- Testing PDF Extraction ---")
# Create a temporary PDF file for testing
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp_pdf:
try:
# Create a simple PDF content (this would normally be a real PDF)
tmp_pdf.write(b"%PDF-1.4\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n")
tmp_pdf_path = tmp_pdf.name
# Test the PDF extraction
text = extract_text_from_pdf(tmp_pdf_path)
print(f"✓ PDF extraction completed. Text length: {len(text)}")
# Clean up
os.unlink(tmp_pdf_path)
except Exception as e:
print(f"✗ PDF extraction failed: {e}")
def test_word_extraction():
"""Test Word text extraction with a sample Word document"""
print("\n--- Testing Word Extraction ---")
try:
# Check if python-docx is available
from recruitment.tasks import DOCX_AVAILABLE
if not DOCX_AVAILABLE:
print("⚠ python-docx not available. Skipping Word extraction test.")
return
# Create a temporary Word file for testing
with tempfile.NamedTemporaryFile(suffix='.docx', delete=False) as tmp_docx:
try:
# Create a simple Word document content
tmp_docx.write(b'PK\x03\x04') # Basic DOCX header
tmp_docx_path = tmp_docx.name
# Test the Word extraction
text = extract_text_from_word(tmp_docx_path)
print(f"✓ Word extraction completed. Text length: {len(text)}")
# Clean up
os.unlink(tmp_docx_path)
except Exception as e:
print(f"✗ Word extraction failed: {e}")
# Clean up on failure
if os.path.exists(tmp_docx.name):
os.unlink(tmp_docx.name)
except Exception as e:
print(f"✗ Word extraction setup failed: {e}")
def test_unified_document_parser():
"""Test the unified document parser"""
print("\n--- Testing Unified Document Parser ---")
# Test with non-existent file
try:
extract_text_from_document('/nonexistent/file.pdf')
print("✗ Should have failed for non-existent file")
except FileNotFoundError:
print("✓ Correctly handled non-existent file")
except Exception as e:
print(f"✗ Unexpected error for non-existent file: {e}")
# Test with unsupported file type
with tempfile.NamedTemporaryFile(suffix='.txt', delete=False) as tmp_txt:
try:
tmp_txt.write(b'This is a text file')
tmp_txt_path = tmp_txt.name
try:
extract_text_from_document(tmp_txt_path)
print("✗ Should have failed for unsupported file type")
except ValueError as e:
print(f"✓ Correctly handled unsupported file type: {e}")
except Exception as e:
print(f"✗ Unexpected error for unsupported file type: {e}")
# Clean up
os.unlink(tmp_txt_path)
except Exception as e:
print(f"✗ Test setup failed: {e}")
def main():
"""Run all tests"""
print("Starting Word Document Integration Tests...")
test_pdf_extraction()
test_word_extraction()
test_unified_document_parser()
print("\n--- Test Summary ---")
print("Integration tests completed. Check the output above for any errors.")
print("\nNote: For full Word document processing, ensure python-docx is installed:")
print("pip install python-docx")
if __name__ == "__main__":
main()

View File

@ -1,444 +0,0 @@
#!/usr/bin/env python3
"""
Comprehensive script to translate all remaining batch files with Arabic translations
"""
import re
import os
# Comprehensive Arabic translation dictionary
TRANSLATIONS = {
# Email and Authentication
"The date and time this notification is scheduled to be sent.": "التاريخ والوقت المحدد لإرسال هذا الإشعار.",
"Send Attempts": "محاولات الإرسال",
"Failed to start the job posting process. Please try again.": "فشل في بدء عملية نشر الوظيفة. يرجى المحاولة مرة أخرى.",
"You don't have permission to view this page.": "ليس لديك إذن لعرض هذه الصفحة.",
"Account Inactive": "الحساب غير نشط",
"Princess Nourah bint Abdulrahman University": "جامعة الأميرة نورة بنت عبدالرحمن",
"Manage your personal details and security.": "إدارة تفاصيلك الشخصية والأمان.",
"Primary": "أساسي",
"Verified": "موثق",
"Unverified": "غير موثق",
"Make Primary": "جعل أساسي",
"Remove": "إزالة",
"Add Email Address": "إضافة عنوان بريد إلكتروني",
"Hello,": "مرحباً،",
"Confirm My KAAUH ATS Email": "تأكيد بريدي الإلكتروني في نظام توظيف جامعة نورة",
"Alternatively, copy and paste this link into your browser:": "بدلاً من ذلك، انسخ والصق هذا الرابط في متصفحك:",
"Password Reset Request": "طلب إعادة تعيين كلمة المرور",
"Click Here to Reset Your Password": "اضغط هنا لإعادة تعيين كلمة المرور",
"This link is only valid for a limited time.": "هذا الرابط صالح لفترة محدودة فقط.",
"Thank you,": "شكراً لك،",
"KAAUH ATS Team": "فريق نظام توظيف جامعة نورة",
"Confirm Email Address": "تأكيد عنوان البريد الإلكتروني",
"Account Verification": "التحقق من الحساب",
"Verify your email to secure your account and unlock full features.": "تحقق من بريدك الإلكتروني لتأمين حسابك وإلغاء قفل جميع الميزات.",
"Confirm Your Email Address": "تأكيد عنوان بريدك الإلكتروني",
"Verification Failed": "فشل التحقق",
"The email confirmation link is expired or invalid.": "رابط تأكيد البريد الإلكتروني منتهي الصلاحية أو غير صالح.",
"Keep me signed in": "ابق مسجلاً للدخول",
"Return to Profile": "العودة إلى الملف الشخصي",
"Enter your e-mail address to reset your password.": "أدخل عنوان بريدك الإلكتروني لإعادة تعيين كلمة المرور.",
"Remember your password?": "تتذكر كلمة المرور؟",
"Log In": "تسجيل الدخول",
"Password Reset Sent": "تم إرسال إعادة تعيين كلمة المرور",
"Return to Login": "العودة إلى تسجيل الدخول",
"Please enter your new password below.": "يرجى إدخال كلمة المرور الجديدة أدناه.",
# Common UI Elements
"Save": "حفظ",
"Cancel": "إلغاء",
"Delete": "حذف",
"Edit": "تحرير",
"View": "عرض",
"Create": "إنشاء",
"Update": "تحديث",
"Submit": "إرسال",
"Search": "بحث",
"Filter": "تصفية",
"Sort": "ترتيب",
"Export": "تصدير",
"Import": "استيراد",
"Download": "تنزيل",
"Upload": "رفع",
"Close": "إغلاق",
"Back": "رجوع",
"Next": "التالي",
"Previous": "السابق",
"First": "الأول",
"Last": "الأخير",
"Home": "الرئيسية",
"Dashboard": "لوحة التحكم",
"Profile": "الملف الشخصي",
"Settings": "الإعدادات",
"Help": "المساعدة",
"About": "حول",
"Contact": "اتصال",
"Logout": "تسجيل الخروج",
"Login": "تسجيل الدخول",
"Register": "التسجيل",
"Sign Up": "إنشاء حساب",
"Sign In": "تسجيل الدخول",
# Status Messages
"Active": "نشط",
"Inactive": "غير نشط",
"Pending": "في الانتظار",
"Completed": "مكتمل",
"Failed": "فشل",
"Success": "نجح",
"Error": "خطأ",
"Warning": "تحذير",
"Info": "معلومات",
"Loading": "جاري التحميل",
"Processing": "جاري المعالجة",
"Ready": "جاهز",
"Not Ready": "غير جاهز",
"Available": "متاح",
"Unavailable": "غير متاح",
"Online": "متصل",
"Offline": "غير متصل",
"Connected": "متصل",
"Disconnected": "منقطع",
"Enabled": "مفعل",
"Disabled": "معطل",
"Required": "مطلوب",
"Optional": "اختياري",
"Yes": "نعم",
"No": "لا",
"True": "صحيح",
"False": "خطأ",
"On": "مفعل",
"Off": "معطل",
"Open": "مفتوح",
"Closed": "مغلق",
"Locked": "مقفل",
"Unlocked": "غير مقفل",
# Form Fields
"Name": "الاسم",
"Email": "البريد الإلكتروني",
"Phone": "الهاتف",
"Address": "العنوان",
"City": "المدينة",
"Country": "البلد",
"State": "الولاية",
"Zip Code": "الرمز البريدي",
"Password": "كلمة المرور",
"Confirm Password": "تأكيد كلمة المرور",
"Username": "اسم المستخدم",
"First Name": "الاسم الأول",
"Last Name": "اسم العائلة",
"Full Name": "الاسم الكامل",
"Company": "الشركة",
"Position": "المنصب",
"Department": "القسم",
"Title": "العنوان",
"Description": "الوصف",
"Comments": "التعليقات",
"Notes": "ملاحظات",
"Date": "التاريخ",
"Time": "الوقت",
"Start Date": "تاريخ البدء",
"End Date": "تاريخ الانتهاء",
"Created": "تم الإنشاء",
"Modified": "تم التعديل",
"Updated": "تم التحديث",
# Messages
"Please select an option": "يرجى اختيار خيار",
"This field is required": "هذا الحقل مطلوب",
"Invalid email address": "عنوان بريد إلكتروني غير صالح",
"Password must be at least 8 characters": "يجب أن تكون كلمة المرور 8 أحرف على الأقل",
"Passwords do not match": "كلمات المرور غير متطابقة",
"Email already exists": "البريد الإلكتروني موجود بالفعل",
"User not found": "المستخدم غير موجود",
"Invalid credentials": "بيانات الاعتماد غير صالحة",
"Access denied": "الوصول مرفوض",
"Permission denied": "الإذن مرفوض",
"Operation successful": "تمت العملية بنجاح",
"Operation failed": "فشلت العملية",
"Data saved successfully": "تم حفظ البيانات بنجاح",
"Data deleted successfully": "تم حذف البيانات بنجاح",
"Are you sure you want to delete this item?": "هل أنت متأكد من أنك تريد حذف هذا العنصر؟",
"This action cannot be undone": "لا يمكن التراجع عن هذا الإجراء",
# Navigation
"Menu": "القائمة",
"Home": "الرئيسية",
"Dashboard": "لوحة التحكم",
"Profile": "الملف الشخصي",
"Settings": "الإعدادات",
"Admin": "المسؤول",
"Users": "المستخدمون",
"Reports": "التقارير",
"Analytics": "التحليلات",
"Messages": "الرسائل",
"Notifications": "الإشعارات",
"Tasks": "المهام",
"Calendar": "التقويم",
"Documents": "المستندات",
"Files": "الملفات",
"Media": "الوسائط",
"Help": "المساعدة",
"Support": "الدعم",
"FAQ": "الأسئلة الشائعة",
"Terms": "الشروط",
"Privacy": "الخصوصية",
"Legal": "قانوني",
# Common Actions
"Add": "إضافة",
"Remove": "إزالة",
"Edit": "تحرير",
"Update": "تحديث",
"Delete": "حذف",
"View": "عرض",
"Show": "إظهار",
"Hide": "إخفاء",
"Enable": "تفعيل",
"Disable": "تعطيل",
"Activate": "تنشيط",
"Deactivate": "إلغاء تنشيط",
"Approve": "موافقة",
"Reject": "رفض",
"Accept": "قبول",
"Decline": "رفض",
"Send": "إرسال",
"Receive": "استلام",
"Download": "تنزيل",
"Upload": "رفع",
"Import": "استيراد",
"Export": "تصدير",
"Print": "طباعة",
"Copy": "نسخ",
"Move": "نقل",
"Rename": "إعادة تسمية",
"Share": "مشاركة",
"Subscribe": "اشتراك",
"Unsubscribe": "إلغاء الاشتراك",
"Follow": "متابعة",
"Unfollow": "إلغاء المتابعة",
"Like": "إعجاب",
"Unlike": "إلغاء الإعجاب",
"Comment": "تعليق",
"Rate": "تقييم",
"Review": "مراجعة",
"Bookmark": "إشارة مرجعية",
"Favorite": "مفضل",
"Archive": "أرشفة",
"Restore": "استعادة",
"Backup": "نسخ احتياطي",
"Recover": "استرداد",
"Reset": "إعادة تعيين",
"Refresh": "تحديث",
"Reload": "إعادة تحميل",
"Sync": "مزامنة",
"Connect": "اتصال",
"Disconnect": "قطع الاتصال",
"Link": "ربط",
"Unlink": "فك الربط",
"Attach": "إرفاق",
"Detach": "فصل",
"Merge": "دمج",
"Split": "تقسيم",
"Combine": "دمج",
"Separate": "فصل",
"Group": "تجميع",
"Ungroup": "فك التجميع",
"Sort": "ترتيب",
"Filter": "تصفية",
"Search": "بحث",
"Find": "بحث",
"Replace": "استبدال",
"Clear": "مسح",
"Clean": "تنظيف",
"Empty": "فارغ",
"Full": "ممتلئ",
"All": "الكل",
"None": "لا شيء",
"Some": "بعض",
"Any": "أي",
"Other": "آخر",
"More": "المزيد",
"Less": "أقل",
"New": "جديد",
"Old": "قديم",
"Recent": "الحديث",
"Latest": "الأحدث",
"Previous": "السابق",
"Next": "التالي",
"First": "الأول",
"Last": "الأخير",
"Current": "الحالي",
"Today": "اليوم",
"Yesterday": "أمس",
"Tomorrow": "غداً",
"This week": "هذا الأسبوع",
"Last week": "الأسبوع الماضي",
"Next week": "الأسبوع القادم",
"This month": "هذا الشهر",
"Last month": "الشهر الماضي",
"Next month": "الشهر القادم",
"This year": "هذا العام",
"Last year": "العام الماضي",
"Next year": "العام القادم",
}
def translate_batch_file(batch_file_path):
"""
Translate a single batch file and return the translations
"""
translations = {}
with open(batch_file_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
i = 0
while i < len(lines):
line = lines[i].strip()
if line.startswith('msgid: "'):
# Extract msgid content, removing the extra quote at the beginning
msgid = line[8:-1] # Extract msgid content (skip the extra quote)
# Skip empty msgid or already Arabic text
if not msgid or msgid.strip() == "" or is_arabic_text(msgid):
i += 1
continue
# Find translation
translation = TRANSLATIONS.get(msgid, "")
if translation:
translations[msgid] = translation
print(f"✓ Found translation: '{msgid}' -> '{translation}'")
else:
print(f"✗ No translation found: '{msgid}'")
i += 1
return translations
def is_arabic_text(text):
"""Check if text contains Arabic characters"""
arabic_chars = set('ابتثجحخدذرزسشصضطظعغفقكلمنهويءآأؤإئابةة')
return any(char in arabic_chars for char in text)
def process_all_batches():
"""
Process all batch files and create a comprehensive translation file
"""
all_translations = {}
# Process batches 02-35 (batch 01 already done)
for batch_num in range(2, 36):
batch_file = f"translation_batch_{batch_num:02d}.txt"
if os.path.exists(batch_file):
print(f"\n=== Processing {batch_file} ===")
batch_translations = translate_batch_file(batch_file)
all_translations.update(batch_translations)
print(f"Found {len(batch_translations)} translations in {batch_file}")
else:
print(f"⚠️ {batch_file} not found")
return all_translations
def create_translation_script(all_translations):
"""
Create a script to apply all translations to the main django.po file
"""
script_content = '''#!/usr/bin/env python3
"""
Script to apply all batch translations to the main django.po file
"""
import re
def apply_all_translations():
"""
Apply all translations to the main django.po file
"""
# All translations from batches 02-35
translations = {
'''
for english, arabic in all_translations.items():
script_content += f' "{english}": "{arabic}",\n'
script_content += ''' }
main_po_file = "locale/ar/LC_MESSAGES/django.po"
# Read the main django.po file
with open(main_po_file, 'r', encoding='utf-8') as f:
main_content = f.read()
# Apply translations to main file
updated_content = main_content
applied_count = 0
for english, arabic in translations.items():
# Pattern to find msgid followed by empty msgstr
pattern = rf'(msgid "{re.escape(english)}"\\s*\\nmsgstr) ""'
replacement = rf'\\1 "{arabic}"'
if re.search(pattern, updated_content):
updated_content = re.sub(pattern, replacement, updated_content)
applied_count += 1
print(f"✓ Applied: '{english}' -> '{arabic}'")
else:
print(f"✗ Not found: '{english}'")
# Write updated content back to main file
with open(main_po_file, 'w', encoding='utf-8') as f:
f.write(updated_content)
print(f"\\nApplied {applied_count} translations to {main_po_file}")
return applied_count
def main():
"""Main function to apply all translations"""
print("Applying all batch translations to main django.po file...")
applied_count = apply_all_translations()
if applied_count > 0:
print(f"\\n✅ Successfully applied {applied_count} translations!")
print("Next steps:")
print("1. Run: python manage.py compilemessages")
print("2. Test the translations in the application")
else:
print("\\n❌ No translations were applied.")
if __name__ == "__main__":
main()
'''
with open("apply_all_translations.py", 'w', encoding='utf-8') as f:
f.write(script_content)
print("Created apply_all_translations.py script")
def main():
"""Main function to process all batches"""
print("🚀 Starting comprehensive translation process...")
# Process all batch files
all_translations = process_all_batches()
print(f"\n📊 Summary:")
print(f"Total translations found: {len(all_translations)}")
if all_translations:
# Create the application script
create_translation_script(all_translations)
print(f"\n✅ Translation processing complete!")
print(f"📝 Created apply_all_translations.py with {len(all_translations)} translations")
print(f"\n🎯 Next steps:")
print(f"1. Run: python apply_all_translations.py")
print(f"2. Run: python manage.py compilemessages")
print(f"3. Test the translations in the application")
else:
print("\n❌ No translations found to process.")
if __name__ == "__main__":
main()

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python3
"""
Script to add Arabic translations for batch 01
"""
# Arabic translations for batch 01
translations = {
"": "", # Line 7 - empty string, keep as is
"Website": "الموقع الإلكتروني",
"Admin Notes": "ملاحظات المسؤول",
"Save Assignment": "حفظ التكليف",
"Assignment": "التكليف",
"Expires At": "ينتهي في",
"Access Token": "رمز الوصول",
"Subject": "الموضوع",
"Recipients": "المستلمون",
"Internal staff involved in the recruitment process for this job": "الموظفون الداخليون المشاركون في عملية التوظيف لهذه الوظيفة",
"External Participant": "مشارك خارجي",
"External participants involved in the recruitment process for this job": "المشاركون الخارجيون المشاركون في عملية التوظيف لهذه الوظيفة",
"Reason for canceling the job posting": "سبب إلغاء نشر الوظيفة",
"Name of person who cancelled this job": "اسم الشخص الذي ألغى هذه الوظيفة",
"Hired": "تم التوظيف",
"Author": "المؤلف",
"Endpoint URL for sending candidate data (for outbound sync)": "عنوان URL لنقطة النهاية لإرسال بيانات المرشح (للمزامنة الصادرة)",
"HTTP method for outbound sync requests": "طريقة HTTP لطلبات المزامنة الصادرة",
"HTTP method for connection testing": "طريقة HTTP لاختبار الاتصال",
"Custom Headers": "رؤوس مخصصة",
"JSON object with custom HTTP headers for sync requests": "كائن JSON يحتوي على رؤوس HTTP مخصصة لطلبات المزامنة",
"Supports Outbound Sync": "يدعم المزامنة الصادرة",
"Whether this source supports receiving candidate data from ATS": "ما إذا كان هذا المصدر يدعم استقبال بيانات المرشح من نظام تتبع المتقدمين",
"Expired": "منتهي الصلاحية",
"Maximum candidates agency can submit for this job": "الحد الأقصى للمرشحين الذين يمكن للوكالة تقديمهم لهذه الوظيفة"
}
def update_batch_file():
"""Update the batch file with Arabic translations"""
input_file = "translation_batch_01.txt"
output_file = "translation_batch_01_completed.txt"
with open(input_file, 'r', encoding='utf-8') as f:
content = f.read()
# Replace empty msgstr with translations
for english, arabic in translations.items():
if english: # Skip empty string
# Find the pattern and replace
old_pattern = f'msgid: "{english}"\nmsgstr: ""\n\nArabic Translation: \nmsgstr: ""'
new_pattern = f'msgid: "{english}"\nmsgstr: ""\n\nArabic Translation: \nmsgstr: "{arabic}"'
content = content.replace(old_pattern, new_pattern)
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
print(f"Updated batch file saved as: {output_file}")
print("Arabic translations added for batch 01")
if __name__ == "__main__":
update_batch_file()

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 01 ===
Translations 1-25 of 843
============================================================
Line 7:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1041:
msgid: "Number of candidates submitted so far"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1052:
msgid: "Deadline for agency to submit candidates"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1068:
msgid: "Original deadline before extensions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1078:
msgid: "Agency Job Assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1082:
msgid: "Agency Job Assignments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1086:
msgid: "Deadline date must be in the future"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1090:
msgid: "Maximum candidates must be greater than 0"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1094:
msgid: "Candidates submitted cannot exceed maximum candidates"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1098:
msgid: "Unique Token"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1108:
msgid: "Password for agency access"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1119:
msgid: "When this access link expires"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1124:
msgid: "Last Accessed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1128:
msgid: "Access Count"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1132:
msgid: "Agency Access Link"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1136:
msgid: "Agency Access Links"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1140:
msgid: "Expiration date must be in the future"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1190:
msgid: "In-App"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1194:
msgid: "Pending"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1198:
msgid: "Sent"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1202:
msgid: "Read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1206:
msgid: "Retrying"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1210:
msgid: "Recipient"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1214:
msgid: "Notification Message"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1218:
msgid: "Notification Type"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 01 ===
Translations 1-25 of 867
============================================================
Line 7:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 320:
msgid: "Website"
msgstr: ""
Arabic Translation:
msgstr: "الموقع الإلكتروني"
----------------------------------------
Line 406:
msgid: "Admin Notes"
msgstr: ""
Arabic Translation:
msgstr: "ملاحظات المسؤول"
----------------------------------------
Line 410:
msgid: "Save Assignment"
msgstr: ""
Arabic Translation:
msgstr: "حفظ التكليف"
----------------------------------------
Line 416:
msgid: "Assignment"
msgstr: ""
Arabic Translation:
msgstr: "التكليف"
----------------------------------------
Line 422:
msgid: "Expires At"
msgstr: ""
Arabic Translation:
msgstr: "ينتهي في"
----------------------------------------
Line 449:
msgid: "Access Token"
msgstr: ""
Arabic Translation:
msgstr: "رمز الوصول"
----------------------------------------
Line 474:
msgid: "Subject"
msgstr: ""
Arabic Translation:
msgstr: "الموضوع"
----------------------------------------
Line 485:
msgid: "Recipients"
msgstr: ""
Arabic Translation:
msgstr: "المستلمون"
----------------------------------------
Line 525:
msgid: "Internal staff involved in the recruitment process for this job"
msgstr: ""
Arabic Translation:
msgstr: "الموظفون الداخليون المشاركون في عملية التوظيف لهذه الوظيفة"
----------------------------------------
Line 529:
msgid: "External Participant"
msgstr: ""
Arabic Translation:
msgstr: "مشارك خارجي"
----------------------------------------
Line 533:
msgid: "External participants involved in the recruitment process for this job"
msgstr: ""
Arabic Translation:
msgstr: "المشاركون الخارجيون المشاركون في عملية التوظيف لهذه الوظيفة"
----------------------------------------
Line 541:
msgid: "Reason for canceling the job posting"
msgstr: ""
Arabic Translation:
msgstr: "سبب إلغاء نشر الوظيفة"
----------------------------------------
Line 551:
msgid: "Name of person who cancelled this job"
msgstr: ""
Arabic Translation:
msgstr: "اسم الشخص الذي ألغى هذه الوظيفة"
----------------------------------------
Line 595:
msgid: "Hired"
msgstr: ""
Arabic Translation:
msgstr: "تم التوظيف"
----------------------------------------
Line 782:
msgid: "Author"
msgstr: ""
Arabic Translation:
msgstr: "المؤلف"
----------------------------------------
Line 877:
msgid: "Endpoint URL for sending candidate data (for outbound sync)"
msgstr: ""
Arabic Translation:
msgstr: "عنوان URL لنقطة النهاية لإرسال بيانات المرشح (للمزامنة الصادرة)"
----------------------------------------
Line 887:
msgid: "HTTP method for outbound sync requests"
msgstr: ""
Arabic Translation:
msgstr: "طريقة HTTP لطلبات المزامنة الصادرة"
----------------------------------------
Line 897:
msgid: "HTTP method for connection testing"
msgstr: ""
Arabic Translation:
msgstr: "طريقة HTTP لاختبار الاتصال"
----------------------------------------
Line 901:
msgid: "Custom Headers"
msgstr: ""
Arabic Translation:
msgstr: "رؤوس مخصصة"
----------------------------------------
Line 905:
msgid: "JSON object with custom HTTP headers for sync requests"
msgstr: ""
Arabic Translation:
msgstr: "كائن JSON يحتوي على رؤوس HTTP مخصصة لطلبات المزامنة"
----------------------------------------
Line 909:
msgid: "Supports Outbound Sync"
msgstr: ""
Arabic Translation:
msgstr: "يدعم المزامنة الصادرة"
----------------------------------------
Line 913:
msgid: "Whether this source supports receiving candidate data from ATS"
msgstr: ""
Arabic Translation:
msgstr: "ما إذا كان هذا المصدر يدعم استقبال بيانات المرشح من نظام تتبع المتقدمين"
----------------------------------------
Line 1026:
msgid: "Expired"
msgstr: ""
Arabic Translation:
msgstr: "منتهي الصلاحية"
----------------------------------------
Line 1030:
msgid: "Maximum candidates agency can submit for this job"
msgstr: ""
Arabic Translation:
msgstr: "الحد الأقصى للمرشحين الذين يمكن للوكالة تقديمهم لهذه الوظيفة"
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 02 ===
Translations 26-50 of 843
============================================================
Line 1234:
msgid: "The date and time this notification is scheduled to be sent."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1238:
msgid: "Send Attempts"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1275:
msgid: "Failed to start the job posting process. Please try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1291:
msgid: "Model Changes (CRUD)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1295:
msgid: "You don't have permission to view this page."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1300:
msgid: "Account Inactive"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1307:
msgid: "جامعة الأميرة نورة بنت عبدالرحمن الأكاديمية"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1314:
msgid: "ومستشفى الملك عبدالله بن عبدالعزيز التخصصي"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1321:
msgid: "Princess Nourah bint Abdulrahman University"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1334:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1339:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1367:
msgid: "Manage your personal details and security."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1399:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1405:
msgid: "Primary"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1409:
msgid: "Verified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1413:
msgid: "Unverified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1417:
msgid: "Make Primary"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1428:
msgid: "Remove"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1438:
msgid: "Add Email Address"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1451:
msgid: "Hello,"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1456:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1463:
msgid: "Confirm My KAAUH ATS Email"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1468:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1474:
msgid: "Alternatively, copy and paste this link into your browser:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1479:
msgid: "Password Reset Request"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 03 ===
Translations 51-75 of 843
============================================================
Line 1484:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1491:
msgid: "Click Here to Reset Your Password"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1496:
msgid: "This link is only valid for a limited time."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1501:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1508:
msgid: "Thank you,"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1513:
msgid: "KAAUH ATS Team"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1518:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1524:
msgid: "Confirm Email Address"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1528:
msgid: "Account Verification"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1532:
msgid: "Verify your email to secure your account and unlock full features."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1536:
msgid: "Confirm Your Email Address"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1541:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1553:
msgid: "Verification Failed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1557:
msgid: "The email confirmation link is expired or invalid."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1561:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1603:
msgid: "Keep me signed in"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1649:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1654:
msgid: "Return to Profile"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1658:
msgid: "Enter your e-mail address to reset your password."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1674:
msgid: "Remember your password?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1678:
msgid: "Log In"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1683:
msgid: "Password Reset Sent"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1695:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1701:
msgid: "Return to Login"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1712:
msgid: "Please enter your new password below."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 04 ===
Translations 76-100 of 843
============================================================
Line 1716:
msgid: "You can then log in."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1720:
msgid: "Password Reset Failed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1724:
msgid: "The password reset link is invalid or has expired."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1728:
msgid: "Request New Reset Link"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1744:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1756:
msgid: "Verify Your Email Address"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1768:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1774:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1780:
msgid: "Change or Resend Email"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1789:
msgid: "Django site admin"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1799:
msgid: "KAAUH Agency Portal"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1807:
msgid: "kaauh logo green bg"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1827:
msgid: "Logout"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1941:
msgid: "Ready to Apply?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1945:
msgid: "Review the job details, then apply below."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1950:
msgid: "Apply for this Position"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1969:
msgid: "Not specified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 1992:
msgid: "JOB ID:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2062:
msgid: "Submission Metadata"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2066:
msgid: "Submission ID:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2077:
msgid: "Form:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2099:
msgid: "Field Property"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2133:
msgid: "Field Required"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2141:
msgid: "Yes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2149:
msgid: "No"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 05 ===
Translations 101-125 of 843
============================================================
Line 2153:
msgid: "No response fields were found for this submission."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2157:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2180:
msgid: "Submissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2184:
msgid: "All Submissions Table"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2188:
msgid: "All Submissions for"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2193:
msgid: "Submission ID"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2232:
msgid: "Page"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2238:
msgid: "of"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2250:
msgid: "There are no submissions for this form template yet."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2254:
msgid: "Submissions for"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2460:
msgid: "Careers"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2473:
msgid: "AI Score"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2484:
msgid: "Top Keywords"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2488:
msgid: "Experience"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2492:
msgid: "years"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2496:
msgid: "Recent Role:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2500:
msgid: "Skills"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2504:
msgid: "Soft Skills:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2508:
msgid: "Industry Match:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2513:
msgid: "Recommendation"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2518:
msgid: "Strengths"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2523:
msgid: "Weaknesses"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2528:
msgid: "Criteria Assessment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2541:
msgid: "Met"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2547:
msgid: "Not Met"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 06 ===
Translations 126-150 of 843
============================================================
Line 2558:
msgid: "Screening Rating"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2563:
msgid: "Language Fluency"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2569:
msgid: "Success"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2574:
msgid: "Copied \"%(text)s\" to clipboard!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2584:
msgid: "System Audit Logs"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2588:
msgid: "Viewing Logs"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2592:
msgid: "Displaying"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2596:
msgid: "total records."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2614:
msgid: "User"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2618:
msgid: "Model"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2622:
msgid: "Object PK"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2648:
msgid: "Path"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2652:
msgid: "CREATE"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2656:
msgid: "UPDATE"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2660:
msgid: "DELETE"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2664:
msgid: "Login"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2674:
msgid: "No logs found for this section or the database is empty."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2685:
msgid: "Email will be sent to all selected recipients"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2700:
msgid: "Loading..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2704:
msgid: "Sending email..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2708:
msgid: "Sending..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2727:
msgid: "Meeting Details (will appear after scheduling):"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2743:
msgid: "Click here to join meeting"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2772:
msgid: "Processing..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2776:
msgid: "An unknown error occurred."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 07 ===
Translations 151-175 of 843
============================================================
Line 2780:
msgid: "An error occurred while processing your request."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2788:
msgid: "Bulk Interview Scheduling"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2792:
msgid: "Configure time slots for:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2813:
msgid: "Candidates to Schedule (Hold Ctrl/Cmd to select multiple)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2868:
msgid: "Thank You!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2872:
msgid: "Your application has been submitted successfully"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2876:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2883:
msgid: "Return to Job Listings"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2887:
msgid: "Job ID#"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 2919:
msgid: "Link"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3005:
msgid: "Hashtags (For Promotion/Search on Linkedin)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3065:
msgid: "Search by name, email, phone, or stage..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3069:
msgid: "Filter Results"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3074:
msgid: "Clear Filters"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3167:
msgid: "JOB ID: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3171:
msgid: "Share Public Link"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3177:
msgid: "Copied!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3215:
msgid: "Tracking"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3249:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3269:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3330:
msgid: "Candidate Categories & Scores"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3334:
msgid: "Key Performance Indicators"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3338:
msgid: "Avg. AI Score"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3343:
msgid: "High Potential"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3353:
msgid: "Avg. Exam Review"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 08 ===
Translations 176-200 of 843
============================================================
Line 3357:
msgid: "Vacancy Fill Rate"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3373:
msgid: "Status form not available. Please check your view."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3380:
msgid: "Save Changes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3396:
msgid: "Search by Title or Department"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3425:
msgid: "Archived"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3440:
msgid: "Clear"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3450:
msgid: "Max Apps"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3481:
msgid: "All"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3486:
msgid: "Screened"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3496:
msgid: "Form"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3500:
msgid: "N/A"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3520:
msgid: "Create your first job posting to get started or adjust your filters."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3554:
msgid: "Search by Topic"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3596:
msgid: "Create your first meeting or adjust your filters."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3641:
msgid: "minutes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3655:
msgid: "Assigned Participants"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3665:
msgid: "External Participants"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3669:
msgid: "System User"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3673:
msgid: "Comments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3696:
msgid: "No comments yet. Be the first to comment!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3712:
msgid: "You must be logged in to add a comment."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3730:
msgid: "You are updating the existing meeting schedule."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3748:
msgid: "Candidate has upcoming interviews. Updating existing schedule."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3752:
msgid: "e.g., Technical Screening, HR Interview"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3762:
msgid: "Save"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 09 ===
Translations 201-225 of 843
============================================================
Line 3858:
msgid: "This participant is not currently assigned to any job."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3862:
msgid: "Metadata"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3873:
msgid: "at"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3877:
msgid: "Total Assigned Jobs"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3896:
msgid: "This action cannot be undone."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3913:
msgid: "Search by Name or Email"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3917:
msgid: "Filter by Assigned Job"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3935:
msgid: "Create your first participant record or adjust your filters."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3952:
msgid: "Secure access link for agency candidate submissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3984:
msgid: "Access Credentials"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 3996:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4002:
msgid: "Usage Statistics"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4006:
msgid: "Total Accesses"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4010:
msgid: "Never"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4014:
msgid: "View Assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4032:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4045:
msgid: "Generate a secure access link for agency to submit candidates"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4057:
msgid: "Select the agency job assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4061:
msgid: "When will this access link expire?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4065:
msgid: "Max Submissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4069:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4074:
msgid: "Whether this access link is currently active"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4078:
msgid: "Notes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4088:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4094:
msgid: "Assignment Details and Management"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 10 ===
Translations 226-250 of 843
============================================================
Line 4099:
msgid: "Edit Assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4166:
msgid: "Submission Progress"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4194:
msgid: "Recent Messages"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4201:
msgid: "From"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4207:
msgid: "New"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4218:
msgid: "Extend Assignment Deadline"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4234:
msgid: "Token copied to clipboard!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4238:
msgid: "Assign a job to an external hiring agency"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4242:
msgid: "Maximum number of candidates the agency can submit"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4246:
msgid: "Date and time when submission period ends"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4263:
msgid: "Total Assignments:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4267:
msgid: "New Assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4271:
msgid: "Search by agency or job title..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4281:
msgid: "Assignments pagination"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4291:
msgid: "Create your first agency assignment to get started."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4295:
msgid: "Create Assignment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4306:
msgid: "You are about to delete a hiring agency. This action cannot be undone."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4316:
msgid: "Warning: This action cannot be undone!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4320:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4326:
msgid: "Agency to be Deleted"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4336:
msgid: "candidate(s) are associated with this agency."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4340:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4346:
msgid: "What will happen when you delete this agency?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4350:
msgid: "The agency profile and all its information will be permanently deleted"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4360:
msgid: "Associated candidates will lose their agency reference"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 11 ===
Translations 251-275 of 843
============================================================
Line 4364:
msgid: "Historical data linking candidates to this agency will be lost"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4368:
msgid: "This action cannot be undone under any circumstances"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4372:
msgid: "Type the agency name to confirm deletion:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4376:
msgid: "This is required to prevent accidental deletions."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4380:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4386:
msgid: "Delete Agency Permanently"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4404:
msgid: "Hiring Agency Details and Candidate Management"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4408:
msgid: "Assign job"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4467:
msgid: "This agency hasn't submitted any candidates yet."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4477:
msgid: "Total"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4487:
msgid: "Visit Website"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4509:
msgid: "Update the hiring agency information below."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4513:
msgid: "Fill in the details to add a new hiring agency."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4517:
msgid: "Please correct the errors below:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4531:
msgid: "Quick Tips"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4535:
msgid: "Provide accurate contact information for better communication"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4539:
msgid: "Include a valid website URL if available"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4543:
msgid: "Add a detailed description to help identify the agency"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4547:
msgid: "All fields marked with * are required"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4575:
msgid: "Search by name, contact person, email, or country..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4579:
msgid: "Agency pagination"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4589:
msgid: "No hiring agencies have been added yet."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4593:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4644:
msgid: "Submit candidates using the form above to get started."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4662:
msgid: "Assignment Info"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 12 ===
Translations 276-300 of 843
============================================================
Line 4666:
msgid: "Days Remaining"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4671:
msgid: "days"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4675:
msgid: "Submission Rate"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4679:
msgid: "Send Message to Admin"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4683:
msgid: "Priority"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4687:
msgid: "Low"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4691:
msgid: "Medium"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4695:
msgid: "High"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4718:
msgid: "Error loading candidate data. Please try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4723:
msgid: "Error updating candidate. Please try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4728:
msgid: "Error removing candidate. Please try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4739:
msgid: "Welcome back"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4743:
msgid: "Total Assignments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4747:
msgid: "Active Assignments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4764:
msgid: "Your Job Assignments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4768:
msgid: "assignments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4772:
msgid: "days left"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4776:
msgid: "days overdue"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4780:
msgid: "Submissions Closed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4784:
msgid: "No Job Assignments Found"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4788:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4794:
msgid: "Agency Portal Login"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4804:
msgid: "Enter the access token provided by the hiring organization"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4808:
msgid: "Enter the password for this access token"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4812:
msgid: "Access Portal"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 13 ===
Translations 301-325 of 843
============================================================
Line 4816:
msgid: "Need Help?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4826:
msgid: "Reach out to your hiring contact"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4836:
msgid: "View user guides and tutorials"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4840:
msgid: "Security Notice"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4844:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4850:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4856:
msgid: "Please enter your access token."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4860:
msgid: "Please enter your password."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4876:
msgid: "Days Remaining:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4927:
msgid: "Click to upload or drag and drop"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4931:
msgid: "Accepted formats: PDF, DOC, DOCX (Maximum 5MB)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4935:
msgid: "Remove File"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4939:
msgid: "Additional Notes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4943:
msgid: "Notes (Optional)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4947:
msgid: "Any additional information about the candidate"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4951:
msgid: "Submitted candidates will be reviewed by the hiring team."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4961:
msgid: "This assignment has expired. Submissions are no longer accepted."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4965:
msgid: "Maximum candidate limit reached for this assignment."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4969:
msgid: "This assignment is not currently active."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4973:
msgid: "Submitting candidate..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4977:
msgid: "Please wait while we process your submission."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4981:
msgid: "Please upload a PDF, DOC, or DOCX file."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 4985:
msgid: "File size must be less than 5MB."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5001:
msgid: "Error submitting candidate. Please try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5005:
msgid: "Network error. Please check your connection and try again."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 14 ===
Translations 326-350 of 843
============================================================
Line 5041:
msgid: "Journey Timeline"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5087:
msgid: "AI Analysis Report"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5091:
msgid: "Match Score"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5095:
msgid: "Category"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5099:
msgid: "Job Fit Narrative"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5109:
msgid: "Years of Experience:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5113:
msgid: "Most Recent Job Title:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5117:
msgid: "Experience Industry Match:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5121:
msgid: "Soft Skills Score:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5131:
msgid: "Minimum Requirements Met:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5135:
msgid: "Screening Stage Rating:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5139:
msgid: "Resume is being parsed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5143:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5175:
msgid: "View Resume AI Overview"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5179:
msgid: "Time to Hire: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5183:
msgid: "Unable to Parse Resume , click to retry"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5193:
msgid: "Candidates in Exam Stage:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5197:
msgid: "Export exam candidates to CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5205:
msgid: "Export CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5222:
msgid: "Screening Stage"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5232:
msgid: "No candidates are currently in the Exam stage for this job."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5236:
msgid: "Candidate Details & Exam Update"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5253:
msgid: "Successfully Hired:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5257:
msgid: "Sync hired candidates to external sources"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5268:
msgid: "Export hired candidates to CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 15 ===
Translations 351-375 of 843
============================================================
Line 5272:
msgid: "Congratulations!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5276:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5303:
msgid: "Loading content..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5313:
msgid: "Syncing candidates..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5317:
msgid: "Syncing hired candidates..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5321:
msgid: "Please wait while we sync candidates to external sources."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5325:
msgid: "Syncing..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5329:
msgid: "An unexpected error occurred during sync."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5345:
msgid: "Successful:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5387:
msgid: "Sync task failed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5391:
msgid: "Failed to check sync status"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5395:
msgid: "Sync timed out after 5 minutes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5399:
msgid: "Sync in progress..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5415:
msgid: "Candidates in Interview Stage:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5419:
msgid: "Export interview candidates to CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5465:
msgid: "Minutes"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5469:
msgid: "No candidates are currently in the Interview stage for this job."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5475:
msgid: "Candidate Details / Bulk Action Form"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5479:
msgid: "Manage all participants"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5484:
msgid: "Users"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5488:
msgid: "Loading email form..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5500:
msgid: "Filter by Job"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5504:
msgid: "Major"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5538:
msgid: "Candidates in Offer Stage:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5542:
msgid: "Export offer candidates to CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 16 ===
Translations 376-400 of 843
============================================================
Line 5546:
msgid: "To Hired"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5556:
msgid: "No candidates are currently in the Offer stage for this job."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5566:
msgid: "Job:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5570:
msgid: "Export screening candidates to CSV"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5574:
msgid: "AI Scoring & Top Candidate Filter"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5578:
msgid: "Min AI Score"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5582:
msgid: "Min Years Exp"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5586:
msgid: "Any Rating"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5614:
msgid: "Is Qualified?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5618:
msgid: "Professional Category"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5622:
msgid: "Top 3 Skills"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5626:
msgid: "AI scoring.."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5630:
msgid: "No candidates match the current stage and filter criteria."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5666:
msgid: "Recruitment Analytics"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5670:
msgid: "Data Scope: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5674:
msgid: "Data Scope: All Jobs"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5684:
msgid: "All Jobs (Default View)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5688:
msgid: "Daily Candidate Applications Trend"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5698:
msgid: "Pipeline Funnel: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5702:
msgid: "Total Pipeline Funnel (All Jobs)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5706:
msgid: "Time-to-Hire Target Check"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5716:
msgid: "Top 5 Most Applied Jobs"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5738:
msgid: "Daily Applications (Last 30 Days)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5754:
msgid: "Mark All as Read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5758:
msgid: "What this will do"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 17 ===
Translations 401-425 of 843
============================================================
Line 5781:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5787:
msgid: "All caught up!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5791:
msgid: "You don't have any unread notifications to mark as read."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5795:
msgid: "Yes, Mark All as Read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5812:
msgid: "Notification Preview"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5829:
msgid: "View notification details and manage your preferences"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5834:
msgid: "Mark as Read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5839:
msgid: "Mark as Unread"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5867:
msgid: "Delivery Attempts"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5919:
msgid: "Mark All Read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5930:
msgid: "Unread"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5934:
msgid: "All Types"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5938:
msgid: "Filter"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5942:
msgid: "Total Notifications"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5946:
msgid: "Email Notifications"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5956:
msgid: "Mark as read"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5960:
msgid: "Mark as unread"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5970:
msgid: "Notifications pagination"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5980:
msgid: "Try adjusting your filters to see more notifications."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5990:
msgid: "Name / Contact"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 5994:
msgid: "View Details and Score Breakdown"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6004:
msgid: "Move to Next Stage"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6008:
msgid: "Move to"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6024:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6031:
msgid: "Days"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 18 ===
Translations 426-450 of 843
============================================================
Line 6035:
msgid: "Target:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6039:
msgid: "Max Scale:"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6049:
msgid: "Home"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6065:
msgid: "All Active & Drafted Positions (Global)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6073:
msgid: "Currently Open Requisitions (Scoped)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6077:
msgid: "Total Profiles in Current Scope"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6081:
msgid: "Total Slots to be Filled (Scoped)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6091:
msgid: "Total Recruiters/Interviewers (Global)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6101:
msgid: "Total Job Posts Sent to LinkedIn (Global)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6105:
msgid: "New Apps (7 Days)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6109:
msgid: "Incoming applications last week"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6113:
msgid: "Avg. Apps per Job"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6117:
msgid: "Average Applications per Job (Scoped)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6127:
msgid: "Avg. Days (Application to Hired)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6131:
msgid: "Avg. Match Score"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6135:
msgid: "Average AI Score (Current Scope)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6140:
msgid: "Score ≥ 75%% Profiles"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6150:
msgid: "Scheduled Interviews (Current Week)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6154:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6166:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6172:
msgid: "Please select a date and time for the interview."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6193:
msgid: "Search by Title or Creator"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6253:
msgid: "Admin Settings Dashboard"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6257:
msgid: "Staff User List"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6273:
msgid: "Last Login"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 19 ===
Translations 451-475 of 843
============================================================
Line 6277:
msgid: "Deactivate User"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6318:
msgid: "Manage email addresses"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6322:
msgid: "Security"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6338:
msgid: "Username"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6342:
msgid: "Date Joined"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6347:
msgid: "{editor}: Editing failed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6352:
msgid: "{editor}: Editing failed: {e}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6358:
msgid: "{text} {deprecated_message}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6381:
msgid: "DeprecationWarning: The command {name!r} is deprecated.{extra_message}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6386:
msgid: "Aborted!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6391:
msgid: "Commands"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6395:
msgid: "Missing command."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6399:
msgid: "No such command {name!r}."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6403:
msgid: "Value must be an iterable."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6418:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6425:
msgid: "env var: {var}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6432:
msgid: "default: {default}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6437:
msgid: "(dynamic)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6442:
msgid: "%(prog)s, version %(version)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6446:
msgid: "Show the version and exit."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6450:
msgid: "Show this message and exit."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6462:
msgid: "Try '{command} {option}' for help."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6467:
msgid: "Invalid value: {message}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6472:
msgid: "Invalid value for {param_hint}: {message}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6476:
msgid: "Missing argument"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 20 ===
Translations 476-500 of 843
============================================================
Line 6486:
msgid: "Missing parameter"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6491:
msgid: "Missing {param_type}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6496:
msgid: "Missing parameter: {param_name}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6501:
msgid: "No such option: {name}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6516:
msgid: "unknown error"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6520:
msgid: "Could not open file {filename!r}: {message}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6530:
msgid: "Argument {name!r} takes {nargs} values."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6534:
msgid: "Option {name!r} does not take a value."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6548:
msgid: "Shell completion is not supported for Bash versions older than 4.4."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6552:
msgid: "Couldn't detect Bash version, shell completion is not supported."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6562:
msgid: "Error: The value you entered was invalid."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6572:
msgid: "Error: The two entered values do not match."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6576:
msgid: "Error: invalid input"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6580:
msgid: "Press any key to continue..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6585:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6611:
msgid: "{value!r} is not a valid {number_type}."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6616:
msgid: "{value} is not in the range {range}."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6620:
msgid: "{value!r} is not a valid boolean. Recognized values: {states}"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6624:
msgid: "{value!r} is not a valid UUID."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6634:
msgid: "directory"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6638:
msgid: "path"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6642:
msgid: "{name} {filename!r} does not exist."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6646:
msgid: "{name} {filename!r} is a file."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6650:
msgid: "{name} {filename!r} is a directory."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6654:
msgid: "{name} {filename!r} is not readable."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 21 ===
Translations 501-525 of 843
============================================================
Line 6658:
msgid: "{name} {filename!r} is not writable."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6662:
msgid: "{name} {filename!r} is not executable."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6677:
msgid: "RoW"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6682:
msgid: "GLO"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6686:
msgid: "RoE"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6696:
msgid: "Site Maps"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6700:
msgid: "Static Files"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6712:
msgid: "…"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6716:
msgid: "That page number is not an integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6720:
msgid: "That page number is less than 1"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6724:
msgid: "That page contains no results"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6728:
msgid: "Enter a valid value."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6739:
msgid: "Enter a valid URL."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6743:
msgid: "Enter a valid integer."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6747:
msgid: "Enter a valid email address."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6752:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6757:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6767:
msgid: "Enter a valid %(protocol)s address."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6771:
msgid: "IPv4"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6776:
msgid: "IPv6"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6780:
msgid: "IPv4 or IPv6"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6784:
msgid: "Enter only digits separated by commas."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6789:
msgid: "Ensure this value is %(limit_value)s (it is %(show_value)s)."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6794:
msgid: "Ensure this value is less than or equal to %(limit_value)s."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6799:
msgid: "Ensure this value is greater than or equal to %(limit_value)s."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 22 ===
Translations 526-550 of 843
============================================================
Line 6804:
msgid: "Ensure this value is a multiple of step size %(limit_value)s."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6809:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6889:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6895:
msgid: "Null characters are not allowed."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6901:
msgid: "and"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6906:
msgid: "%(model_name)s with this %(field_labels)s already exists."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6911:
msgid: "Constraint “%(name)s” is violated."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6916:
msgid: "Value %(value)r is not a valid choice."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6920:
msgid: "This field cannot be null."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6924:
msgid: "This field cannot be blank."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6929:
msgid: "%(model_name)s with this %(field_label)s already exists."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6936:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6942:
msgid: "Field of type: %(field_type)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6947:
msgid: "“%(value)s” value must be either True or False."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6952:
msgid: "“%(value)s” value must be either True, False, or None."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6956:
msgid: "Boolean (Either True or False)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6961:
msgid: "String (up to %(max_length)s)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6965:
msgid: "String (unlimited)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6976:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6984:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6990:
msgid: "Date (without time)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 6995:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7002:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7008:
msgid: "Date (with time)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7013:
msgid: "“%(value)s” value must be a decimal number."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 23 ===
Translations 551-575 of 843
============================================================
Line 7017:
msgid: "Decimal number"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7022:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7041:
msgid: "“%(value)s” value must be a float."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7052:
msgid: "“%(value)s” value must be an integer."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7062:
msgid: "Big (8 byte) integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7066:
msgid: "Small integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7084:
msgid: "“%(value)s” value must be either None, True or False."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7088:
msgid: "Boolean (Either True, False or None)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7092:
msgid: "Positive big integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7096:
msgid: "Positive integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7100:
msgid: "Positive small integer"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7105:
msgid: "Slug (up to %(max_length)s)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7109:
msgid: "Text"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7114:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7121:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7137:
msgid: "URL"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7141:
msgid: "Raw binary data"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7146:
msgid: "“%(value)s” is not a valid UUID."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7150:
msgid: "Universally unique identifier"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7154:
msgid: "Image"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7158:
msgid: "A JSON object"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7162:
msgid: "Value must be valid JSON."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7167:
msgid: "%(model)s instance with %(field)s %(value)r is not a valid choice."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7171:
msgid: "Foreign Key (type determined by related field)"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7175:
msgid: "One-to-one relationship"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 24 ===
Translations 576-600 of 843
============================================================
Line 7180:
msgid: "%(from)s-%(to)s relationship"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7185:
msgid: "%(from)s-%(to)s relationships"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7189:
msgid: "Many-to-many relationship"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7195:
msgid: ":?.!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7199:
msgid: "This field is required."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7223:
msgid: "Enter a valid date/time."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7234:
msgid: "The number of days must be between {min_days} and {max_days}."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7238:
msgid: "No file was submitted. Check the encoding type on the form."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7242:
msgid: "No file was submitted."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7246:
msgid: "The submitted file is empty."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7262:
msgid: "Please either submit a file or check the clear checkbox, not both."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7266:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7275:
msgid: "Select a valid choice. %(value)s is not one of the available choices."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7293:
msgid: "Enter a valid UUID."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7297:
msgid: "Enter a valid JSON."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7302:
msgid: ":"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7307:
msgid: "(Hidden field %(name)s) %(error)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7312:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7341:
msgid: "Order"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7346:
msgid: "Please correct the duplicate data for %(field)s."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7351:
msgid: "Please correct the duplicate data for %(field)s, which must be unique."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7356:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7362:
msgid: "Please correct the duplicate values below."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7366:
msgid: "The inline value did not match the parent instance."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7370:
msgid: "Select a valid choice. That choice is not one of the available choices."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 25 ===
Translations 601-625 of 843
============================================================
Line 7375:
msgid: "“%(pk)s” is not a valid value."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7380:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7386:
msgid: "Currently"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7400:
msgid: "Unknown"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7405:
msgid: "yes,no,maybe"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7422:
msgid: "%s KB"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7427:
msgid: "%s MB"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7432:
msgid: "%s GB"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7437:
msgid: "%s TB"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7442:
msgid: "%s PB"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7446:
msgid: "p.m."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7450:
msgid: "a.m."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7454:
msgid: "PM"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7458:
msgid: "AM"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7462:
msgid: "midnight"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7466:
msgid: "noon"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7470:
msgid: "Monday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7474:
msgid: "Tuesday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7478:
msgid: "Wednesday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7482:
msgid: "Thursday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7486:
msgid: "Friday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7490:
msgid: "Saturday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7494:
msgid: "Sunday"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7498:
msgid: "Mon"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7502:
msgid: "Tue"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 26 ===
Translations 626-650 of 843
============================================================
Line 7506:
msgid: "Wed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7510:
msgid: "Thu"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7514:
msgid: "Fri"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7524:
msgid: "Sun"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7528:
msgid: "January"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7532:
msgid: "February"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7542:
msgid: "April"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7546:
msgid: "May"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7550:
msgid: "June"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7554:
msgid: "July"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7558:
msgid: "August"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7562:
msgid: "September"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7566:
msgid: "October"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7570:
msgid: "November"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7574:
msgid: "December"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7578:
msgid: "jan"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7582:
msgid: "feb"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7592:
msgid: "apr"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7602:
msgid: "jun"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7606:
msgid: "jul"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7616:
msgid: "sep"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7620:
msgid: "oct"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7624:
msgid: "nov"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7628:
msgid: "dec"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7633:
msgid: "Jan."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 27 ===
Translations 651-675 of 843
============================================================
Line 7638:
msgid: "Feb."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7650:
msgid: "April"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7655:
msgid: "May"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7660:
msgid: "June"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7665:
msgid: "July"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7670:
msgid: "Aug."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7675:
msgid: "Sept."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7680:
msgid: "Oct."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7685:
msgid: "Nov."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7690:
msgid: "Dec."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7695:
msgid: "January"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7700:
msgid: "February"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7712:
msgid: "April"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7717:
msgid: "May"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7722:
msgid: "June"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7727:
msgid: "July"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7732:
msgid: "August"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7737:
msgid: "September"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7742:
msgid: "October"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7747:
msgid: "November"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7752:
msgid: "December"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7756:
msgid: "This is not a valid IPv6 address."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7762:
msgid: "%(truncated_text)s…"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7774:
msgid: ", "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7844:
msgid: "Forbidden"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 28 ===
Translations 676-700 of 843
============================================================
Line 7848:
msgid: "CSRF verification failed. Request aborted."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7860:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7876:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7883:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7889:
msgid: "More information is available with DEBUG=True."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7893:
msgid: "No year specified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7899:
msgid: "Date out of range"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7903:
msgid: "No month specified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7907:
msgid: "No day specified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7911:
msgid: "No week specified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7917:
msgid: "No %(verbose_name_plural)s available"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7922:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7929:
msgid: "Invalid date string “%(datestr)s” given format “%(format)s”"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7934:
msgid: "No %(verbose_name)s found matching the query"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7938:
msgid: "Page is not “last”, nor can it be converted to an int."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7943:
msgid: "Invalid page (%(page_number)s): %(message)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7948:
msgid: "Empty list and “%(class_name)s.allow_empty” is False."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7952:
msgid: "Directory indexes are not allowed here."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7957:
msgid: "“%(path)s” does not exist"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7964:
msgid: "Index of %(directory)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7969:
msgid: "The install worked successfully! Congratulations!"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7974:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7989:
msgid: "Django Documentation"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7993:
msgid: "Topics, references, &amp; how-tos"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 7997:
msgid: "Tutorial: A Polling App"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 29 ===
Translations 701-725 of 843
============================================================
Line 8001:
msgid: "Get started with Django"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8005:
msgid: "Django Community"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8009:
msgid: "Connect, get help, or contribute"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8013:
msgid: "You do not have permission to upload files."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8017:
msgid: "You must be logged in to upload files."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8022:
msgid: "File should be at most %(max_size)s MB."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8026:
msgid: "Invalid form data"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8030:
msgid: "Check the correct settings.CKEDITOR_5_CONFIGS "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8034:
msgid: "Only POST method is allowed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8038:
msgid: "Attachment module is disabled"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8042:
msgid: "Only authenticated users are allowed"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8046:
msgid: "No files were requested"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8050:
msgid: "File size exceeds the limit allowed and cannot be saved"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8054:
msgid: "Failed to save attachment"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8059:
msgid: "Attempting to connect to qpid with SASL mechanism %s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8064:
msgid: "Connected to qpid with SASL mechanism %s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8069:
msgid: "Unable to connect to qpid with SASL mechanism %s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8074:
msgid: "required"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8079:
msgid: "Arguments"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8089:
msgid: "[default: {}]"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8093:
msgid: "[env var: {}]"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8097:
msgid: "[required]"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8101:
msgid: "Aborted."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8106:
msgid: "Try [blue]'{command_path} {help_option}'[/] for help."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8123:
msgid: "Collapse"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 30 ===
Translations 726-750 of 843
============================================================
Line 8128:
msgid: "Value"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8132:
msgid: "Default"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8137:
msgid: "Code"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8141:
msgid: "Modified"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8145:
msgid: "Reset to default"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8166:
msgid: " By %(filter_title)s "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8171:
msgid: "To"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8175:
msgid: "Date from"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8179:
msgid: "Date to"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8195:
msgid: "Paragraph"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8199:
msgid: "Underlined"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8203:
msgid: "Bold"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8207:
msgid: "Italic"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8211:
msgid: "Strike"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8218:
msgid: "Heading"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8222:
msgid: "Quote"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8226:
msgid: "Unordered list"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8230:
msgid: "Ordered list"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8234:
msgid: "Indent increase"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8238:
msgid: "Indent decrease"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8242:
msgid: "Undo"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8246:
msgid: "Redo"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8256:
msgid: "Unlink"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8260:
msgid: "Object permissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8267:
msgid: "Object"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 31 ===
Translations 751-775 of 843
============================================================
Line 8272:
msgid: "Group"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8276:
msgid: "Group permissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8286:
msgid: "User permissions"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8297:
msgid: "Export"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8301:
msgid: "Import"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8322:
msgid: "This exporter will export the following fields"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8326:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8344:
msgid: "Skipped"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8348:
msgid: "Some rows failed to validate"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8352:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8359:
msgid: "Row"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8370:
msgid: "Non field specific"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8374:
msgid: "This exporter will export the following fields: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8378:
msgid: "This importer will import the following fields: "
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8385:
msgid: "%(class_name)s %(instance)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8390:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8396:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8415:
msgid: "This object doesn't have a change history."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8419:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8424:
msgid: "Press the 'Change History' button below to edit the history."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8431:
msgid: "Date/time"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8449:
msgid: "None"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8453:
msgid: "Revert"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8469:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8483:
msgid: "Run the selected action"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 32 ===
Translations 776-800 of 843
============================================================
Line 8487:
msgid: "Run"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8491:
msgid: "Click here to select the objects across all pages"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8496:
msgid: "Select all %(total_count)s %(module_name)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8500:
msgid: "Clear selection"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8506:
msgid: "Models in the %(name)s application"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8512:
msgid: "You dont have permission to view or edit anything."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8516:
msgid: "After you've created a user, youll be able to edit more user options."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8521:
msgid: "Enter a new password for the user <strong>%(username)s</strong>."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8533:
msgid: "History"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8545:
msgid: "Filters"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8549:
msgid: "Select all rows"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8559:
msgid: "Remove from sorting"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8564:
msgid: "Sorting priority: %(priority_number)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8569:
msgid: "Expand row"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8574:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8582:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8589:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8596:
msgid: "Objects"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8601:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8609:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8616:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8626:
msgid: "Welcome back to"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8631:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8637:
msgid: "Log in"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8641:
msgid: "Forgotten your password or username?"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,204 +0,0 @@
=== TRANSLATION BATCH 33 ===
Translations 801-825 of 843
============================================================
Line 8645:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8653:
msgid: "Show all"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8658:
msgid: "Type to search"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8662:
msgid: "Save and continue editing"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8666:
msgid: "Save and view"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8670:
msgid: "Save and add another"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8674:
msgid: "Save as new"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8678:
msgid: "You have been successfully logged out from the administration"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8682:
msgid: "Thanks for spending some quality time with the web site today."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8686:
msgid: "Log in again"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8690:
msgid: "Your password was changed."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8694:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8721:
msgid: "Add %(name)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8731:
msgid: "Add"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8735:
msgid: "True"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8739:
msgid: "False"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8743:
msgid: "Hide counts"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8753:
msgid: "Clear all filters"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8757:
msgid: "Recent searches"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8761:
msgid: "No recent searches"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8771:
msgid: "Loading more results..."
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8792:
msgid: "No, take me back"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8796:
msgid: "Yes, Im sure"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8800:
msgid: "Record picture"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8816:
msgid: ""
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,148 +0,0 @@
=== TRANSLATION BATCH 34 ===
Translations 826-843 of 843
============================================================
Line 8821:
msgid: "Reset filters"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8826:
msgid: "Go back"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8836:
msgid: "Unknown content"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8870:
msgid: "%(full_result_count)s total"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8888:
msgid: "Django administration"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8892:
msgid: "General"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8896:
msgid: "Dark"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8900:
msgid: "Light"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8904:
msgid: "System"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8908:
msgid: "Return to site"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8919:
msgid: "Choose file to upload"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8924:
msgid: "Change selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8929:
msgid: "Add another %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8934:
msgid: "View selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8939:
msgid: "Delete selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8943:
msgid: "Add row"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8947:
msgid: "Welcome"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8951:
msgid: "Select all objects on this page for an action"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

View File

@ -1,140 +0,0 @@
=== TRANSLATION BATCH 35 ===
Translations 851-867 of 867
============================================================
Line 8826:
msgid: "Go back"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8836:
msgid: "Unknown content"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8870:
msgid: "%(full_result_count)s total"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8888:
msgid: "Django administration"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8892:
msgid: "General"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8896:
msgid: "Dark"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8900:
msgid: "Light"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8904:
msgid: "System"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8908:
msgid: "Return to site"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8919:
msgid: "Choose file to upload"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8924:
msgid: "Change selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8929:
msgid: "Add another %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8934:
msgid: "View selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8939:
msgid: "Delete selected %(model)s"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8943:
msgid: "Add row"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8947:
msgid: "Welcome"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------
Line 8951:
msgid: "Select all objects on this page for an action"
msgstr: ""
Arabic Translation:
msgstr: ""
----------------------------------------

1
txt
View File

@ -1 +0,0 @@
Please Indicate the area that you are interested in the CV (ICU, OR, Medical Ward, Surgical Ward, Women`s Health). Bachelors degree in Nursing with minimum GPA (4 out of 5). SCFHS Nurse license classified as (Specialist). Country Specialist Nurse license. BLS Certified (ACLS, PALS, NALS dependent on unit requirement). Home Country equivalent Board Certifications must be maintained when appropriate. 2 year or more experience. Experience in same area. Key Accountabilities & Responsibilities Clinical: Is accountable for utilizing the nursing process, appropriate tools, evidence based knowledge, empathy and compassion in the assessment, planning, implementation and evaluation of nursing care for individual patients, while considering the individuals holistic needs and in accordance with scope of practice, hospital policy and procedure. Demonstrates the knowledge and skills, including critical thinking, necessary to implement the nursing plan of care, nursing interventions and procedures, as necessary for the care of the individual patient taking into consideration the patients condition, culture and medical plan of care. Advocates for patient by guiding best practice and standards of care within multidisciplinary team. Reports any deterioration in patients condition to physician, escalating via chain of command as necessary. Works towards reducing length of stay by advocating commencing discharge planning on admission. Is an advocate for patient safety, minimizes patient risk by ensuring a safe environment and conditions. Follows all policies and procedures, reporting observed or perceived risks in a timely fashion Suggests opportunities for improvement in care and in care environment. Uses transcultural awareness during all interactions with patients, families and colleagues. Works effectively with multidisciplinary team towards safe, effective and efficient patient outcomes. Maintains patient confidentiality according to policy. Ensures appropriate delegation of any duties when necessary. Takes appropriate action in emergencies. Documents all care accurately, completely and in a timely fashion. Demonstrates the computer skills necessary for carrying out duties. Education: Educates and informs patients and families on the care and management of condition, to adapt a problem-solving approach to managing and reporting complications. Provides health promotion and disease prevention advice. Participates in own and others education, training and professional development as needed. Shares appropriate, relevant and up to date information and knowledge with colleagues. Leadership: Utilizes leadership skills as nurse in charge of shift. Communicates effectively to ensure patient safety. Demonstrates knowledge of and follows all hospital related policies and procedures Reports potential or observed safety hazards immediately to supervisor, removes hazard or provides solution when possible. Reports any work-related risks such as equipment failures or resource insufficiencies to supervisor immediately. Uses communication and conflict negotiation skills to prevent and resolve complaints, reports through the chain of command as per hospital policy and procedure. Contributes to improving quality outcomes including patient and staff satisfaction indicators. Utilizes multidisciplinary team to ensure optimal patient experience. Exercises care in utilizing resources to maintain a cost efficient service. Actively participates in unit based meetings and councils. Supports a just culture, speaks up and promotes civility in the workplace. Research: Identifies opportunities for improvement that are evidence based. Maintains and shares up to date knowledge related to evidence based practice. Is involved in relevant projects related to practice, improvement and safety. Is actively involved in unit journal club. Hospital-wide: Respects patients and their families and promotes a patient-centered care culture. Participates and supports quality improvement and patient safety activities as an individual or as part of multidisciplinary teams. Performs other job-related duties as assigned.