diff --git a/SMS/settings.py b/SMS/settings.py index 86af760..4b2444b 100644 --- a/SMS/settings.py +++ b/SMS/settings.py @@ -24,7 +24,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'o!ld8nrt4vc*h1zoey*wj48x*q0#ss12h=+zh)kk^6b3aygg=!' +SECRET_KEY = "o!ld8nrt4vc*h1zoey*wj48x*q0#ss12h=+zh)kk^6b3aygg=!" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -32,65 +32,62 @@ DEBUG = True ALLOWED_HOSTS = [] # change the default user models to our custom model -AUTH_USER_MODEL = 'accounts.User' +AUTH_USER_MODEL = "accounts.User" # Application definition DJANGO_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django_cleanup', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", ] # Thired party apps THIRED_PARTY_APPS = [ - 'crispy_forms', - 'rest_framework', - 'channels', + "crispy_forms", + "rest_framework", ] # Custom apps PROJECT_APPS = [ - 'app.apps.AppConfig', - 'accounts.apps.AccountsConfig', - 'course.apps.CourseConfig', - 'result.apps.ResultConfig', - 'search.apps.SearchConfig', - 'quiz.apps.QuizConfig', - 'payments.apps.PaymentsConfig', + "app.apps.AppConfig", + "accounts.apps.AccountsConfig", + "course.apps.CourseConfig", + "result.apps.ResultConfig", + "search.apps.SearchConfig", + "quiz.apps.QuizConfig", + "payments.apps.PaymentsConfig", ] # Combine all apps INSTALLED_APPS = DJANGO_APPS + THIRED_PARTY_APPS + PROJECT_APPS MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'SMS.urls' +ROOT_URLCONF = "SMS.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", # 'django.template.context_processors.i18n', # 'django.template.context_processors.media', # 'django.template.context_processors.static', @@ -100,7 +97,7 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = 'SMS.wsgi.application' +WSGI_APPLICATION = "SMS.wsgi.application" ASGI_APPLICATION = "SMS.asgi.application" @@ -116,16 +113,16 @@ ASGI_APPLICATION = "SMS.asgi.application" # } # ----------------------------- -# NOTE: Some model fields may not work on sqlite db, +# NOTE: Some model fields may not work on sqlite db, # so consider using postgresql instead DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': env('DB_NAME'), - 'USER': env('DB_USER'), - 'PASSWORD': env('DB_PASSWORD'), - 'HOST': env('DB_HOST'), - 'PORT': env('DB_PORT'), + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": env("DB_NAME"), + "USER": env("DB_USER"), + "PASSWORD": env("DB_PASSWORD"), + "HOST": env("DB_HOST"), + "PORT": env("DB_PORT"), } } @@ -137,16 +134,16 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -154,9 +151,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -168,42 +165,44 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] -STATIC_ROOT = posixpath.join(*(BASE_DIR.split(os.path.sep) + ['staticfiles'])) +STATIC_ROOT = posixpath.join(*(BASE_DIR.split(os.path.sep) + ["staticfiles"])) -MEDIA_URL = '/media/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'media') +MEDIA_URL = "/media/" +MEDIA_ROOT = os.path.join(BASE_DIR, "media") # ----------------------------------- # E-mail configuration -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'smtp.gmail.com' # Here i'm using gmail as the email host, but you can change it +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = ( + "smtp.gmail.com" # Here i'm using gmail as the email host, but you can change it +) EMAIL_PORT = 587 EMAIL_USE_TLS = True -EMAIL_HOST_USER = env('USER_EMAIL') -EMAIL_HOST_PASSWORD = env('USER_PASSWORD') +EMAIL_HOST_USER = env("USER_EMAIL") +EMAIL_HOST_PASSWORD = env("USER_PASSWORD") # crispy config -CRISPY_TEMPLATE_PACK = 'bootstrap4' +CRISPY_TEMPLATE_PACK = "bootstrap4" -LOGIN_REDIRECT_URL = '/' -LOGOUT_REDIRECT_URL = '/' +LOGIN_REDIRECT_URL = "/" +LOGOUT_REDIRECT_URL = "/" # DRF setup REST_FRAMEWORK = { - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.IsAuthenticated', + "DEFAULT_PERMISSION_CLASSES": [ + "rest_framework.permissions.IsAuthenticated", + ], + "DEFAULT_AUTHENTICATION_CLASSES": [ + "rest_framework.authentication.SessionAuthentication", + "rest_framework.authentication.BasicAuthentication", ], - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.BasicAuthentication' - ] } # Strip payment config -STRIPE_SECRET_KEY = env('STRIPE_SECRET_KEY') -STRIPE_PUBLISHABLE_KEY = env('STRIPE_PUBLISHABLE_KEY') +STRIPE_SECRET_KEY = env("STRIPE_SECRET_KEY") +STRIPE_PUBLISHABLE_KEY = env("STRIPE_PUBLISHABLE_KEY") diff --git a/accounts/views.py b/accounts/views.py index 7b1a134..89d29f3 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -8,7 +8,11 @@ from django.views.generic import CreateView, ListView from django.core.paginator import Paginator from django.db.models import Q from django.utils.decorators import method_decorator -from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm +from django.contrib.auth.forms import ( + UserCreationForm, + UserChangeForm, + PasswordChangeForm, +) from .decorators import lecturer_required, student_required, admin_required from course.models import Course @@ -20,119 +24,137 @@ from .models import User, Student, Parent def validate_username(request): username = request.GET.get("username", None) - data = { - "is_taken": User.objects.filter(username__iexact = username).exists() - } - return JsonResponse (data) + data = {"is_taken": User.objects.filter(username__iexact=username).exists()} + return JsonResponse(data) def register(request): - if request.method == 'POST': + if request.method == "POST": form = StudentAddForm(request.POST) if form.is_valid(): form.save() - messages.success(request, f'Account created successfuly.') + messages.success(request, f"Account created successfuly.") else: - messages.error(request, f'Somthing is not correct, please fill all fields correctly.') + messages.error( + request, f"Somthing is not correct, please fill all fields correctly." + ) else: form = StudentAddForm(request.POST) - return render(request, "registration/register.html", {'form': form}) + return render(request, "registration/register.html", {"form": form}) @login_required def profile(request): - """ Show profile of any user that fire out the request """ - try: - current_session = get_object_or_404(Session, is_current_session=True) - current_semester = get_object_or_404(Semester, is_current_semester=True, session=current_session) - - except Semester.MultipleObjectsReturned and Semester.DoesNotExist and Session.DoesNotExist: - raise Http404 + """Show profile of any user that fire out the request""" + current_session = Session.objects.filter(is_current_session=True).first() + current_semester = Semester.objects.filter( + is_current_semester=True, session=current_session + ).first() if request.user.is_lecturer: - courses = Course.objects.filter(allocated_course__lecturer__pk=request.user.id).filter( - semester=current_semester) - return render(request, 'accounts/profile.html', { - 'title': request.user.get_full_name, - "courses": courses, - 'current_session': current_session, - 'current_semester': current_semester, - }) + courses = Course.objects.filter( + allocated_course__lecturer__pk=request.user.id + ).filter(semester=current_semester) + return render( + request, + "accounts/profile.html", + { + "title": request.user.get_full_name, + "courses": courses, + "current_session": current_session, + "current_semester": current_semester, + }, + ) elif request.user.is_student: level = Student.objects.get(student__pk=request.user.id) try: parent = Parent.objects.get(student=level) except: parent = "no parent set" - courses = TakenCourse.objects.filter(student__student__id=request.user.id, course__level=level.level) + courses = TakenCourse.objects.filter( + student__student__id=request.user.id, course__level=level.level + ) context = { - 'title': request.user.get_full_name, - 'parent': parent, - 'courses': courses, - 'level': level, - 'current_session': current_session, - 'current_semester': current_semester, + "title": request.user.get_full_name, + "parent": parent, + "courses": courses, + "level": level, + "current_session": current_session, + "current_semester": current_semester, } - return render(request, 'accounts/profile.html', context) + return render(request, "accounts/profile.html", context) else: staff = User.objects.filter(is_lecturer=True) - return render(request, 'accounts/profile.html', { - 'title': request.user.get_full_name, - "staff": staff, - 'current_session': current_session, - 'current_semester': current_semester, - }) + return render( + request, + "accounts/profile.html", + { + "title": request.user.get_full_name, + "staff": staff, + "current_session": current_session, + "current_semester": current_semester, + }, + ) @login_required @admin_required def profile_single(request, id): - """ Show profile of any selected user """ + """Show profile of any selected user""" if request.user.id == id: return redirect("/profile/") - current_session = get_object_or_404(Session, is_current_session=True) - current_semester = get_object_or_404(Semester, is_current_semester=True, session=current_session) + current_session = Session.objects.filter(is_current_session=True).first() + current_semester = Semester.objects.filter( + is_current_semester=True, session=current_session + ).first() + user = User.objects.get(pk=id) if user.is_lecturer: - courses = Course.objects.filter(allocated_course__lecturer__pk=id).filter(semester=current_semester) + courses = Course.objects.filter(allocated_course__lecturer__pk=id).filter( + semester=current_semester + ) context = { - 'title': user.get_full_name, + "title": user.get_full_name, "user": user, "user_type": "Lecturer", "courses": courses, - 'current_session': current_session, - 'current_semester': current_semester, + "current_session": current_session, + "current_semester": current_semester, } - return render(request, 'accounts/profile_single.html', context) + return render(request, "accounts/profile_single.html", context) elif user.is_student: student = Student.objects.get(student__pk=id) - courses = TakenCourse.objects.filter(student__student__id=id, course__level=student.level) + courses = TakenCourse.objects.filter( + student__student__id=id, course__level=student.level + ) context = { - 'title': user.get_full_name, - 'user': user, + "title": user.get_full_name, + "user": user, "user_type": "student", - 'courses': courses, - 'student': student, - 'current_session': current_session, - 'current_semester': current_semester, + "courses": courses, + "student": student, + "current_session": current_session, + "current_semester": current_semester, } - return render(request, 'accounts/profile_single.html', context) + return render(request, "accounts/profile_single.html", context) else: context = { - 'title': user.get_full_name, + "title": user.get_full_name, "user": user, "user_type": "superuser", - 'current_session': current_session, - 'current_semester': current_semester, + "current_session": current_session, + "current_semester": current_semester, } - return render(request, 'accounts/profile_single.html', context) + return render(request, "accounts/profile_single.html", context) @login_required @admin_required def admin_panel(request): - return render(request, 'setting/admin_panel.html', {}) + return render(request, "setting/admin_panel.html", {}) + + # ######################################################## @@ -141,85 +163,107 @@ def admin_panel(request): # ######################################################## @login_required def profile_update(request): - if request.method == 'POST': + if request.method == "POST": form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user) if form.is_valid(): form.save() - messages.success(request, 'Your profile has been updated successfully.') - return redirect('profile') + messages.success(request, "Your profile has been updated successfully.") + return redirect("profile") else: - messages.error(request, 'Please correct the error(s) below.') + messages.error(request, "Please correct the error(s) below.") else: form = ProfileUpdateForm(instance=request.user) - return render(request, 'setting/profile_info_change.html', { - 'title': 'Setting | DjangoSMS', - 'form': form, - }) + return render( + request, + "setting/profile_info_change.html", + { + "title": "Setting | DjangoSMS", + "form": form, + }, + ) @login_required def change_password(request): - if request.method == 'POST': + if request.method == "POST": form = PasswordChangeForm(request.user, request.POST) if form.is_valid(): user = form.save() update_session_auth_hash(request, user) - messages.success(request, 'Your password was successfully updated!') - return redirect('profile') + messages.success(request, "Your password was successfully updated!") + return redirect("profile") else: - messages.error(request, 'Please correct the error(s) below. ') + messages.error(request, "Please correct the error(s) below. ") else: form = PasswordChangeForm(request.user) - return render(request, 'setting/password_change.html', { - 'form': form, - }) + return render( + request, + "setting/password_change.html", + { + "form": form, + }, + ) + + # ######################################################## + @login_required @admin_required def staff_add_view(request): - if request.method == 'POST': + if request.method == "POST": form = StaffAddForm(request.POST) - first_name = request.POST.get('first_name') - last_name = request.POST.get('last_name') + first_name = request.POST.get("first_name") + last_name = request.POST.get("last_name") if form.is_valid(): form.save() - messages.success(request, "Account for lecturer " + first_name + ' ' + last_name + " has been created.") + messages.success( + request, + "Account for lecturer " + + first_name + + " " + + last_name + + " has been created.", + ) return redirect("lecturer_list") else: form = StaffAddForm() context = { - 'title': 'Lecturer Add | DjangoSMS', - 'form': form, + "title": "Lecturer Add | DjangoSMS", + "form": form, } - return render(request, 'accounts/add_staff.html', context) + return render(request, "accounts/add_staff.html", context) @login_required @admin_required def edit_staff(request, pk): instance = get_object_or_404(User, is_lecturer=True, pk=pk) - if request.method == 'POST': + if request.method == "POST": form = ProfileUpdateForm(request.POST, request.FILES, instance=instance) full_name = instance.get_full_name if form.is_valid(): form.save() - messages.success(request, 'Lecturer ' + full_name + ' has been updated.') - return redirect('lecturer_list') + messages.success(request, "Lecturer " + full_name + " has been updated.") + return redirect("lecturer_list") else: - messages.error(request, 'Please correct the error below.') + messages.error(request, "Please correct the error below.") else: form = ProfileUpdateForm(instance=instance) - return render(request, 'accounts/edit_lecturer.html', { - 'title': 'Edit Lecturer | DjangoSMS', - 'form': form, - }) + return render( + request, + "accounts/edit_lecturer.html", + { + "title": "Edit Lecturer | DjangoSMS", + "form": form, + }, + ) -@method_decorator([login_required, admin_required], name='dispatch') +@method_decorator([login_required, admin_required], name="dispatch") class LecturerListView(ListView): queryset = User.objects.filter(is_lecturer=True) template_name = "accounts/lecturer_list.html" @@ -227,7 +271,7 @@ class LecturerListView(ListView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['title'] = "Lecturers | DjangoSMS" + context["title"] = "Lecturers | DjangoSMS" return context @@ -238,14 +282,17 @@ class LecturerListView(ListView): # staff.delete() # return redirect('lecturer_list') + @login_required @admin_required def delete_staff(request, pk): lecturer = get_object_or_404(User, pk=pk) full_name = lecturer.get_full_name lecturer.delete() - messages.success(request, 'Lecturer ' + full_name + ' has been deleted.') - return redirect('lecturer_list') + messages.success(request, "Lecturer " + full_name + " has been deleted.") + return redirect("lecturer_list") + + # ######################################################## @@ -255,23 +302,27 @@ def delete_staff(request, pk): @login_required @admin_required def student_add_view(request): - if request.method == 'POST': + if request.method == "POST": form = StudentAddForm(request.POST) - first_name = request.POST.get('first_name') - last_name = request.POST.get('last_name') + first_name = request.POST.get("first_name") + last_name = request.POST.get("last_name") if form.is_valid(): form.save() - messages.success(request, 'Account for ' + first_name + ' ' + last_name + ' has been created.') - return redirect('student_list') + messages.success( + request, + "Account for " + first_name + " " + last_name + " has been created.", + ) + return redirect("student_list") else: - messages.error(request, 'Correct the error(s) below.') + messages.error(request, "Correct the error(s) below.") else: form = StudentAddForm() - return render(request, 'accounts/add_student.html', { - 'title': "Add Student | DjangoSMS", - 'form': form - }) + return render( + request, + "accounts/add_student.html", + {"title": "Add Student | DjangoSMS", "form": form}, + ) @login_required @@ -279,39 +330,43 @@ def student_add_view(request): def edit_student(request, pk): # instance = User.objects.get(pk=pk) instance = get_object_or_404(User, is_student=True, pk=pk) - if request.method == 'POST': + if request.method == "POST": form = ProfileUpdateForm(request.POST, request.FILES, instance=instance) full_name = instance.get_full_name if form.is_valid(): form.save() - messages.success(request, ('Student ' + full_name + ' has been updated.')) - return redirect('student_list') + messages.success(request, ("Student " + full_name + " has been updated.")) + return redirect("student_list") else: - messages.error(request, 'Please correct the error below.') + messages.error(request, "Please correct the error below.") else: form = ProfileUpdateForm(instance=instance) - return render(request, 'accounts/edit_student.html', { - 'title': 'Edit-profile | DjangoSMS', - 'form': form, - }) + return render( + request, + "accounts/edit_student.html", + { + "title": "Edit-profile | DjangoSMS", + "form": form, + }, + ) -@method_decorator([login_required, admin_required], name='dispatch') +@method_decorator([login_required, admin_required], name="dispatch") class StudentListView(ListView): template_name = "accounts/student_list.html" paginate_by = 10 # if pagination is desired def get_queryset(self): queryset = Student.objects.all() - query = self.request.GET.get('student_id') + query = self.request.GET.get("student_id") if query is not None: queryset = queryset.filter(Q(department=query)) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['title'] = "Students | DjangoSMS" + context["title"] = "Students | DjangoSMS" return context @@ -321,15 +376,17 @@ def delete_student(request, pk): student = get_object_or_404(Student, pk=pk) # full_name = student.user.get_full_name student.delete() - messages.success(request, 'Student has been deleted.') - return redirect('student_list') + messages.success(request, "Student has been deleted.") + return redirect("student_list") + + # ######################################################## class ParentAdd(CreateView): model = Parent form_class = ParentAddForm - template_name = 'accounts/parent_form.html' + template_name = "accounts/parent_form.html" # def parent_add(request): diff --git a/requirements/base.txt b/requirements/base.txt index df5baf2..5331557 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -21,3 +21,7 @@ djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework django-cors-headers==3.13.0 # https://github.com/adamchainz/django-cors-headers # DRF-spectacular for api documentation drf-spectacular==0.25.1 # https://github.com/tfranzel/drf-spectacular + +reportlab==4.0.4 +stripe==5.5.0 +gopay==2.0.1 diff --git a/templates/accounts/profile.html b/templates/accounts/profile.html index bfbb00f..014df2b 100644 --- a/templates/accounts/profile.html +++ b/templates/accounts/profile.html @@ -11,24 +11,24 @@
Home {{ user.get_full_name }}
{% if messages %} - {% for message in messages %} - {% if message.tags == 'error' %} -
- {{ message }} -
- {% else %} -
- {{ message }} -
- {% endif %} - {% endfor %} +{% for message in messages %} +{% if message.tags == 'error' %} +
+ {{ message }} +
+{% else %} +
+ {{ message }} +
+{% endif %} +{% endfor %} {% endif %}
Edit Profile - Change password + Change password
@@ -67,13 +67,13 @@

