From 2dd90e4d38db95337eee2797ab1474ede8c5ddf1 Mon Sep 17 00:00:00 2001 From: ismail Date: Tue, 21 Oct 2025 14:26:29 +0300 Subject: [PATCH] fix error --- .../__pycache__/settings.cpython-313.pyc | Bin 8370 -> 8455 bytes recruitment/__pycache__/forms.cpython-313.pyc | Bin 26844 -> 27062 bytes .../linkedin_service.cpython-313.pyc | Bin 16444 -> 16545 bytes .../__pycache__/models.cpython-313.pyc | Bin 59055 -> 60864 bytes recruitment/__pycache__/urls.cpython-313.pyc | Bin 11294 -> 11420 bytes .../__pycache__/validators.cpython-313.pyc | Bin 1131 -> 1131 bytes recruitment/__pycache__/views.cpython-313.pyc | Bin 91306 -> 93485 bytes .../views_frontend.cpython-313.pyc | Bin 23362 -> 23362 bytes recruitment/migrations/0001_initial.py | 600 ------------------ recruitment/views.py | 41 +- 10 files changed, 40 insertions(+), 601 deletions(-) delete mode 100644 recruitment/migrations/0001_initial.py diff --git a/NorahUniversity/__pycache__/settings.cpython-313.pyc b/NorahUniversity/__pycache__/settings.cpython-313.pyc index 3e3558682b9a923b25fcb998c3d7ef70438474d3..b3d3954123eaa66a740736630f674d78cc4500c4 100644 GIT binary patch delta 1093 zcmX|8%TrT#6u!Tkhb97sNsKy341z$2xd|8`3Mkv`5&A~$3>^pP0zg*^PBUX?>urI_xu{aJ<;;Kx!Ec4 zZz%V7b}INy%Q5luFFg^l>%&R-(ScKnJtC+bo#=`P#?vNto5*=#EBVkH7IZQ!A&?N{ zhn+gmN2efDC-W`@afU0LMu@thP!CHl?EJ!tOaVk7bF>fr7zoQ0#92DC>OizNbV!o8 zYzTv-aG5Ym1Vhx1VH)6s*o*kthaz<7+@Nf%AW0NubNBp9a}Xmmgi#)CEFl;#Bm^!h zM#Eu@Qw(uBhY325NgBZvjbfU{ST1m{iN5k6L|_ynKgGkk9H+qi=-aM$2rE1&$HV#Al*%6MNX z7WUj%EOZH9)8d94c#w_?NpjZqEYX8LM>ehH()m!wK6p0sv~nVbn%?J$@}E+kYmARQF_G1udmebcHBufiaNDx6 zMTIK*qa&lDsy{u_=l#KmShqFxCjDq+{$#+G?(z1DZGFre>&Y4kHm#7}Q0um8dM&S- zo7A0UDwS2LYHB55p@;hS-eIv+d+Pm7_PFDdlb5e7CsQl&EB*%`dMMuj delta 998 zcmX|8TT@e46h8Z$5Djt(5~Ge1L%1fGlL!IAMdhL(NUQOyRVlO$65t3VVda40Eoket zm$5zVlXj+0j<0QA`V0EfnNFv^FnQ6}J~-Ox)bY`^kKoy}zV+?3zPX_Ffh!9t3KnpcuKQ*y6!^tbGs}zKeNJOO&qSP|s!h!HMMd51u z{b;2yAJ^F;Xrm}%bbtlz8-mvFMR;3ByDD2(6l&vbzVrPyhB&pOi(BeW2*#d-K(DTH z8yz@Eoj62s9HuVxQ8)Uj2Lsg0c98Engh4utBh-hZ+(ti!Xn<`H!*m44=qN^L2%|KN z;~2vS_z*509&T{IUu40_+6TOU%VFHu*ly{%ubK55| zW&87(wtWgSwx7kE^bseGz`z9_V?H6GyqGQ6V=eMnX=GTVAe+d`#1eHQc~Wd|~r1aSOL`NAie+fAw9x1o!wVx$f&4 zN50ZE8pYRid{zy9lZ**PDJ?wLVq4vn=?o?3mea;cigJdzYPFWdMMGh}?5QZ6sd%9} zPs;yw${MW-Z_;a3OJcI{vZ_uD88W#jAuYk)W|#&2G`ATjZpkd0)2XysbQ)>t-^nh> z{Jew(>umL~Fsz@eTk7A}DsDA1)0r_Nw;`8RDQnlXURE1o);i~j@u6=$z;;n_nvjP_uuj@Zs#k_Rj#hNUInbbYkEY$s_^->=Zzt&&DSBe7gl}u JRmW>C@D@K;3tIpH diff --git a/recruitment/__pycache__/forms.cpython-313.pyc b/recruitment/__pycache__/forms.cpython-313.pyc index 2f0ec5aab456471a398568fb9cb47db5ed70511d..56f5f323f2c48db77f69a6d7669d01808c68c514 100644 GIT binary patch delta 233 zcmca}k#XB)M&8f7yj%=GV3z$o!)hY0B;&J<>U){_Bp8$!f=#3tf=y!>gAyhyx(iRP zXXIeDNjKCq+x&t#IdQVHqZp&eWPg59m2_rJmRo`$`RVC7sgB9X`K5U!Zuv#InLC&m z7>Z1QX8UQfP7V|lne5^qs$9Yd6a*0<*c_#N2ixFN`GNcWfb`m#K_3VIfHdR*G#Uj3_vDW FD*#GhI#B=s delta 78 zcmdmXneom=M&8f7yj%=GaG&XG2G>MhNya@J)%P;9q#J6QY!+fkPGr)w*({j$nsG8? fh9p-bBLf2vF%(yBR>>%5$|zFg1QY=PqFxl{ diff --git a/recruitment/__pycache__/linkedin_service.cpython-313.pyc b/recruitment/__pycache__/linkedin_service.cpython-313.pyc index fb440f143e9c9521acf9a31a70a5368cffa0218d..75e7844056c375605cdc06137c3b19e816fcbb8e 100644 GIT binary patch delta 481 zcmdnfz__rHk@qt%FBbz4m}P&@__&dmMU~?d3j@PchG53Y_e~@=8>+Uk7)7gsRDeJz zlPM#F6)a-4hk+rH10)tK94yMh5GT9=9Oz+@e}OaYLWzz!$^>o`4msa+1MA*;rhw8>)jQyI@rUSlsI obqS+Ukumtl2 zDNlaLC_MR(CJ&>?W=^dcj7*wBlecT%ojg-#4Wr~{H(g$)&4v2Mm{}G9jhnn*SblPp zF~86zAV-t8NCHR|#e;}BldFyW**1Wf8z)~d_F`n(EN$|Uk#YHCUNcRbIUw=PAYu!U z&}1&^0kNlpi0vQ&Hi$`JWw{_xu$f*U)|SadX3>nso6ni~u&_bQnXF)~DGqW$<`+h= zY3o4>jX}hw$qCjj0((GABe>x9$y=<|8RtyCW8KE+u{qgBmx*!zbdZp`2vQ^iA|!#tEe@O9{FKt1RJ)>Elbs#>`3qPX L`93j#NU$OR1dwF2 diff --git a/recruitment/__pycache__/models.cpython-313.pyc b/recruitment/__pycache__/models.cpython-313.pyc index f37d8a23aa4cb03759e6fb2ecddb042a6d4ef841..d45fe48bcf80144ed2ef4183e60ceb8cb7a87919 100644 GIT binary patch delta 10216 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 C!pgk> delta 8897 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 diff --git a/recruitment/__pycache__/urls.cpython-313.pyc b/recruitment/__pycache__/urls.cpython-313.pyc index ccb46c298600c9d339cf347a56ca3e4153a992b6..d758325a516ffc8b05f773c9cb39d75983f9ee9e 100644 GIT binary patch delta 1188 zcmZvc&u<$=6vw^xxJueOEi^X%l?3l@*7hcmRfyvT*R9*c&_Y^4U005i#&w(!peS)1 zCnT*L!!1HWO0)+m5h14>@X;t2bBe`ZuG5R&U-Vn zlE2L#&i4J~a-FvEXX4?Dk5;sUKCk_(>xal6XZ3kWwq=|1t>E`PjQd#m#B$}{)>`s30-K$7kp z*9WgU?A3e5kD<9U+q{{?e;c0D#*pmx)unUxpGnW&t9uL7rGrav2Y{rQqi)=iWvOmd zWFP03a=>pTpZD3Ey=Je{%zeLbw9pv^@(w#!H%??f4?U9u2@H8KG}(#Mc*%Nm_+|Nt{rN+X($e%xOsU7$SoE^C!>>_8LB2h zO`6wpK<+W6ZhWo;c>hDi+VF{@aQ?2SoIR?=F;zW<>&Fe3>N6_pDKVY+cj~k!_+r&6 z(NV1uzu@={P8)6@nz|3vnMt?^jc%Dfv67O>j3Rc+6^AEy^a;lil-<_#b>*^Y$r zk!Tfa#;KA5C1p+*fXuPS!tM$iZ*S5>4iY(YehbKFtij87!vmbZAzvc>kum<}268K6 z9qt=sH-bszOQb&}=UyH;ky&zY`r07rHCL*Si@yU4-eP`QbK@9oFEDMi$b?XGH$U}VdlRhTnX7Uc}5{I6+sZR%=-gW`G!e$-l3dSoVp2nP*%wsUPzx?&u z!CET`B*E?rvw$YBpQG+5xT9w5Dv&fQ3i$x#;1ehH#=sjhpYCN)v^S~pIoiZI1* kWfw?;Z3??B>_o>&FJ<9U)-0?8sj?lkU!19K@&AB-0LO@bF8}}l delta 1085 zcmXYwOK1~87{{A*QmmT#j3!Omw7Z*4vR3M&G1VBGzI;G^(Wa(J+gPo(Dq34n*QgEN z3M#bh!5%~+9t?sI>7^H;XAd&p#nGE55kZ(Dh@gnG-?*?pGV}Y-_sz_br$f&&bwAwh zwN>I#(?2Kwh8F6)&adm=M82%AnK?C4iauXzcc0j}^tPei;W)kYv9Y7t3MiR%x5Wa7 zcyIiwwTg=O4vy5I}s zJLD?TtJ^lI+jboJP}hUlCgZ?;wpKiBcOUHTqy6WBjPoIpqaaoEnh3J0=S&9tk{dFNwnOABmip?i-4ImYieP!?pX=2DEQNl=rtCkrIU?@Bu> zZLD&W#nTW^)8Sh{Zu6oj-xO&OJcJxZ79u;vOd0thVju1|vMGv5U8o8 zPSg4kwflRG26>^gGTgP&%X;$AlcyI=Aa{6CBnOO;NEVPK!#=@##VBO43 H@z?(cK&D~N diff --git a/recruitment/__pycache__/validators.cpython-313.pyc b/recruitment/__pycache__/validators.cpython-313.pyc index 7126ff0fda654c7a83f6f451af673c5cc867fcc0..535cebdd543abe5ae5920387017e897a7fb87a4b 100644 GIT binary patch delta 25 fcmaFO@tTACGcPX}0}z;Hf1k*Gl#yxU#aYY%W*`V8 delta 25 fcmaFO@tTACGcPX}0}$M2`Z|&OC?n&>i?f&kX>bT( diff --git a/recruitment/__pycache__/views.cpython-313.pyc b/recruitment/__pycache__/views.cpython-313.pyc index 0170e13a76d023df7970d04a3419f8f558bb0816..0ec2a0c55edff3ce0d948407f9e2d2592177b05f 100644 GIT binary patch delta 19262 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 #Koz@A3s1?e1fxYhfmII**T+ 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 diff --git a/recruitment/__pycache__/views_frontend.cpython-313.pyc b/recruitment/__pycache__/views_frontend.cpython-313.pyc index 94019cea128c8143430a2136a13f1a258c0f7d60..f0fcd8b8dedf2af6f4cf66768a481efd410a1f67 100644 GIT binary patch delta 22 ccmX@Kjq%VnM()qNyj%=GV3z%TBe!`p09Z%{`v3p{ delta 22 ccmX@Kjq%VnM()qNyj%=G@U-sRMsD+H09}3uyZ`_I diff --git a/recruitment/migrations/0001_initial.py b/recruitment/migrations/0001_initial.py deleted file mode 100644 index 4824bab..0000000 --- a/recruitment/migrations/0001_initial.py +++ /dev/null @@ -1,600 +0,0 @@ -# Generated by Django 5.2.6 on 2025-10-19 18:40 - -import django.core.validators -import django.db.models.deletion -import django_ckeditor_5.fields -import django_countries.fields -import django_extensions.db.fields -import recruitment.validators -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='BreakTime', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start_time', models.TimeField(verbose_name='Start Time')), - ('end_time', models.TimeField(verbose_name='End Time')), - ], - ), - migrations.CreateModel( - name='FormStage', - 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')), - ('name', models.CharField(help_text='Name of the stage', max_length=200)), - ('order', models.PositiveIntegerField(default=0, help_text='Order of the stage in the form')), - ('is_predefined', models.BooleanField(default=False, help_text='Whether this is a default resume stage')), - ], - options={ - 'verbose_name': 'Form Stage', - 'verbose_name_plural': 'Form Stages', - 'ordering': ['order'], - }, - ), - migrations.CreateModel( - name='HiringAgency', - 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')), - ('name', models.CharField(max_length=200, unique=True, verbose_name='Agency Name')), - ('contact_person', models.CharField(blank=True, max_length=150, verbose_name='Contact Person')), - ('email', models.EmailField(blank=True, max_length=254)), - ('phone', models.CharField(blank=True, max_length=20)), - ('website', models.URLField(blank=True)), - ('notes', models.TextField(blank=True, help_text='Internal notes about the agency')), - ('country', django_countries.fields.CountryField(blank=True, max_length=2, null=True)), - ('address', models.TextField(blank=True, null=True)), - ], - options={ - 'verbose_name': 'Hiring Agency', - 'verbose_name_plural': 'Hiring Agencies', - 'ordering': ['name'], - }, - ), - migrations.CreateModel( - name='Source', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('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')), - ('name', models.CharField(help_text='e.g., ATS, ERP ', max_length=100, unique=True, verbose_name='Source Name')), - ('source_type', models.CharField(help_text='e.g., ATS, ERP ', max_length=100, verbose_name='Source Type')), - ('description', models.TextField(blank=True, help_text='A description of the source', verbose_name='Description')), - ('ip_address', models.GenericIPAddressField(blank=True, help_text='The IP address of the source', null=True, verbose_name='IP Address')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('api_key', models.CharField(blank=True, help_text='API key for authentication (will be encrypted)', max_length=255, null=True, verbose_name='API Key')), - ('api_secret', models.CharField(blank=True, help_text='API secret for authentication (will be encrypted)', max_length=255, null=True, verbose_name='API Secret')), - ('trusted_ips', models.TextField(blank=True, help_text='Comma-separated list of trusted IP addresses', null=True, verbose_name='Trusted IP Addresses')), - ('is_active', models.BooleanField(default=True, help_text='Whether this source is active for integration', verbose_name='Active')), - ('integration_version', models.CharField(blank=True, help_text='Version of the integration protocol', max_length=50, verbose_name='Integration Version')), - ('last_sync_at', models.DateTimeField(blank=True, help_text='Timestamp of the last successful synchronization', null=True, verbose_name='Last Sync At')), - ('sync_status', models.CharField(blank=True, choices=[('IDLE', 'Idle'), ('SYNCING', 'Syncing'), ('ERROR', 'Error'), ('DISABLED', 'Disabled')], default='IDLE', max_length=20, verbose_name='Sync Status')), - ], - options={ - 'verbose_name': 'Source', - 'verbose_name_plural': 'Sources', - 'ordering': ['name'], - }, - ), - migrations.CreateModel( - name='ZoomMeeting', - 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')), - ('meeting_id', models.CharField(db_index=True, max_length=20, unique=True, verbose_name='Meeting ID')), - ('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')), - ('meeting_id', models.CharField(db_index=True, max_length=20, unique=True, verbose_name='Meeting ID')), - ('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')), - ('join_url', models.URLField(verbose_name='Join URL')), - ('participant_video', models.BooleanField(default=True, verbose_name='Participant Video')), - ('password', models.CharField(blank=True, max_length=20, null=True, verbose_name='Password')), - ('join_before_host', models.BooleanField(default=False, verbose_name='Join Before Host')), - ('mute_upon_entry', models.BooleanField(default=False, verbose_name='Mute Upon Entry')), - ('waiting_room', models.BooleanField(default=False, verbose_name='Waiting Room')), - ('zoom_gateway_response', models.JSONField(blank=True, null=True, verbose_name='Zoom Gateway Response')), - ('status', models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status')), - ('status', models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='FormField', - 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')), - ('label', models.CharField(help_text='Label for the field', max_length=200)), - ('field_type', models.CharField(choices=[('text', 'Text Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes')], help_text='Type of the field', max_length=20)), - ('placeholder', models.CharField(blank=True, help_text='Placeholder text', max_length=200)), - ('required', models.BooleanField(default=False, help_text='Whether the field is required')), - ('order', models.PositiveIntegerField(default=0, help_text='Order of the field in the stage')), - ('is_predefined', models.BooleanField(default=False, help_text='Whether this is a default field')), - ('options', models.JSONField(blank=True, default=list, help_text='Options for selection fields (stored as JSON array)')), - ('file_types', models.CharField(blank=True, help_text="Allowed file types (comma-separated, e.g., '.pdf,.doc,.docx')", max_length=200)), - ('max_file_size', models.PositiveIntegerField(default=5, help_text='Maximum file size in MB (default: 5MB)')), - ('multiple_files', models.BooleanField(default=False, help_text='Allow multiple files to be uploaded')), - ('max_files', models.PositiveIntegerField(default=1, help_text='Maximum number of files allowed (when multiple_files is True)')), - ('stage', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='recruitment.formstage')), - ], - options={ - 'verbose_name': 'Form Field', - 'verbose_name_plural': 'Form Fields', - 'ordering': ['order'], - }, - ), - migrations.CreateModel( - name='FormTemplate', - 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')), - ('name', models.CharField(help_text='Name of the form template', max_length=200)), - ('description', models.TextField(blank=True, help_text='Description of the form template')), - ('is_active', models.BooleanField(default=False, help_text='Whether this template is active')), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='form_templates', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Form Template', - 'verbose_name_plural': 'Form Templates', - 'ordering': ['-created_at'], - }, - ), - migrations.CreateModel( - name='FormSubmission', - 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')), - ('submitted_at', models.DateTimeField(auto_now_add=True, db_index=True)), - ('applicant_name', models.CharField(blank=True, help_text='Name of the applicant', max_length=200)), - ('applicant_email', models.EmailField(blank=True, db_index=True, help_text='Email of the applicant', max_length=254)), - ('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='form_submissions', to=settings.AUTH_USER_MODEL)), - ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='recruitment.formtemplate')), - ], - options={ - 'verbose_name': 'Form Submission', - 'verbose_name_plural': 'Form Submissions', - 'ordering': ['-submitted_at'], - }, - migrations.CreateModel( - name='FormSubmission', - 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')), - ('submitted_at', models.DateTimeField(auto_now_add=True, db_index=True)), - ('applicant_name', models.CharField(blank=True, help_text='Name of the applicant', max_length=200)), - ('applicant_email', models.EmailField(blank=True, db_index=True, help_text='Email of the applicant', max_length=254)), - ('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='form_submissions', to=settings.AUTH_USER_MODEL)), - ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='recruitment.formtemplate')), - ], - options={ - 'verbose_name': 'Form Submission', - 'verbose_name_plural': 'Form Submissions', - 'ordering': ['-submitted_at'], - }, - ), - migrations.AddField( - model_name='formstage', - name='template', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stages', to='recruitment.formtemplate'), - ), - migrations.CreateModel( - name='Candidate', - 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')), - ('first_name', models.CharField(max_length=255, verbose_name='First Name')), - ('last_name', models.CharField(max_length=255, verbose_name='Last Name')), - ('email', models.EmailField(db_index=True, max_length=254, verbose_name='Email')), - ('email', models.EmailField(db_index=True, max_length=254, verbose_name='Email')), - ('phone', models.CharField(max_length=20, verbose_name='Phone')), - ('address', models.TextField(max_length=200, verbose_name='Address')), - ('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')), - ('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')), - ('is_potential_candidate', models.BooleanField(default=False, verbose_name='Potential Candidate')), - ('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')], db_index=True, default='Applied', max_length=100, verbose_name='Stage')), - ('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Offer', 'Offer')], db_index=True, default='Applied', max_length=100, verbose_name='Stage')), - ('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=100, 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=100, 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=100, null=True, verbose_name='Interview Status')), - ('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=100, 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')], max_length=100, null=True, verbose_name='Offer Status')), - ('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')), - ('ai_analysis_data', models.JSONField(default=dict, help_text='Full JSON output from the resume scoring model.', verbose_name='AI Analysis Data')), - ('ai_analysis_data', models.JSONField(default=dict, help_text='Full JSON output from the resume scoring model.', verbose_name='AI Analysis Data')), - ('submitted_by_agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submitted_candidates', to='recruitment.hiringagency', verbose_name='Submitted by Agency')), - ], - options={ - 'verbose_name': 'Candidate', - 'verbose_name_plural': 'Candidates', - }, - ), - migrations.CreateModel( - name='JobPosting', - fields=[ - ('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')), - ('title', models.CharField(max_length=200)), - ('department', models.CharField(blank=True, max_length=100)), - ('job_type', models.CharField(choices=[('FULL_TIME', 'Full-time'), ('PART_TIME', 'Part-time'), ('CONTRACT', 'Contract'), ('INTERNSHIP', 'Internship'), ('FACULTY', 'Faculty'), ('TEMPORARY', 'Temporary')], default='FULL_TIME', max_length=20)), - ('workplace_type', models.CharField(choices=[('ON_SITE', 'On-site'), ('REMOTE', 'Remote'), ('HYBRID', 'Hybrid')], default='ON_SITE', max_length=20)), - ('location_city', models.CharField(blank=True, max_length=100)), - ('location_state', models.CharField(blank=True, max_length=100)), - ('location_country', models.CharField(default='Saudia Arabia', max_length=100)), - ('description', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Description')), - ('qualifications', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)), - ('salary_range', models.CharField(blank=True, help_text='e.g., $60,000 - $80,000', max_length=200)), - ('benefits', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)), - ('application_url', models.URLField(blank=True, help_text='URL where candidates apply', null=True, validators=[django.core.validators.URLValidator()])), - ('application_start_date', models.DateField(blank=True, null=True)), - ('application_deadline', models.DateField(blank=True, db_index=True, null=True)), - ('application_deadline', models.DateField(blank=True, db_index=True, null=True)), - ('application_instructions', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)), - ('internal_job_id', models.CharField(editable=False, max_length=50, primary_key=True, serialize=False)), - ('created_by', models.CharField(blank=True, help_text='Name of person who created this job', max_length=100)), - ('status', models.CharField(choices=[('DRAFT', 'Draft'), ('ACTIVE', 'Active'), ('CLOSED', 'Closed'), ('CANCELLED', 'Cancelled'), ('ARCHIVED', 'Archived')], db_index=True, default='DRAFT', max_length=20)), - ('status', models.CharField(choices=[('DRAFT', 'Draft'), ('ACTIVE', 'Active'), ('CLOSED', 'Closed'), ('CANCELLED', 'Cancelled'), ('ARCHIVED', 'Archived')], db_index=True, default='DRAFT', max_length=20)), - ('hash_tags', models.CharField(blank=True, help_text='Comma-separated hashtags for linkedin post like #hiring,#jobopening', max_length=200, validators=[recruitment.validators.validate_hash_tags])), - ('linkedin_post_id', models.CharField(blank=True, help_text='LinkedIn post ID after posting', max_length=200)), - ('linkedin_post_url', models.URLField(blank=True, help_text='Direct URL to LinkedIn post')), - ('posted_to_linkedin', models.BooleanField(default=False)), - ('linkedin_post_status', models.CharField(blank=True, help_text='Status of LinkedIn posting', max_length=50)), - ('linkedin_posted_at', models.DateTimeField(blank=True, null=True)), - ('published_at', models.DateTimeField(blank=True, db_index=True, null=True)), - ('published_at', models.DateTimeField(blank=True, db_index=True, null=True)), - ('position_number', models.CharField(blank=True, help_text='University position number', max_length=50)), - ('reporting_to', models.CharField(blank=True, help_text='Who this position reports to', max_length=100)), - ('joining_date', models.DateField(blank=True, help_text='Desired start date', null=True)), - ('open_positions', models.PositiveIntegerField(default=1, help_text='Number of open positions for this job')), - ('max_applications', models.PositiveIntegerField(blank=True, default=1000, help_text='Maximum number of applications allowed', null=True)), - ('max_applications', models.PositiveIntegerField(blank=True, default=1000, help_text='Maximum number of applications allowed', null=True)), - ('cancel_reason', models.TextField(blank=True, help_text='Reason for canceling the job posting', verbose_name='Cancel Reason')), - ('cancelled_by', models.CharField(blank=True, help_text='Name of person who cancelled this job', max_length=100, verbose_name='Cancelled By')), - ('cancelled_at', models.DateTimeField(blank=True, null=True)), - ('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')), - ('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={ - 'verbose_name': 'Job Posting', - 'verbose_name_plural': 'Job Postings', - 'ordering': ['-created_at'], - }, - ), - migrations.CreateModel( - name='InterviewSchedule', - 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')), - ('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')), - ('start_date', models.DateField(db_index=True, verbose_name='Start Date')), - ('end_date', models.DateField(db_index=True, verbose_name='End Date')), - ('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')), - ('start_time', models.TimeField(verbose_name='Start Time')), - ('end_time', models.TimeField(verbose_name='End Time')), - ('break_start_time', models.TimeField(blank=True, null=True, verbose_name='Break Start Time')), - ('break_end_time', models.TimeField(blank=True, null=True, verbose_name='Break End Time')), - ('break_start_time', models.TimeField(blank=True, null=True, verbose_name='Break Start Time')), - ('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.candidate')), - ('candidates', models.ManyToManyField(blank=True, null=True, related_name='interview_schedules', to='recruitment.candidate')), - ('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')), - ], - ), - migrations.AddField( - model_name='formtemplate', - name='job', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='form_template', to='recruitment.jobposting'), - ), - migrations.AddField( - model_name='candidate', - name='job', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='candidates', to='recruitment.jobposting', verbose_name='Job'), - ), - migrations.CreateModel( - name='JobPostingImage', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('post_image', models.ImageField(upload_to='post/', validators=[recruitment.validators.validate_image_size])), - ('job', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='post_images', to='recruitment.jobposting')), - ], - ), - migrations.CreateModel( - name='Profile', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='SharedFormTemplate', - 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')), - ('is_public', models.BooleanField(default=False, help_text='Whether this template is publicly available')), - ('shared_with', models.ManyToManyField(blank=True, related_name='shared_templates', to=settings.AUTH_USER_MODEL)), - ('template', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='recruitment.formtemplate')), - ], - options={ - 'verbose_name': 'Shared Form Template', - 'verbose_name_plural': 'Shared Form Templates', - }, - ), - migrations.CreateModel( - name='IntegrationLog', - 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')), - ('action', models.CharField(choices=[('REQUEST', 'Request'), ('RESPONSE', 'Response'), ('ERROR', 'Error'), ('SYNC', 'Sync'), ('CREATE_JOB', 'Create Job'), ('UPDATE_JOB', 'Update Job')], max_length=20, verbose_name='Action')), - ('endpoint', models.CharField(blank=True, max_length=255, verbose_name='Endpoint')), - ('method', models.CharField(blank=True, max_length=10, verbose_name='HTTP Method')), - ('request_data', models.JSONField(blank=True, null=True, verbose_name='Request Data')), - ('response_data', models.JSONField(blank=True, null=True, verbose_name='Response Data')), - ('status_code', models.CharField(blank=True, max_length=10, verbose_name='Status Code')), - ('error_message', models.TextField(blank=True, verbose_name='Error Message')), - ('ip_address', models.GenericIPAddressField(verbose_name='IP Address')), - ('user_agent', models.CharField(blank=True, max_length=255, verbose_name='User Agent')), - ('processing_time', models.FloatField(blank=True, null=True, verbose_name='Processing Time (seconds)')), - ('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='integration_logs', to='recruitment.source', verbose_name='Source')), - ], - options={ - 'verbose_name': 'Integration Log', - 'verbose_name_plural': 'Integration Logs', - 'ordering': ['-created_at'], - }, - ), - migrations.CreateModel( - name='TrainingMaterial', - 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')), - ('title', models.CharField(max_length=255, verbose_name='Title')), - ('content', django_ckeditor_5.fields.CKEditor5Field(blank=True, verbose_name='Content')), - ('video_link', models.URLField(blank=True, verbose_name='Video Link')), - ('file', models.FileField(blank=True, upload_to='training_materials/', verbose_name='File')), - ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Created by')), - ], - options={ - 'verbose_name': 'Training Material', - 'verbose_name_plural': 'Training Materials', - }, - ), - migrations.CreateModel( - name='ScheduledInterview', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), - ('interview_date', models.DateField(db_index=True, verbose_name='Interview Date')), - ('interview_date', models.DateField(db_index=True, verbose_name='Interview Date')), - ('interview_time', models.TimeField(verbose_name='Interview Time')), - ('status', models.CharField(choices=[('scheduled', 'Scheduled'), ('confirmed', 'Confirmed'), ('cancelled', 'Cancelled'), ('completed', 'Completed')], db_index=True, default='scheduled', max_length=20)), - ('status', models.CharField(choices=[('scheduled', 'Scheduled'), ('confirmed', 'Confirmed'), ('cancelled', 'Cancelled'), ('completed', 'Completed')], db_index=True, default='scheduled', max_length=20)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('candidate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.candidate')), - ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.jobposting')), - ('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')), - ], - ), - migrations.CreateModel( - name='MeetingComment', - 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')), - ('content', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Content')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='meeting_comments', to=settings.AUTH_USER_MODEL, verbose_name='Author')), - ('meeting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='recruitment.zoommeeting', verbose_name='Meeting')), - ], - options={ - 'verbose_name': 'Meeting Comment', - 'verbose_name_plural': 'Meeting Comments', - 'ordering': ['-created_at'], - }, - ), - migrations.CreateModel( - name='FieldResponse', - 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')), - ('value', models.JSONField(blank=True, help_text='Response value (stored as JSON)', null=True)), - ('uploaded_file', models.FileField(blank=True, null=True, upload_to='form_uploads/')), - ('field', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formfield')), - ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formsubmission')), - ], - ), - migrations.CreateModel( - name='MeetingComment', - 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')), - ('content', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Content')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='meeting_comments', to=settings.AUTH_USER_MODEL, verbose_name='Author')), - ('meeting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='recruitment.zoommeeting', verbose_name='Meeting')), - ], - options={ - 'verbose_name': 'Meeting Comment', - 'verbose_name_plural': 'Meeting Comments', - 'ordering': ['-created_at'], - }, - ), - migrations.CreateModel( - name='FieldResponse', - 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')), - ('value', models.JSONField(blank=True, help_text='Response value (stored as JSON)', null=True)), - ('uploaded_file', models.FileField(blank=True, null=True, upload_to='form_uploads/')), - ('field', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formfield')), - ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formsubmission')), - ], - options={ - 'verbose_name': 'Field Response', - 'verbose_name_plural': 'Field Responses', - 'indexes': [models.Index(fields=['submission'], name='recruitment_submiss_474130_idx'), models.Index(fields=['field'], name='recruitment_field_i_097e5b_idx')], - 'verbose_name': 'Field Response', - 'verbose_name_plural': 'Field Responses', - 'indexes': [models.Index(fields=['submission'], name='recruitment_submiss_474130_idx'), models.Index(fields=['field'], name='recruitment_field_i_097e5b_idx')], - }, - ), - migrations.AddIndex( - model_name='formsubmission', - index=models.Index(fields=['submitted_at'], name='recruitment_submitt_7946c8_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['start_date'], name='recruitment_start_d_15d55e_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['end_date'], name='recruitment_end_dat_aeb00e_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['created_by'], name='recruitment_created_d0bdcc_idx'), - ), - migrations.AddIndex( - model_name='formtemplate', - index=models.Index(fields=['created_at'], name='recruitment_created_c21775_idx'), - ), - migrations.AddIndex( - model_name='formtemplate', - index=models.Index(fields=['is_active'], name='recruitment_is_acti_ae5efb_idx'), - ), - migrations.AddIndex( - model_name='candidate', - index=models.Index(fields=['stage'], name='recruitment_stage_f1c6eb_idx'), - ), - migrations.AddIndex( - model_name='candidate', - index=models.Index(fields=['created_at'], name='recruitment_created_73590f_idx'), - ), - migrations.AddIndex( - model_name='jobposting', - index=models.Index(fields=['status', 'created_at', 'title'], name='recruitment_status_8b77aa_idx'), - ), - migrations.AddIndex( - model_name='jobposting', - index=models.Index(fields=['slug'], name='recruitment_slug_004045_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['job', 'status'], name='recruitment_job_id_f09e22_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['interview_date', 'interview_time'], name='recruitment_intervi_7f5877_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['candidate', 'job'], name='recruitment_candida_43d5b0_idx'), - ), - migrations.AddIndex( - model_name='formsubmission', - index=models.Index(fields=['submitted_at'], name='recruitment_submitt_7946c8_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['start_date'], name='recruitment_start_d_15d55e_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['end_date'], name='recruitment_end_dat_aeb00e_idx'), - ), - migrations.AddIndex( - model_name='interviewschedule', - index=models.Index(fields=['created_by'], name='recruitment_created_d0bdcc_idx'), - ), - migrations.AddIndex( - model_name='formtemplate', - index=models.Index(fields=['created_at'], name='recruitment_created_c21775_idx'), - ), - migrations.AddIndex( - model_name='formtemplate', - index=models.Index(fields=['is_active'], name='recruitment_is_acti_ae5efb_idx'), - ), - migrations.AddIndex( - model_name='candidate', - index=models.Index(fields=['stage'], name='recruitment_stage_f1c6eb_idx'), - ), - migrations.AddIndex( - model_name='candidate', - index=models.Index(fields=['created_at'], name='recruitment_created_73590f_idx'), - ), - migrations.AddIndex( - model_name='jobposting', - index=models.Index(fields=['status', 'created_at', 'title'], name='recruitment_status_8b77aa_idx'), - ), - migrations.AddIndex( - model_name='jobposting', - index=models.Index(fields=['slug'], name='recruitment_slug_004045_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['job', 'status'], name='recruitment_job_id_f09e22_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['interview_date', 'interview_time'], name='recruitment_intervi_7f5877_idx'), - ), - migrations.AddIndex( - model_name='scheduledinterview', - index=models.Index(fields=['candidate', 'job'], name='recruitment_candida_43d5b0_idx'), - ), - ] diff --git a/recruitment/views.py b/recruitment/views.py index dfaace8..1d3e901 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -823,6 +823,22 @@ def form_wizard_view(request, template_id): """Display the form as a step-by-step wizard""" template = get_object_or_404(FormTemplate, pk=template_id, is_active=True) job_id = template.job.internal_job_id + job=template.job + is_limit_exceeded=job.is_application_limit_reached + if is_limit_exceeded: + messages.error( + request, + 'Application limit reached: This job is no longer accepting new applications. Please explore other available positions.' + ) + return redirect('job_detail_candidate',slug=job.slug) + + if job.is_expired: + messages.error( + request, + 'Application deadline passed: This job is no longer accepting new applications. Please explore other available positions.' + ) + return redirect('job_detail_candidate',slug=job.slug) + return render( request, "forms/form_wizard.html", @@ -2046,8 +2062,12 @@ def user_profile_image_update(request, pk): def user_detail(request, pk): user = get_object_or_404(User, pk=pk) + try: + profile_instance = user.profile + profile_form = ProfileImageUploadForm(instance=profile_instance) + except: + profile_form = ProfileImageUploadForm() - profile_form = ProfileImageUploadForm() if request.method == 'POST': first_name=request.POST.get('first_name') last_name=request.POST.get('last_name') @@ -2175,6 +2195,25 @@ def set_staff_password(request,pk): return render(request,'user/staff_password_create.html',{'form':form,'user':user}) +@user_passes_test(is_superuser_check) +def account_toggle_status(request,pk): + user=get_object_or_404(User,pk=pk) + if request.method=='POST': + print(user.is_active) + form=ToggleAccountForm(request.POST) + if form.is_valid(): + if user.is_active: + user.is_active=False + user.save() + messages.success(request,f'Staff with email: {user.email} deactivated successfully') + return redirect('admin_settings') + else: + user.is_active=True + user.save() + messages.success(request,f'Staff with email: {user.email} activated successfully') + return redirect('admin_settings') + else: + messages.error(f'Please correct the error below') @login_required