From 776c322148b249045f244c6f71efe8df2301f5c6 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 4 Feb 2026 03:56:23 +0000 Subject: [PATCH] Autosave: 20260204-035622 --- config/__pycache__/settings.cpython-311.pyc | Bin 7496 -> 7489 bytes config/settings.py | 4 +- core/__pycache__/admin.cpython-311.pyc | Bin 4779 -> 6699 bytes core/__pycache__/forms.cpython-311.pyc | Bin 0 -> 4292 bytes core/__pycache__/models.cpython-311.pyc | Bin 5886 -> 8209 bytes core/__pycache__/urls.cpython-311.pyc | Bin 694 -> 1081 bytes core/__pycache__/views.cpython-311.pyc | Bin 2909 -> 5039 bytes core/admin.py | 75 +++-- core/forms.py | 57 ++++ core/management/commands/seed_data.py | 16 +- ...ame_educationallevel_classroom_and_more.py | 21 ++ ...rename_level_student_classroom_and_more.py | 23 ++ ...nt_avatar_student_city_student_moderate.py | 28 ++ ...moderate_student_mobile_number_and_more.py | 51 ++++ ...allevel_classroom_and_more.cpython-311.pyc | Bin 0 -> 895 bytes ...student_classroom_and_more.cpython-311.pyc | Bin 0 -> 847 bytes ...dent_city_student_moderate.cpython-311.pyc | Bin 0 -> 1401 bytes ...ent_mobile_number_and_more.cpython-311.pyc | Bin 0 -> 2153 bytes core/models.py | 35 ++- core/templates/base.html | 17 +- core/templates/core/profile.html | 77 +++++ core/templates/core/registration.html | 262 ++++++++++++++++++ core/templates/core/subject_detail.html | 4 +- core/urls.py | 6 +- core/views.py | 46 ++- static/js/admin_resource.js | 6 +- static/js/admin_student.js | 4 +- staticfiles/js/admin_resource.js | 6 +- staticfiles/js/admin_student.js | 4 +- 29 files changed, 688 insertions(+), 54 deletions(-) create mode 100644 core/__pycache__/forms.cpython-311.pyc create mode 100644 core/forms.py create mode 100644 core/migrations/0002_rename_educationallevel_classroom_and_more.py create mode 100644 core/migrations/0003_rename_level_student_classroom_and_more.py create mode 100644 core/migrations/0004_student_avatar_student_city_student_moderate.py create mode 100644 core/migrations/0005_city_moderate_student_mobile_number_and_more.py create mode 100644 core/migrations/__pycache__/0002_rename_educationallevel_classroom_and_more.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0003_rename_level_student_classroom_and_more.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0004_student_avatar_student_city_student_moderate.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0005_city_moderate_student_mobile_number_and_more.cpython-311.pyc create mode 100644 core/templates/core/profile.html create mode 100644 core/templates/core/registration.html diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 8c9c2f7f0bed660bb0f4b6348a8bdf0744b86aec..7ccceb4f5ad8a4fb106fac133e993a29736956f3 100644 GIT binary patch delta 50 zcmX?MbzZ diff --git a/config/settings.py b/config/settings.py index 8b4d2d5..04a4eca 100644 --- a/config/settings.py +++ b/config/settings.py @@ -276,7 +276,7 @@ JAZZMIN_SETTINGS = { "core.Teacher": "fas fa-chalkboard-teacher", "core.Subject": "fas fa-book", "core.Resource": "fas fa-file-alt", - "core.EducationalLevel": "fas fa-layer-group", + "core.Classroom": "fas fa-layer-group", }, # Icons that are used when one is not manually specified "default_icon_parents": "fas fa-chevron-circle-right", @@ -298,4 +298,4 @@ JAZZMIN_SETTINGS = { "use_google_fonts_cdn": True, # Whether to show the UI customizer on the sidebar "show_ui_builder": True, -} +} \ No newline at end of file diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 4069c426abfd18a9a46c8e4baa53f82a217c3d22..e3f5397a6e03bbeb9f0f9e7c0e6dd05ac99ff6de 100644 GIT binary patch literal 6699 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 as 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 RK$9jd$cSfp6jb`>`~uMn#-{)P diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 31d12f8dc3cdfb0bfd5efefc3d1d7903b1df46e5..544cde0351b72ae9f21710e01c552a7c99c02969 100644 GIT binary patch delta 446 zcmdnSx|2g=IWI340}!m;*_7GK#K7vK2zKWu+#U z6zks-14_ihCE{TcRU8FH`DvLssrt9rp{y$Qoc#3s(h~h!Y!HT@Chslol&r+b(-^ho zia?$(;sp_WK;jl}a%pi%er`NO>EwfqzFcBJaYi66{xVsDsW0ya3rB-XhxCNhD`Gkq zj9o9VxLss%yTalI7Qeu$zC!ehrt1ZtlnX4W7g1-39eT})K_F&U@^bQVt$3i{DUATKT`uY2o{L|Ed>C7pMf6$ delta 107 zcmdnVv5i$@IWI340}ya>H)R$wGB7*_abSQ0%J{sAVWP$wu5^|tjuhTt22H-nd5jyF r{WLiz&tNi`{EW$$OAx3MsGFg9+GJbiK7kLMto%$3+#p!Q4-^IfBgGWS diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 701adce0ed70c945b4ffeea37f7fb62a6d3afef3..fdde019f1dfa0e6c5e84e0d680d1e3894e9ef68b 100644 GIT binary patch delta 2457 zcmai0U2NOd6~33GL`f8NWy@6@*|8niuB|L^mL_e}#);C|v6r>B)7tJ9VXLZ$jLk$6 z-AgJdQm0Z219gi6Y03f)hCKvB=QT@#x@#Z$^HS_7*oHweh(#daVJ~^uo3^4rFcfXi zr6m9K2fZLa9G-J{c+dULxtAN!_Xa|Ll;r?|@#V)aYkvt`3$^2aUK{vD5h>nmFefKv zj1;7Z*-(xo3CKRhpAF|)k}bK`WNR*xjO5yqZLU6$y)PF{MnRUAP;!?N1Z-Diz}>2( zgqF}MeB~DVlsl3!g@CO?2?KVjveL5Mqm}t2_b9Dk>{24rDBgDM&kIT%JE5#Tr{z;r zeXgKUm1(@7(F^8(FuW2M9REl*Z5UM7bB;J&ID1~rn2tE3rZe*@1&vuy)Vv9=?P`cm zsdJiP(zL1R`7xd5tO;DfvenHU#%+*rMKt(=k z%SZ3XiFG+qksq_=$3FN6_cx4V)^CM_xZV1@(2qN<{|Qgxerwb-2%4N{e|rofIYC1; zQ`vNWu8^Kn=|NDnS?_yR!2Oi>5643AOnHDfPurP%h{0h1gK2wudZ-&EWYlv^DXN*) zvh+b_w0#t%0d#r%3U-BxV;#-Bd zw|MIWAGJ>V_7uTml>-gj^#LUKCmml_y{KkWn&JdA&4q@iv76WtjPyD6CZrww; z*V>UX>93Gsn+)F}BkN@3v(ek}^6WDelCnw4D)~Ec=LczVFD_p0KV3MR)iOP5URlt! zyxDV3r#*CA!7xS6O?Zqx0@I*J84NQx2H0` zcGk)jyohfI)=SVrpW=`}dl#`)6Ql4zdO1^W217{UR$)4~Hm5X=@*$JA-p8?`Nw(Y; zk-{s&BGz!dN}Cp_NzbGsoSvGVp{!3YM>9HA4{WDsXx_|a9f1)Q_c`92YR>BlZ2@Qc za{$LPcIt_f(~eIwQc!tNwNS+$rWQ8ublis}`9yT>qd-Qw=kn0=3($ z7eOeYsu)^&@p^P!>@JJl8|3~Qm)>4n`{jqfsgMzyj4TUPiCjJQ+Oby?uP17V_xD$$ zvEqvMrgrVZTNjqc??yVVk5?jncBHQy?5m03@I?TH2P$OHCWFhuU8&`bfpW*8wR0aS zYtK}qQCk`<3#0Uh*`_e773AN+_xVi{uHgKx-Xbyu@M?@LqWci_utVVrK7;bYCG~K{YSy5v>Fe7)>+3qH9@dpcy&2g|-BZv#!srNlWP9IXx0hTl-L&XlW?`l69)SP% z4Z{ZtS@k%57IbV$3=LbC0{X8WDWe@%72RLnc~#Mo@{e6rw6DDLvN&nt*C8)HTtk}> m4&alxhPGil;=(n~i=PHH!~gQ2Sn6u1!W`aHL*E5Av2OrQTW9hB delta 682 zcmZ{i-)qxQ6vuPhCTY{&q}^(buu97;TTq$9S%$xg1?%v~WK0nBHVtXiK3G7(V$R2>P@KpLTAh;ER{!!^!vD@5wngc{{O_Q(t4O z2(bFC|dk}bQbCN^w=lK6TpnE07ppDPOb~D!2O1o z2$wl(rxpbRvk1C>^g9C0hz9A4cBf(aPP=8fSIH`I19`D?=N@VJfqa8ljk|=hM@o+U zKp#+&ZANBLn(aicOdSM!9B%It;EC`J=Lfhn#N|FNzkArj)d8*!ajlPQJv=wSb6dBf zpAgEiad8?QU^m4Q(%G80fQsykIEk`sS3IWYpi+?Xh+lWD)=I}(A@n#%8FpHF0o(i1 z%X2AsrcrzH>9-8Oi-td5a$IpVb k' + '' + '' + '', + edit_url, + delete_url + ) + actions_column.short_description = 'Actions' + +@admin.register(Classroom) +class ClassroomAdmin(ActionsModelAdmin): + list_display = ('name_en', 'name_ar', 'actions_column') @admin.register(Teacher) -class TeacherAdmin(admin.ModelAdmin): - list_display = ('user', 'specialization') +class TeacherAdmin(ActionsModelAdmin): + list_display = ('user', 'specialization', 'actions_column') @admin.register(Subject) -class SubjectAdmin(admin.ModelAdmin): - list_display = ('name_en', 'name_ar', 'level', 'price', 'teacher') - list_filter = ('level', 'teacher') +class SubjectAdmin(ActionsModelAdmin): + list_display = ('name_en', 'name_ar', 'classroom', 'price', 'teacher', 'actions_column') + list_filter = ('classroom', 'teacher') search_fields = ('name_en', 'name_ar') +@admin.register(City) +class CityAdmin(ActionsModelAdmin): + list_display = ('name', 'actions_column') + +@admin.register(Moderate) +class ModerateAdmin(ActionsModelAdmin): + list_display = ('name', 'actions_column') + class ResourceAdminForm(forms.ModelForm): - educational_level = forms.ModelChoiceField( - queryset=EducationalLevel.objects.all(), + classroom = forms.ModelChoiceField( + queryset=Classroom.objects.all(), required=True, - label="Filter by Educational Level" + label="Filter by Classroom" ) class Meta: @@ -30,22 +61,22 @@ class ResourceAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance and self.instance.pk and self.instance.subject: - self.fields['educational_level'].initial = self.instance.subject.level + self.fields['classroom'].initial = self.instance.subject.classroom @admin.register(Resource) -class ResourceAdmin(admin.ModelAdmin): +class ResourceAdmin(ActionsModelAdmin): form = ResourceAdminForm - list_display = ('title_en', 'subject', 'created_at') - list_filter = ('subject__level', 'subject') - fields = ('educational_level', 'subject', 'title_en', 'title_ar', 'file', 'link') + list_display = ('title_en', 'subject', 'created_at', 'actions_column') + list_filter = ('subject__classroom', 'subject') + fields = ('classroom', 'subject', 'title_en', 'title_ar', 'file', 'link') class Media: js = ('js/admin_resource.js',) @admin.register(Student) -class StudentAdmin(admin.ModelAdmin): - list_display = ('user', 'level', 'phone_number') - list_filter = ('level',) +class StudentAdmin(ActionsModelAdmin): + list_display = ('user', 'classroom', 'mobile_number', 'city', 'moderate', 'actions_column') + list_filter = ('classroom', 'city', 'moderate') filter_horizontal = ('subscribed_subjects',) class Media: @@ -53,6 +84,6 @@ class StudentAdmin(admin.ModelAdmin): def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) - if obj and obj.level: - form.base_fields['subscribed_subjects'].queryset = Subject.objects.filter(level=obj.level) + if obj and obj.classroom: + form.base_fields['subscribed_subjects'].queryset = Subject.objects.filter(classroom=obj.classroom) return form \ No newline at end of file diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..d2bdeb4 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,57 @@ +from django import forms +from django.contrib.auth.models import User +from .models import Student, Subject, Classroom + +class StudentRegistrationForm(forms.ModelForm): + first_name = forms.CharField(max_length=30, required=True, label="Full Name (First)") + last_name = forms.CharField(max_length=30, required=True, label="Full Name (Last)") + username = forms.CharField(max_length=150, required=True) + email = forms.EmailField(required=True) + password = forms.CharField(widget=forms.PasswordInput, required=True) + + classroom = forms.ModelChoiceField(queryset=Classroom.objects.all(), required=True, empty_label="Select Classroom") + subjects = forms.ModelMultipleChoiceField( + queryset=Subject.objects.all(), + required=False, + widget=forms.CheckboxSelectMultiple, + label="Select Subjects" + ) + + class Meta: + model = Student + fields = ['mobile_number', 'moderate', 'city', 'avatar'] + widgets = { + 'avatar': forms.FileInput(attrs={'accept': 'image/*', 'capture': 'camera'}), # generic hint, but we'll use custom JS + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # optimize subjects loading + self.fields['subjects'].queryset = Subject.objects.none() + + if 'classroom' in self.data: + try: + classroom_id = int(self.data.get('classroom')) + self.fields['subjects'].queryset = Subject.objects.filter(classroom_id=classroom_id) + except (ValueError, TypeError): + pass + elif self.instance.pk and self.instance.classroom: + self.fields['subjects'].queryset = Subject.objects.filter(classroom=self.instance.classroom) + + def save(self, commit=True): + # We need to save the User first, then the Student + user = User.objects.create_user( + username=self.cleaned_data['username'], + email=self.cleaned_data['email'], + password=self.cleaned_data['password'], + first_name=self.cleaned_data['first_name'], + last_name=self.cleaned_data['last_name'] + ) + student = super().save(commit=False) + student.user = user + student.classroom = self.cleaned_data['classroom'] + + if commit: + student.save() + student.subscribed_subjects.set(self.cleaned_data['subjects']) + return student \ No newline at end of file diff --git a/core/management/commands/seed_data.py b/core/management/commands/seed_data.py index c143bb3..3918e96 100644 --- a/core/management/commands/seed_data.py +++ b/core/management/commands/seed_data.py @@ -1,6 +1,6 @@ from django.core.management.base import BaseCommand from django.contrib.auth.models import User -from core.models import EducationalLevel, Subject, Teacher +from core.models import Classroom, Subject, Teacher class Command(BaseCommand): help = 'Seeds the database with sample data' @@ -14,13 +14,13 @@ class Command(BaseCommand): teacher, _ = Teacher.objects.get_or_create(user=user, specialization='Mathematics') - # Create Educational Levels - l1, _ = EducationalLevel.objects.get_or_create( + # Create Classrooms + l1, _ = Classroom.objects.get_or_create( name_en='Primary School', name_ar='المرحلة الابتدائية', description='Grades 1-6' ) - l2, _ = EducationalLevel.objects.get_or_create( + l2, _ = Classroom.objects.get_or_create( name_en='High School', name_ar='المرحلة الثانوية', description='Grades 10-12' @@ -28,7 +28,7 @@ class Command(BaseCommand): # Create Subjects Subject.objects.get_or_create( - level=l1, + classroom=l1, teacher=teacher, name_en='Basic Math', name_ar='الرياضيات الأساسية', @@ -37,7 +37,7 @@ class Command(BaseCommand): price=20.00 ) Subject.objects.get_or_create( - level=l2, + classroom=l2, teacher=teacher, name_en='Physics', name_ar='الفيزياء', @@ -46,7 +46,7 @@ class Command(BaseCommand): price=50.00 ) Subject.objects.get_or_create( - level=l2, + classroom=l2, teacher=teacher, name_en='Chemistry', name_ar='الكيمياء', @@ -55,4 +55,4 @@ class Command(BaseCommand): price=45.00 ) - self.stdout.write(self.style.SUCCESS('Successfully seeded sample data')) + self.stdout.write(self.style.SUCCESS('Successfully seeded sample data')) \ No newline at end of file diff --git a/core/migrations/0002_rename_educationallevel_classroom_and_more.py b/core/migrations/0002_rename_educationallevel_classroom_and_more.py new file mode 100644 index 0000000..74c3896 --- /dev/null +++ b/core/migrations/0002_rename_educationallevel_classroom_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 5.2.7 on 2026-02-03 19:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.RenameModel( + old_name='EducationalLevel', + new_name='Classroom', + ), + migrations.AlterModelOptions( + name='classroom', + options={'verbose_name': 'Classroom', 'verbose_name_plural': 'Classrooms'}, + ), + ] diff --git a/core/migrations/0003_rename_level_student_classroom_and_more.py b/core/migrations/0003_rename_level_student_classroom_and_more.py new file mode 100644 index 0000000..b9026dc --- /dev/null +++ b/core/migrations/0003_rename_level_student_classroom_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.7 on 2026-02-03 19:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_rename_educationallevel_classroom_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='student', + old_name='level', + new_name='classroom', + ), + migrations.RenameField( + model_name='subject', + old_name='level', + new_name='classroom', + ), + ] diff --git a/core/migrations/0004_student_avatar_student_city_student_moderate.py b/core/migrations/0004_student_avatar_student_city_student_moderate.py new file mode 100644 index 0000000..89992c2 --- /dev/null +++ b/core/migrations/0004_student_avatar_student_city_student_moderate.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.7 on 2026-02-04 02:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0003_rename_level_student_classroom_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='student', + name='avatar', + field=models.ImageField(blank=True, null=True, upload_to='students/', verbose_name='Picture'), + ), + migrations.AddField( + model_name='student', + name='city', + field=models.CharField(blank=True, choices=[('cairo', 'Cairo'), ('giza', 'Giza'), ('alexandria', 'Alexandria')], max_length=50, verbose_name='City'), + ), + migrations.AddField( + model_name='student', + name='moderate', + field=models.CharField(blank=True, choices=[('morning', 'Morning'), ('evening', 'Evening')], max_length=50, verbose_name='Moderate'), + ), + ] diff --git a/core/migrations/0005_city_moderate_student_mobile_number_and_more.py b/core/migrations/0005_city_moderate_student_mobile_number_and_more.py new file mode 100644 index 0000000..e5b8534 --- /dev/null +++ b/core/migrations/0005_city_moderate_student_mobile_number_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 5.2.7 on 2026-02-04 03:46 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0004_student_avatar_student_city_student_moderate'), + ] + + operations = [ + migrations.CreateModel( + name='City', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='Name')), + ], + options={ + 'verbose_name': 'City', + 'verbose_name_plural': 'Cities', + }, + ), + migrations.CreateModel( + name='Moderate', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='Name')), + ], + options={ + 'verbose_name': 'Moderate', + 'verbose_name_plural': 'Moderates', + }, + ), + migrations.AddField( + model_name='student', + name='mobile_number', + field=models.CharField(blank=True, max_length=20, verbose_name='Mobile Number'), + ), + migrations.AlterField( + model_name='student', + name='city', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.city', verbose_name='City'), + ), + migrations.AlterField( + model_name='student', + name='moderate', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.moderate', verbose_name='Moderate'), + ), + ] diff --git a/core/migrations/__pycache__/0002_rename_educationallevel_classroom_and_more.cpython-311.pyc b/core/migrations/__pycache__/0002_rename_educationallevel_classroom_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8436b8e6a2e8a38e6fd8c659ecb53c5a9e319ac6 GIT binary patch literal 895 zcmZuwzi-n(6nFfgmf+C1f2O%)vDG=im5R;<5Q577R0EhA`SH~c=*U+l}Qeg`THx7H;AA~H) zf(blvK}aU>yEI9nBymLX~Z<5V=;?e<+9CgC9TBQf`cUgwy?1-z*x8# z$Bg6=m3|ZBcex)aw2BB#X+mfcgf!zycro*es^k_UlJxweXh6C4Uz9fsm!)(vgzqp` zs-1Ve9TrnB@8-!M_vm{X3vcB48#d!ywT92t=1W!Q?UpGV()W`d+aO)7R!Qr+LTK0x>7CmT vO0^&In=+Jd0IoUvby7ME)Ma_ literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0003_rename_level_student_classroom_and_more.cpython-311.pyc b/core/migrations/__pycache__/0003_rename_level_student_classroom_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..676f49c2a4673f1352816c3573400757541228e5 GIT binary patch literal 847 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 gye;&u|GKxWzAve5^mnnNH {% trans "Teachers" %} + {% if user.is_staff %} + {% endif %}
{% if user.is_authenticated %} - {% trans "Hello" %}, {{ user.username }} + {% else %} + {% trans "Register" %} {% trans "Login" %} {% endif %}
diff --git a/core/templates/core/profile.html b/core/templates/core/profile.html new file mode 100644 index 0000000..07e1156 --- /dev/null +++ b/core/templates/core/profile.html @@ -0,0 +1,77 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}{% trans "My Profile" %} | EduPlatform{% endblock %} + +{% block content %} +
+
+
+
+
+
+ {% if student_profile and student_profile.avatar %} + Profile + {% else %} +
+ {{ user.username|make_list|first|upper }} +
+ {% endif %} +
+