My Courses

{% if courses %} -
- {% for course in courses %} - - {% endfor %} -
+
+ {% for course in courses %} + + {% endfor %} +
{% else %} -
No courses!
+
No courses!
{% endif %}
{% endif %} @@ -91,18 +91,20 @@

Level: {{ level.level }}

{% endif %} - +

Contact Info

Email: {{ user.email }}

Tel No.: {{ user.phone }}

Address/city: {{ user.address }}

- +

Important Dates

Last login: {{ user.last_login }}

+ {% if current_semester and current_session %}

Academic Year: {{ current_semester }} Semester {{ current_session }}

+ {% endif %}

Registered Date: {{ user.date_joined|date }}

@@ -113,4 +115,4 @@ {% endif %} -{% endblock content %} +{% endblock content %} \ No newline at end of file diff --git a/templates/accounts/profile_single.html b/templates/accounts/profile_single.html index 0aa43d4..fe06258 100644 --- a/templates/accounts/profile_single.html +++ b/templates/accounts/profile_single.html @@ -7,17 +7,17 @@
Home {{ user.get_full_name }}
{% if messages %} - {% for message in messages %} - {% if message.tags == 'error' %} -
- {{ message }} -
- {% else %} -
- {{ message }} -
- {% endif %} - {% endfor %} +{% for message in messages %} +{% if message.tags == 'error' %} +
+ {{ message }} +
+{% else %} +
+ {{ message }} +
+{% endif %} +{% endfor %} {% endif %} {% if request.user.is_superuser %} @@ -59,17 +59,17 @@

My Courses

{% if courses %} -
- {% for course in courses %} - - {% endfor %} -
+
+ {% for course in courses %} + + {% endfor %} +
{% else %} -
No courses!
+
No courses!
{% endif %}
{% endif %} - +

Personal Info

First Name: {{ user.first_name|title }}

@@ -84,18 +84,20 @@

Level: {{ student.level }}

{% endif %} - +

Contact Info

Email: {{ user.email }}

Tel No.: {{ user.phone }}

Address/city: {{ user.address }}

- +

Important Dates

Last login: {{ user.last_login }}

+ {% if current_semester and current_session %}

Academic Year: {{ current_semester }} Semester {{ current_session }}

+ {% endif %}

Registered Date: {{ user.date_joined|date }}

@@ -104,4 +106,4 @@
-{% endblock content %} +{% endblock content %} \ No newline at end of file