{{ user.get_full_name|default:user.username }}

+

{{ user.email }}

+ {% if student_profile and student_profile.classroom %} + {{ student_profile.classroom.name_en }} + {% elif user.is_staff %} + {% trans "Staff / Admin" %} + {% endif %} +
+
+ +
+ + {% if student_profile %} +

{% trans "Student Details" %}

+
+
+ +

{{ user.username }}

+
+
+ +

{{ student_profile.city|default:"-" }}

+
+
+ +

{{ student_profile.moderate|default:"-" }}

+
+
+ +

{{ student_profile.mobile_number|default:"-" }}

+
+
+ +

{% trans "My Subjects" %}

+ {% if student_profile.subscribed_subjects.all %} +
+ {% for subject in student_profile.subscribed_subjects.all %} + + {{ subject.name_en }} + {% trans "View" %} + + {% endfor %} +
+ {% else %} +

{% trans "No subjects subscribed yet." %}

+ {% endif %} + {% else %} +
+ {% trans "You are logged in as a staff member or user without a student profile." %} +
+ {% endif %} +
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/registration.html b/core/templates/core/registration.html new file mode 100644 index 0000000..01f554d --- /dev/null +++ b/core/templates/core/registration.html @@ -0,0 +1,262 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}{% trans "Student Registration" %}{% endblock %} + +{% block content %} +
+
+
+
+

{% trans "Student Registration" %}

+ +
+ {% csrf_token %} + + {% if form.errors %} +
+ {{ form.errors }} +
+ {% endif %} + + +
{% trans "Personal Information" %}
+
+
+ + {{ form.first_name }} +
+
+ + {{ form.last_name }} +
+
+ +
+ + {{ form.username }} +
+ +
+ + {{ form.email }} +
+ +
+ + {{ form.password }} +
+ + +
{% trans "Student Details" %}
+
+
+ + {{ form.mobile_number }} +
+
+ + {{ form.moderate }} +
+
+ + {{ form.city }} +
+
+ + +
+ + {{ form.classroom }} +
+ +
+ +
+

{% trans "Select a classroom to see subjects." %}

+
+
+ +
+

{% trans "Total Amount:" %}

+

0.00

+
+ + +
{% trans "Profile Picture" %}
+
+
+
+ +
+ + +
+
+
+ + +
+ {% trans "No photo taken" %} +
+ +
+
+
+ + {{ form.avatar }} +
+
+ + +
+
+
+
+
+{% endblock %} + +{% block extra_js %} + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/subject_detail.html b/core/templates/core/subject_detail.html index e92bcd8..49302d7 100644 --- a/core/templates/core/subject_detail.html +++ b/core/templates/core/subject_detail.html @@ -11,7 +11,7 @@ @@ -27,7 +27,7 @@ {% endif %}
- {% if LANGUAGE_CODE == 'ar' %}{{ subject.level.name_ar }}{% else %}{{ subject.level.name_en }}{% endif %} + {% if LANGUAGE_CODE == 'ar' %}{{ subject.classroom.name_ar }}{% else %}{{ subject.classroom.name_en }}{% endif %}
diff --git a/core/urls.py b/core/urls.py index db3ba87..defe932 100644 --- a/core/urls.py +++ b/core/urls.py @@ -6,4 +6,8 @@ urlpatterns = [ path('set-language//', views.set_language, name='set_language'), path('subject//', views.subject_detail, name='subject_detail'), path('ajax/get-subjects-by-level/', views.get_subjects_by_level, name='get_subjects_by_level'), -] + path('register/', views.register_student, name='register_student'), + path('ajax/get-classroom-subjects/', views.get_classroom_subjects, name='get_classroom_subjects'), + path('profile/', views.profile, name='profile'), + path('logout/', views.custom_logout, name='logout'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index 0113265..665968d 100644 --- a/core/views.py +++ b/core/views.py @@ -3,11 +3,14 @@ from django.utils import translation from django.conf import settings from django.http import JsonResponse from django.contrib.admin.views.decorators import staff_member_required -from .models import EducationalLevel, Subject, Teacher +from django.contrib.auth.decorators import login_required +from django.contrib.auth import logout +from .models import Classroom, Subject, Teacher, Student +from .forms import StudentRegistrationForm def index(request): # Fetch levels with their related subjects using prefetch_related for efficiency - levels = EducationalLevel.objects.prefetch_related('subjects').all() + levels = Classroom.objects.prefetch_related('subjects').all() context = { 'levels': levels, @@ -32,8 +35,41 @@ def subject_detail(request, pk): @staff_member_required def get_subjects_by_level(request): - level_id = request.GET.get('level_id') + level_id = request.GET.get('level_id') or request.GET.get('classroom_id') if not level_id: return JsonResponse([], safe=False) - subjects = Subject.objects.filter(level_id=level_id).values('id', 'name_en', 'name_ar') - return JsonResponse(list(subjects), safe=False) \ No newline at end of file + subjects = Subject.objects.filter(classroom_id=level_id).values('id', 'name_en', 'name_ar') + return JsonResponse(list(subjects), safe=False) + +def get_classroom_subjects(request): + """Public endpoint for registration form""" + classroom_id = request.GET.get('classroom_id') + if not classroom_id: + return JsonResponse([], safe=False) + subjects = Subject.objects.filter(classroom_id=classroom_id).values('id', 'name_en', 'price') + return JsonResponse(list(subjects), safe=False) + +def register_student(request): + if request.method == 'POST': + form = StudentRegistrationForm(request.POST, request.FILES) + if form.is_valid(): + student = form.save() + # Redirect to success page or login + return redirect('index') # Placeholder + else: + form = StudentRegistrationForm() + + return render(request, 'core/registration.html', {'form': form}) + +@login_required +def profile(request): + try: + student_profile = request.user.student_profile + except Student.DoesNotExist: + student_profile = None + + return render(request, 'core/profile.html', {'student_profile': student_profile}) + +def custom_logout(request): + logout(request) + return redirect('index') diff --git a/static/js/admin_resource.js b/static/js/admin_resource.js index c1b837f..514a034 100644 --- a/static/js/admin_resource.js +++ b/static/js/admin_resource.js @@ -2,12 +2,12 @@ 'use strict'; $(function() { console.log("Admin Resource JS loaded"); - var $levelSelect = $('#id_educational_level'); + var $levelSelect = $('#id_classroom'); var $subjectSelect = $('#id_subject'); // Check if elements exist if (!$levelSelect.length) { - console.warn("Educational Level field #id_educational_level not found"); + console.warn("Classroom field #id_classroom not found"); } if (!$subjectSelect.length) { console.warn("Subject field #id_subject not found"); @@ -17,7 +17,7 @@ var isArabic = $('html').attr('lang') === 'ar' || $('body').hasClass('rtl'); function updateSubjects(levelId, currentSubjectId) { - console.log("Updating subjects for level:", levelId); + console.log("Updating subjects for classroom:", levelId); // If no level selected, clear subjects if (!levelId) { $subjectSelect.html(''); diff --git a/static/js/admin_student.js b/static/js/admin_student.js index aa01ef6..143a254 100644 --- a/static/js/admin_student.js +++ b/static/js/admin_student.js @@ -1,7 +1,7 @@ (function($) { 'use strict'; $(function() { - var $levelSelect = $('#id_level'); + var $levelSelect = $('#id_classroom'); var $subjectSelect = $('#id_subscribed_subjects'); // Check if we are in the admin change form if (!$levelSelect.length || !$subjectSelect.length) return; @@ -75,4 +75,4 @@ updateSubjects($levelSelect.val(), selectedValues); } }); -})(django.jQuery); +})(django.jQuery); \ No newline at end of file diff --git a/staticfiles/js/admin_resource.js b/staticfiles/js/admin_resource.js index c1b837f..514a034 100644 --- a/staticfiles/js/admin_resource.js +++ b/staticfiles/js/admin_resource.js @@ -2,12 +2,12 @@ 'use strict'; $(function() { console.log("Admin Resource JS loaded"); - var $levelSelect = $('#id_educational_level'); + var $levelSelect = $('#id_classroom'); var $subjectSelect = $('#id_subject'); // Check if elements exist if (!$levelSelect.length) { - console.warn("Educational Level field #id_educational_level not found"); + console.warn("Classroom field #id_classroom not found"); } if (!$subjectSelect.length) { console.warn("Subject field #id_subject not found"); @@ -17,7 +17,7 @@ var isArabic = $('html').attr('lang') === 'ar' || $('body').hasClass('rtl'); function updateSubjects(levelId, currentSubjectId) { - console.log("Updating subjects for level:", levelId); + console.log("Updating subjects for classroom:", levelId); // If no level selected, clear subjects if (!levelId) { $subjectSelect.html(''); diff --git a/staticfiles/js/admin_student.js b/staticfiles/js/admin_student.js index aa01ef6..143a254 100644 --- a/staticfiles/js/admin_student.js +++ b/staticfiles/js/admin_student.js @@ -1,7 +1,7 @@ (function($) { 'use strict'; $(function() { - var $levelSelect = $('#id_level'); + var $levelSelect = $('#id_classroom'); var $subjectSelect = $('#id_subscribed_subjects'); // Check if we are in the admin change form if (!$levelSelect.length || !$subjectSelect.length) return; @@ -75,4 +75,4 @@ updateSubjects($levelSelect.val(), selectedValues); } }); -})(django.jQuery); +})(django.jQuery); \ No newline at end of file