Resolve lint warnings

This commit is contained in:
papi 2023-12-26 00:25:09 +03:00
parent ca47cbf8c7
commit 11154d2fd1
41 changed files with 1878 additions and 1127 deletions

View File

@ -5,13 +5,31 @@ from .models import User, Student, Parent
class UserAdmin(admin.ModelAdmin):
list_display = ['get_full_name', 'username', 'email', 'is_active', 'is_student', 'is_lecturer', 'is_parent', 'is_staff']
search_fields = ['username', 'first_name', 'last_name', 'email', 'is_active', 'is_lecturer', 'is_parent', 'is_staff']
list_display = [
"get_full_name",
"username",
"email",
"is_active",
"is_student",
"is_lecturer",
"is_parent",
"is_staff",
]
search_fields = [
"username",
"first_name",
"last_name",
"email",
"is_active",
"is_lecturer",
"is_parent",
"is_staff",
]
class Meta:
managed = True
verbose_name = 'User'
verbose_name_plural = 'Users'
verbose_name = "User"
verbose_name_plural = "Users"
# class ScoreAdmin(admin.ModelAdmin):

View File

@ -1,10 +1,8 @@
from rest_framework import serializers
from django.contrib.auth.views import get_user_model
User = get_user_model()
from django.contrib.auth import get_user_model
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
model = get_user_model()
fields = "__all__"

View File

@ -1,9 +1,8 @@
from . import views
from django.urls import path
from . import views
app_name = "accounts-api"
urlpatterns = [
path('', views.UserListAPIView.as_view(), name="users-api"),
path("", views.UserListAPIView.as_view(), name="users-api"),
]

View File

@ -1,24 +1,23 @@
from rest_framework import generics
from django.contrib.auth.views import get_user_model
from django.contrib.auth import get_user_model
from .serializers import UserSerializer
User = get_user_model()
class UserListAPIView(generics.ListAPIView):
lookup_field = 'id'
lookup_field = "id"
serializer_class = UserSerializer
def get_queryset(self):
qs = User.objects.all()
q = self.request.GET.get('q')
qs = get_user_model().objects.all()
q = self.request.GET.get("q")
if q is not None:
qs = qs.filter(username__iexact=q)
return qs
class UserDetailView(generics.RetrieveAPIView):
lookup_field = 'id'
User = get_user_model()
lookup_field = "id"
queryset = User.objects.all()
model = User

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
name = "accounts"

View File

@ -3,7 +3,9 @@ from django.http import Http404
from django.contrib.auth.decorators import user_passes_test
def student_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404):
def student_required(
function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404
):
"""
Decorator for views that checks that the logged in user is a student,
redirects to the log-in page if necessary.
@ -11,14 +13,16 @@ def student_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, log
actual_decorator = user_passes_test(
lambda u: u.is_active and u.is_student or u.is_superuser,
login_url=login_url,
redirect_field_name=redirect_field_name
redirect_field_name=redirect_field_name,
)
if function:
return actual_decorator(function)
return actual_decorator
def lecturer_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404):
def lecturer_required(
function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404
):
"""
Decorator for views that checks that the logged in user is a teacher,
redirects to the log-in page if necessary.
@ -26,14 +30,16 @@ def lecturer_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, lo
actual_decorator = user_passes_test(
lambda u: u.is_active and u.is_lecturer or u.is_superuser,
login_url=login_url,
redirect_field_name=redirect_field_name
redirect_field_name=redirect_field_name,
)
if function:
return actual_decorator(function)
return actual_decorator
def admin_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404):
def admin_required(
function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=Http404
):
"""
Decorator for views that checks that the logged in user is a teacher,
redirects to the log-in page if necessary.
@ -41,7 +47,7 @@ def admin_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login
actual_decorator = user_passes_test(
lambda u: u.is_active and u.is_superuser,
login_url=login_url,
redirect_field_name=redirect_field_name
redirect_field_name=redirect_field_name,
)
if function:
return actual_decorator(function)

View File

@ -1,82 +1,59 @@
from django import forms
from django.db import transaction
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm
from django.contrib.auth.forms import (
UserCreationForm,
UserChangeForm,
)
# from django.contrib.auth.models import User
from django.contrib.auth.forms import PasswordResetForm
from course.models import Program
# from .models import User, Student, LEVEL
from .models import *
class StaffAddForm(UserCreationForm):
username = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Username", )
first_name = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="First Name", )
last_name = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Last Name", )
address = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Address", )
phone = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Mobile No.", )
email = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Email", )
password1 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password", )
password2 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password Confirmation", )
class Meta(UserCreationForm.Meta):
model = User
@transaction.atomic()
def save(self, commit=True):
user = super().save(commit=False)
user.is_lecturer = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.phone = self.cleaned_data.get('phone')
user.address = self.cleaned_data.get('address')
user.email = self.cleaned_data.get('email')
if commit:
user.save()
return user
class StudentAddForm(UserCreationForm):
username = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
'id': 'username_id'
"type": "text",
"class": "form-control",
}
),
label="Username",
)
first_name = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="First Name",
)
last_name = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Last Name",
)
address = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Address",
@ -86,8 +63,88 @@ class StudentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Mobile No.",
)
email = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Email",
)
password1 = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password",
)
password2 = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password Confirmation",
)
class Meta(UserCreationForm.Meta):
model = User
@transaction.atomic()
def save(self, commit=True):
user = super().save(commit=False)
user.is_lecturer = True
user.first_name = self.cleaned_data.get("first_name")
user.last_name = self.cleaned_data.get("last_name")
user.phone = self.cleaned_data.get("phone")
user.address = self.cleaned_data.get("address")
user.email = self.cleaned_data.get("email")
if commit:
user.save()
return user
class StudentAddForm(UserCreationForm):
username = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={"type": "text", "class": "form-control", "id": "username_id"}
),
label="Username",
)
address = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Address",
)
phone = forms.CharField(
max_length=30,
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Mobile No.",
@ -97,8 +154,8 @@ class StudentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="First name",
@ -108,8 +165,8 @@ class StudentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Last name",
@ -119,34 +176,50 @@ class StudentAddForm(UserCreationForm):
widget=forms.Select(
choices=LEVEL,
attrs={
'class': 'browser-default custom-select form-control',
}
"class": "browser-default custom-select form-control",
},
),
)
department = forms.ModelChoiceField(
queryset=Program.objects.all(),
widget=forms.Select(attrs={'class': 'browser-default custom-select form-control'}),
widget=forms.Select(
attrs={"class": "browser-default custom-select form-control"}
),
label="Department",
)
email = forms.EmailField(
widget=forms.TextInput(
attrs={
'type': 'email',
'class': 'form-control',
"type": "email",
"class": "form-control",
}
),
label="Email Address",
)
password1 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password", )
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password",
)
password2 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password Confirmation", )
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password Confirmation",
)
# def validate_email(self):
# email = self.cleaned_data['email']
@ -160,16 +233,16 @@ class StudentAddForm(UserCreationForm):
def save(self):
user = super().save(commit=False)
user.is_student = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.address = self.cleaned_data.get('address')
user.phone = self.cleaned_data.get('phone')
user.email = self.cleaned_data.get('email')
user.first_name = self.cleaned_data.get("first_name")
user.last_name = self.cleaned_data.get("last_name")
user.address = self.cleaned_data.get("address")
user.phone = self.cleaned_data.get("phone")
user.email = self.cleaned_data.get("email")
user.save()
student = Student.objects.create(
student=user,
level=self.cleaned_data.get('level'),
department=self.cleaned_data.get('department')
level=self.cleaned_data.get("level"),
department=self.cleaned_data.get("department"),
)
student.save()
return user
@ -177,36 +250,66 @@ class StudentAddForm(UserCreationForm):
class ProfileUpdateForm(UserChangeForm):
email = forms.EmailField(
widget=forms.TextInput(attrs={'type': 'email', 'class': 'form-control', }),
label="Email Address", )
widget=forms.TextInput(
attrs={
"type": "email",
"class": "form-control",
}
),
label="Email Address",
)
first_name = forms.CharField(
widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="First Name", )
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="First Name",
)
last_name = forms.CharField(
widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Last Name", )
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Last Name",
)
phone = forms.CharField(
widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Phone No.", )
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Phone No.",
)
address = forms.CharField(
widget=forms.TextInput(attrs={'type': 'text', 'class': 'form-control', }),
label="Address / city", )
widget=forms.TextInput(
attrs={
"type": "text",
"class": "form-control",
}
),
label="Address / city",
)
class Meta:
model = User
fields = ['email', 'phone', 'address', 'picture', 'first_name', 'last_name']
fields = ["email", "phone", "address", "picture", "first_name", "last_name"]
class EmailValidationOnForgotPassword(PasswordResetForm):
def clean_email(self):
email = self.cleaned_data['email']
email = self.cleaned_data["email"]
if not User.objects.filter(email__iexact=email, is_active=True).exists():
msg = "There is no user registered with the specified E-mail address. "
self.add_error('email', msg)
self.add_error("email", msg)
return email
@ -215,8 +318,8 @@ class ParentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Username",
@ -225,8 +328,8 @@ class ParentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Address",
@ -236,8 +339,8 @@ class ParentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Mobile No.",
@ -247,8 +350,8 @@ class ParentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="First name",
@ -258,8 +361,8 @@ class ParentAddForm(UserCreationForm):
max_length=30,
widget=forms.TextInput(
attrs={
'type': 'text',
'class': 'form-control',
"type": "text",
"class": "form-control",
}
),
label="Last name",
@ -268,8 +371,8 @@ class ParentAddForm(UserCreationForm):
email = forms.EmailField(
widget=forms.TextInput(
attrs={
'type': 'email',
'class': 'form-control',
"type": "email",
"class": "form-control",
}
),
label="Email Address",
@ -277,24 +380,42 @@ class ParentAddForm(UserCreationForm):
student = forms.ModelChoiceField(
queryset=Student.objects.all(),
widget=forms.Select(attrs={'class': 'browser-default custom-select form-control'}),
widget=forms.Select(
attrs={"class": "browser-default custom-select form-control"}
),
label="Student",
)
relation_ship = forms.CharField(
widget=forms.Select(
choices=RELATION_SHIP,
attrs={'class': 'browser-default custom-select form-control',}
attrs={
"class": "browser-default custom-select form-control",
},
),
)
password1 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password", )
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password",
)
password2 = forms.CharField(
max_length=30, widget=forms.TextInput(attrs={'type': 'password', 'class': 'form-control', }),
label="Password Confirmation", )
max_length=30,
widget=forms.TextInput(
attrs={
"type": "password",
"class": "form-control",
}
),
label="Password Confirmation",
)
# def validate_email(self):
# email = self.cleaned_data['email']
@ -308,16 +429,16 @@ class ParentAddForm(UserCreationForm):
def save(self):
user = super().save(commit=False)
user.is_parent = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.address = self.cleaned_data.get('address')
user.phone = self.cleaned_data.get('phone')
user.email = self.cleaned_data.get('email')
user.first_name = self.cleaned_data.get("first_name")
user.last_name = self.cleaned_data.get("last_name")
user.address = self.cleaned_data.get("address")
user.phone = self.cleaned_data.get("phone")
user.email = self.cleaned_data.get("email")
user.save()
parent = Parent.objects.create(
user=user,
student=self.cleaned_data.get('student'),
relation_ship=self.cleaned_data.get('relation_ship')
student=self.cleaned_data.get("student"),
relation_ship=self.cleaned_data.get("relation_ship"),
)
parent.save()
return user

View File

@ -28,7 +28,7 @@ GRAND_MOTHER = "Grand mother"
GRAND_FATHER = "Grand father"
OTHER = "Other"
RELATION_SHIP = (
RELATION_SHIP = (
(FATHER, "Father"),
(MOTHER, "Mother"),
(BROTHER, "Brother"),
@ -38,16 +38,20 @@ RELATION_SHIP = (
(OTHER, "Other"),
)
class UserManager(UserManager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (Q(username__icontains=query) |
Q(first_name__icontains=query)|
Q(last_name__icontains=query)|
Q(email__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
or_lookup = (
Q(username__icontains=query)
| Q(first_name__icontains=query)
| Q(last_name__icontains=query)
| Q(email__icontains=query)
)
qs = qs.filter(
or_lookup
).distinct() # distinct() is often necessary with Q lookups
return qs
@ -58,7 +62,9 @@ class User(AbstractUser):
is_dep_head = models.BooleanField(default=False)
phone = models.CharField(max_length=60, blank=True, null=True)
address = models.CharField(max_length=60, blank=True, null=True)
picture = models.ImageField(upload_to='profile_pictures/%y/%m/%d/', default='default.png', null=True)
picture = models.ImageField(
upload_to="profile_pictures/%y/%m/%d/", default="default.png", null=True
)
email = models.EmailField(blank=True, null=True)
username_validator = ASCIIUsernameValidator()
@ -73,7 +79,7 @@ class User(AbstractUser):
return full_name
def __str__(self):
return '{} ({})'.format(self.username, self.get_full_name)
return "{} ({})".format(self.username, self.get_full_name)
@property
def get_user_role(self):
@ -90,11 +96,11 @@ class User(AbstractUser):
try:
return self.picture.url
except:
no_picture = settings.MEDIA_URL + 'default.png'
no_picture = settings.MEDIA_URL + "default.png"
return no_picture
def get_absolute_url(self):
return reverse('profile_single', kwargs={'id': self.id})
return reverse("profile_single", kwargs={"id": self.id})
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
@ -108,7 +114,7 @@ class User(AbstractUser):
pass
def delete(self, *args, **kwargs):
if self.picture.url != settings.MEDIA_URL + 'default.png':
if self.picture.url != settings.MEDIA_URL + "default.png":
self.picture.delete()
super().delete(*args, **kwargs)
@ -117,10 +123,10 @@ class StudentManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (Q(level__icontains=query) |
Q(department__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
or_lookup = Q(level__icontains=query) | Q(department__icontains=query)
qs = qs.filter(
or_lookup
).distinct() # distinct() is often necessary with Q lookups
return qs
@ -136,7 +142,7 @@ class Student(models.Model):
return self.student.get_full_name
def get_absolute_url(self):
return reverse('profile_single', kwargs={'id': self.id})
return reverse("profile_single", kwargs={"id": self.id})
def delete(self, *args, **kwargs):
self.student.delete()
@ -148,6 +154,7 @@ class Parent(models.Model):
Connect student with their parent, parents can
only view their connected students information
"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
student = models.OneToOneField(Student, null=True, on_delete=models.SET_NULL)
first_name = models.CharField(max_length=120)

View File

@ -1,57 +1,59 @@
from django.urls import path, include
from django.contrib.auth.views import (
PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView,
PasswordResetCompleteView, LoginView, LogoutView
)
PasswordResetView,
PasswordResetDoneView,
PasswordResetConfirmView,
PasswordResetCompleteView,
LoginView,
LogoutView,
)
from .views import (
profile, profile_single, admin_panel,
profile_update, change_password,
LecturerListView, StudentListView,
staff_add_view, edit_staff,
delete_staff, student_add_view,
edit_student, delete_student, ParentAdd, validate_username, register
)
profile,
profile_single,
admin_panel,
profile_update,
change_password,
LecturerListView,
StudentListView,
staff_add_view,
edit_staff,
delete_staff,
student_add_view,
edit_student,
delete_student,
ParentAdd,
validate_username,
register,
)
from .forms import EmailValidationOnForgotPassword
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('admin_panel/', admin_panel, name='admin_panel'),
path('profile/', profile, name='profile'),
path('profile/<int:id>/detail/', profile_single, name='profile_single'),
path('setting/', profile_update, name='edit_profile'),
path('change_password/', change_password, name='change_password'),
path('lecturers/', LecturerListView.as_view(), name='lecturer_list'),
path('lecturer/add/', staff_add_view, name='add_lecturer'),
path('staff/<int:pk>/edit/', edit_staff, name='staff_edit'),
path('lecturers/<int:pk>/delete/', delete_staff, name='lecturer_delete'),
path('students/', StudentListView.as_view(), name='student_list'),
path('student/add/', student_add_view, name='add_student'),
path('student/<int:pk>/edit/', edit_student, name='student_edit'),
path('students/<int:pk>/delete/', delete_student, name='student_delete'),
path('parents/add/', ParentAdd.as_view(), name='add_parent'),
path('ajax/validate-username/', validate_username, name='validate_username'),
path('register/', register, name='register'),
path("", include("django.contrib.auth.urls")),
path("admin_panel/", admin_panel, name="admin_panel"),
path("profile/", profile, name="profile"),
path("profile/<int:id>/detail/", profile_single, name="profile_single"),
path("setting/", profile_update, name="edit_profile"),
path("change_password/", change_password, name="change_password"),
path("lecturers/", LecturerListView.as_view(), name="lecturer_list"),
path("lecturer/add/", staff_add_view, name="add_lecturer"),
path("staff/<int:pk>/edit/", edit_staff, name="staff_edit"),
path("lecturers/<int:pk>/delete/", delete_staff, name="lecturer_delete"),
path("students/", StudentListView.as_view(), name="student_list"),
path("student/add/", student_add_view, name="add_student"),
path("student/<int:pk>/edit/", edit_student, name="student_edit"),
path("students/<int:pk>/delete/", delete_student, name="student_delete"),
path("parents/add/", ParentAdd.as_view(), name="add_parent"),
path("ajax/validate-username/", validate_username, name="validate_username"),
path("register/", register, name="register"),
# path('add-student/', StudentAddView.as_view(), name='add_student'),
# path('programs/course/delete/<int:pk>/', course_delete, name='delete_course'),
# Setting urls
# path('profile/<int:pk>/edit/', profileUpdateView, name='edit_profile'),
# path('profile/<int:pk>/change-password/', changePasswordView, name='change_password'),
# ################################################################
# path('login/', LoginView.as_view(), name='login'),
# path('logout/', LogoutView.as_view(), name='logout', kwargs={'next_page': '/'}),
# path('password-reset/', PasswordResetView.as_view(
# form_class=EmailValidationOnForgotPassword,
# template_name='registration/password_reset.html'

View File

@ -7,9 +7,9 @@ from django.utils.translation import gettext_lazy as _
@deconstructible
class ASCIIUsernameValidator(validators.RegexValidator):
regex = r'^[a-zA-Z]+\/(...)\/(....)'
regex = r"^[a-zA-Z]+\/(...)\/(....)"
message = _(
'Enter a valid username. This value may contain only English letters, '
'numbers, and @/./+/-/_ characters.'
"Enter a valid username. This value may contain only English letters, "
"numbers, and @/./+/-/_ characters."
)
flags = re.ASCII

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class AppConfig(AppConfig):
name = 'app'
name = "app"

View File

@ -8,27 +8,32 @@ from .models import NewsAndEvents, Session, Semester, SEMESTER
class NewsAndEventsForm(forms.ModelForm):
class Meta:
model = NewsAndEvents
fields = ('title', 'summary', 'posted_as',)
fields = (
"title",
"summary",
"posted_as",
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['summary'].widget.attrs.update({'class': 'form-control'})
self.fields['posted_as'].widget.attrs.update({'class': 'form-control'})
self.fields["title"].widget.attrs.update({"class": "form-control"})
self.fields["summary"].widget.attrs.update({"class": "form-control"})
self.fields["posted_as"].widget.attrs.update({"class": "form-control"})
class SessionForm(forms.ModelForm):
next_session_begins = forms.DateTimeField(
widget=forms.TextInput(
attrs={
'type': 'date',
"type": "date",
}
),
required=True)
required=True,
)
class Meta:
model = Session
fields = ['session', 'is_current_session', 'next_session_begins']
fields = ["session", "is_current_session", "next_session_begins"]
class SemesterForm(forms.ModelForm):
@ -36,17 +41,17 @@ class SemesterForm(forms.ModelForm):
widget=forms.Select(
choices=SEMESTER,
attrs={
'class': 'browser-default custom-select',
}
"class": "browser-default custom-select",
},
),
label="semester",
)
is_current_semester = forms.CharField(
widget=forms.Select(
choices=((True, 'Yes'), (False, 'No')),
choices=((True, "Yes"), (False, "No")),
attrs={
'class': 'browser-default custom-select',
}
"class": "browser-default custom-select",
},
),
label="is current semester ?",
)
@ -54,21 +59,22 @@ class SemesterForm(forms.ModelForm):
queryset=Session.objects.all(),
widget=forms.Select(
attrs={
'class': 'browser-default custom-select',
"class": "browser-default custom-select",
}
),
required=True
required=True,
)
next_semester_begins = forms.DateTimeField(
widget=forms.TextInput(
attrs={
'type': 'date',
'class': 'form-control',
"type": "date",
"class": "form-control",
}
),
required=True)
required=True,
)
class Meta:
model = Semester
fields = ['semester', 'is_current_semester', 'session', 'next_semester_begins']
fields = ["semester", "is_current_semester", "session", "next_semester_begins"]

View File

@ -24,12 +24,12 @@ SEMESTER = (
class NewsAndEventsQuerySet(models.query.QuerySet):
def search(self, query):
lookups = (Q(title__icontains=query) |
Q(summary__icontains=query) |
Q(posted_as__icontains=query)
)
lookups = (
Q(title__icontains=query)
| Q(summary__icontains=query)
| Q(posted_as__icontains=query)
)
return self.filter(lookups).distinct()
@ -41,7 +41,9 @@ class NewsAndEventsManager(models.Manager):
return self.get_queryset()
def get_by_id(self, id):
qs = self.get_queryset().filter(id=id) # NewsAndEvents.objects == self.get_queryset()
qs = self.get_queryset().filter(
id=id
) # NewsAndEvents.objects == self.get_queryset()
if qs.count() == 1:
return qs.first()
return None
@ -75,7 +77,9 @@ class Session(models.Model):
class Semester(models.Model):
semester = models.CharField(max_length=10, choices=SEMESTER, blank=True)
is_current_semester = models.BooleanField(default=False, blank=True, null=True)
session = models.ForeignKey(Session, on_delete=models.CASCADE, blank=True, null=True)
session = models.ForeignKey(
Session, on_delete=models.CASCADE, blank=True, null=True
)
next_semester_begins = models.DateField(null=True, blank=True)
def __str__(self):

View File

@ -1,29 +1,35 @@
from django.urls import path
from .views import (
home_view, post_add, edit_post, delete_post,
session_list_view, session_add_view, session_update_view, session_delete_view,
semester_list_view, semester_add_view, semester_update_view, semester_delete_view,
dashboard_view
home_view,
post_add,
edit_post,
delete_post,
session_list_view,
session_add_view,
session_update_view,
session_delete_view,
semester_list_view,
semester_add_view,
semester_update_view,
semester_delete_view,
dashboard_view,
)
urlpatterns = [
# Accounts url
path('', home_view, name='home'),
path('add_item/', post_add, name='add_item'),
path('item/<int:pk>/edit/', edit_post, name='edit_post'),
path('item/<int:pk>/delete/', delete_post, name='delete_post'),
path('session/', session_list_view, name="session_list"),
path('session/add/', session_add_view, name="add_session"),
path('session/<int:pk>/edit/', session_update_view, name="edit_session"),
path('session/<int:pk>/delete/', session_delete_view, name="delete_session"),
path('semester/', semester_list_view, name="semester_list"),
path('semester/add/', semester_add_view, name="add_semester"),
path('semester/<int:pk>/edit/', semester_update_view, name="edit_semester"),
path('semester/<int:pk>/delete/', semester_delete_view, name="delete_semester"),
path('dashboard/', dashboard_view, name="dashboard"),
path("", home_view, name="home"),
path("add_item/", post_add, name="add_item"),
path("item/<int:pk>/edit/", edit_post, name="edit_post"),
path("item/<int:pk>/delete/", delete_post, name="delete_post"),
path("session/", session_list_view, name="session_list"),
path("session/add/", session_add_view, name="add_session"),
path("session/<int:pk>/edit/", session_update_view, name="edit_session"),
path("session/<int:pk>/delete/", session_delete_view, name="delete_session"),
path("semester/", semester_list_view, name="semester_list"),
path("semester/add/", semester_add_view, name="add_semester"),
path("semester/<int:pk>/edit/", semester_update_view, name="edit_semester"),
path("semester/<int:pk>/delete/", semester_delete_view, name="delete_semester"),
path("dashboard/", dashboard_view, name="dashboard"),
]

View File

@ -13,54 +13,62 @@ from .models import *
# ########################################################
@login_required
def home_view(request):
items = NewsAndEvents.objects.all().order_by('-updated_date')
items = NewsAndEvents.objects.all().order_by("-updated_date")
context = {
'title': "News & Events | DjangoSMS",
'items': items,
"title": "News & Events | DjangoSMS",
"items": items,
}
return render(request, 'app/index.html', context)
return render(request, "app/index.html", context)
@login_required
def post_add(request):
if request.method == 'POST':
if request.method == "POST":
form = NewsAndEventsForm(request.POST)
title = request.POST.get('title')
title = request.POST.get("title")
if form.is_valid():
form.save()
messages.success(request, (title + ' has been uploaded.'))
return redirect('home')
messages.success(request, (title + " has been uploaded."))
return redirect("home")
else:
messages.error(request, 'Please correct the error(s) below.')
messages.error(request, "Please correct the error(s) below.")
else:
form = NewsAndEventsForm()
return render(request, 'app/post_add.html', {
'title': 'Add Post | DjangoSMS',
'form': form,
})
return render(
request,
"app/post_add.html",
{
"title": "Add Post | DjangoSMS",
"form": form,
},
)
@login_required
@lecturer_required
def edit_post(request, pk):
instance = get_object_or_404(NewsAndEvents, pk=pk)
if request.method == 'POST':
if request.method == "POST":
form = NewsAndEventsForm(request.POST, instance=instance)
title = request.POST.get('title')
title = request.POST.get("title")
if form.is_valid():
form.save()
messages.success(request, (title + ' has been updated.'))
return redirect('home')
messages.success(request, (title + " has been updated."))
return redirect("home")
else:
messages.error(request, 'Please correct the error(s) below.')
messages.error(request, "Please correct the error(s) below.")
else:
form = NewsAndEventsForm(instance=instance)
return render(request, 'app/post_add.html', {
'title': 'Edit Post | DjangoSMS',
'form': form,
})
return render(
request,
"app/post_add.html",
{
"title": "Edit Post | DjangoSMS",
"form": form,
},
)
@login_required
@ -69,8 +77,9 @@ def delete_post(request, pk):
post = get_object_or_404(NewsAndEvents, pk=pk)
title = post.title
post.delete()
messages.success(request, (title + ' has been deleted.'))
return redirect('home')
messages.success(request, (title + " has been deleted."))
return redirect("home")
# ########################################################
# Session
@ -78,21 +87,23 @@ def delete_post(request, pk):
@login_required
@lecturer_required
def session_list_view(request):
""" Show list of all sessions """
sessions = Session.objects.all().order_by('-is_current_session', '-session')
return render(request, 'app/session_list.html', {"sessions": sessions})
"""Show list of all sessions"""
sessions = Session.objects.all().order_by("-is_current_session", "-session")
return render(request, "app/session_list.html", {"sessions": sessions})
@login_required
@lecturer_required
def session_add_view(request):
""" check request method, if POST we add session otherwise show empty form """
if request.method == 'POST':
"""check request method, if POST we add session otherwise show empty form"""
if request.method == "POST":
form = SessionForm(request.POST)
if form.is_valid():
data = form.data.get('is_current_session') # returns string of 'True' if the user selected Yes
data = form.data.get(
"is_current_session"
) # returns string of 'True' if the user selected Yes
print(data)
if data == 'true':
if data == "true":
sessions = Session.objects.all()
if sessions:
for session in sessions:
@ -105,22 +116,22 @@ def session_add_view(request):
form.save()
else:
form.save()
messages.success(request, 'Session added successfully. ')
return redirect('session_list')
messages.success(request, "Session added successfully. ")
return redirect("session_list")
else:
form = SessionForm()
return render(request, 'app/session_update.html', {'form': form})
return render(request, "app/session_update.html", {"form": form})
@login_required
@lecturer_required
def session_update_view(request, pk):
session = Session.objects.get(pk=pk)
if request.method == 'POST':
if request.method == "POST":
form = SessionForm(request.POST, instance=session)
data = form.data.get('is_current_session')
if data == 'true':
data = form.data.get("is_current_session")
if data == "true":
sessions = Session.objects.all()
if sessions:
for session in sessions:
@ -131,18 +142,18 @@ def session_update_view(request, pk):
if form.is_valid():
form.save()
messages.success(request, 'Session updated successfully. ')
return redirect('session_list')
messages.success(request, "Session updated successfully. ")
return redirect("session_list")
else:
form = SessionForm(request.POST, instance=session)
if form.is_valid():
form.save()
messages.success(request, 'Session updated successfully. ')
return redirect('session_list')
messages.success(request, "Session updated successfully. ")
return redirect("session_list")
else:
form = SessionForm(instance=session)
return render(request, 'app/session_update.html', {'form': form})
return render(request, "app/session_update.html", {"form": form})
@login_required
@ -152,11 +163,13 @@ def session_delete_view(request, pk):
if session.is_current_session:
messages.error(request, "You cannot delete current session")
return redirect('session_list')
return redirect("session_list")
else:
session.delete()
messages.success(request, "Session successfully deleted")
return redirect('session_list')
return redirect("session_list")
# ########################################################
@ -166,86 +179,106 @@ def session_delete_view(request, pk):
@login_required
@lecturer_required
def semester_list_view(request):
semesters = Semester.objects.all().order_by('-is_current_semester', '-semester')
return render(request, 'app/semester_list.html', {"semesters": semesters, })
semesters = Semester.objects.all().order_by("-is_current_semester", "-semester")
return render(
request,
"app/semester_list.html",
{
"semesters": semesters,
},
)
@login_required
@lecturer_required
def semester_add_view(request):
if request.method == 'POST':
if request.method == "POST":
form = SemesterForm(request.POST)
if form.is_valid():
data = form.data.get('is_current_semester') # returns string of 'True' if the user selected Yes
if data == 'True':
semester = form.data.get('semester')
ss = form.data.get('session')
data = form.data.get(
"is_current_semester"
) # returns string of 'True' if the user selected Yes
if data == "True":
semester = form.data.get("semester")
ss = form.data.get("session")
session = Session.objects.get(pk=ss)
try:
if Semester.objects.get(semester=semester, session=ss):
messages.error(request, semester + " semester in " + session.session + " session already exist")
return redirect('add_semester')
messages.error(
request,
semester
+ " semester in "
+ session.session
+ " session already exist",
)
return redirect("add_semester")
except:
semesters = Semester.objects.all()
sessions = Session.objects.all()
if semesters:
for semester in semesters:
if semester.is_current_semester == True:
unset_semester = Semester.objects.get(is_current_semester=True)
unset_semester = Semester.objects.get(
is_current_semester=True
)
unset_semester.is_current_semester = False
unset_semester.save()
for session in sessions:
if session.is_current_session == True:
unset_session = Session.objects.get(is_current_session=True)
unset_session = Session.objects.get(
is_current_session=True
)
unset_session.is_current_session = False
unset_session.save()
new_session = request.POST.get('session')
new_session = request.POST.get("session")
set_session = Session.objects.get(pk=new_session)
set_session.is_current_session = True
set_session.save()
form.save()
messages.success(request, 'Semester added successfully.')
return redirect('semester_list')
messages.success(request, "Semester added successfully.")
return redirect("semester_list")
form.save()
messages.success(request, 'Semester added successfully. ')
return redirect('semester_list')
messages.success(request, "Semester added successfully. ")
return redirect("semester_list")
else:
form = SemesterForm()
return render(request, 'app/semester_update.html', {'form': form})
return render(request, "app/semester_update.html", {"form": form})
@login_required
@lecturer_required
def semester_update_view(request, pk):
semester = Semester.objects.get(pk=pk)
if request.method == 'POST':
if request.POST.get('is_current_semester') == 'True': # returns string of 'True' if the user selected yes for 'is current semester'
if request.method == "POST":
if (
request.POST.get("is_current_semester") == "True"
): # returns string of 'True' if the user selected yes for 'is current semester'
unset_semester = Semester.objects.get(is_current_semester=True)
unset_semester.is_current_semester = False
unset_semester.save()
unset_session = Session.objects.get(is_current_session=True)
unset_session.is_current_session = False
unset_session.save()
new_session = request.POST.get('session')
new_session = request.POST.get("session")
form = SemesterForm(request.POST, instance=semester)
if form.is_valid():
set_session = Session.objects.get(pk=new_session)
set_session.is_current_session = True
set_session.save()
form.save()
messages.success(request, 'Semester updated successfully !')
return redirect('semester_list')
messages.success(request, "Semester updated successfully !")
return redirect("semester_list")
else:
form = SemesterForm(request.POST, instance=semester)
if form.is_valid():
form.save()
return redirect('semester_list')
return redirect("semester_list")
else:
form = SemesterForm(instance=semester)
return render(request, 'app/semester_update.html', {'form': form})
return render(request, "app/semester_update.html", {"form": form})
@login_required
@ -254,11 +287,13 @@ def semester_delete_view(request, pk):
semester = get_object_or_404(Semester, pk=pk)
if semester.is_current_semester:
messages.error(request, "You cannot delete current semester")
return redirect('semester_list')
return redirect("semester_list")
else:
semester.delete()
messages.success(request, "Semester successfully deleted")
return redirect('semester_list')
return redirect("semester_list")
# ########################################################
@ -284,7 +319,8 @@ def semester_delete_view(request, pk):
# return response
@login_required
@admin_required
def dashboard_view(request):
return render(request, 'app/dashboard.html')
return render(request, "app/dashboard.html")

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class CourseConfig(AppConfig):
name = 'course'
name = "course"

View File

@ -8,98 +8,109 @@ from .models import Program, Course, CourseAllocation, Upload, UploadVideo
# User = settings.AUTH_USER_MODEL
class ProgramForm(forms.ModelForm):
class Meta:
model = Program
fields = '__all__'
fields = "__all__"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['summary'].widget.attrs.update({'class': 'form-control'})
self.fields["title"].widget.attrs.update({"class": "form-control"})
self.fields["summary"].widget.attrs.update({"class": "form-control"})
class CourseAddForm(forms.ModelForm):
class Meta:
model = Course
fields = '__all__'
fields = "__all__"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['code'].widget.attrs.update({'class': 'form-control'})
self.fields["title"].widget.attrs.update({"class": "form-control"})
self.fields["code"].widget.attrs.update({"class": "form-control"})
# self.fields['courseUnit'].widget.attrs.update({'class': 'form-control'})
self.fields['credit'].widget.attrs.update({'class': 'form-control'})
self.fields['summary'].widget.attrs.update({'class': 'form-control'})
self.fields['program'].widget.attrs.update({'class': 'form-control'})
self.fields['level'].widget.attrs.update({'class': 'form-control'})
self.fields['year'].widget.attrs.update({'class': 'form-control'})
self.fields['semester'].widget.attrs.update({'class': 'form-control'})
self.fields["credit"].widget.attrs.update({"class": "form-control"})
self.fields["summary"].widget.attrs.update({"class": "form-control"})
self.fields["program"].widget.attrs.update({"class": "form-control"})
self.fields["level"].widget.attrs.update({"class": "form-control"})
self.fields["year"].widget.attrs.update({"class": "form-control"})
self.fields["semester"].widget.attrs.update({"class": "form-control"})
class CourseAllocationForm(forms.ModelForm):
courses = forms.ModelMultipleChoiceField(
queryset=Course.objects.all().order_by('level'),
widget=forms.CheckboxSelectMultiple(attrs={'class': 'browser-default checkbox'}),
required=True
queryset=Course.objects.all().order_by("level"),
widget=forms.CheckboxSelectMultiple(
attrs={"class": "browser-default checkbox"}
),
required=True,
)
lecturer = forms.ModelChoiceField(
queryset=User.objects.filter(is_lecturer=True),
widget=forms.Select(attrs={'class': 'browser-default custom-select'}),
widget=forms.Select(attrs={"class": "browser-default custom-select"}),
label="lecturer",
)
class Meta:
model = CourseAllocation
fields = ['lecturer', 'courses']
fields = ["lecturer", "courses"]
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
user = kwargs.pop("user")
super(CourseAllocationForm, self).__init__(*args, **kwargs)
self.fields['lecturer'].queryset = User.objects.filter(is_lecturer=True)
self.fields["lecturer"].queryset = User.objects.filter(is_lecturer=True)
class EditCourseAllocationForm(forms.ModelForm):
courses = forms.ModelMultipleChoiceField(
queryset=Course.objects.all().order_by('level'),
queryset=Course.objects.all().order_by("level"),
widget=forms.CheckboxSelectMultiple,
required=True
required=True,
)
lecturer = forms.ModelChoiceField(
queryset=User.objects.filter(is_lecturer=True),
widget=forms.Select(attrs={'class': 'browser-default custom-select'}),
widget=forms.Select(attrs={"class": "browser-default custom-select"}),
label="lecturer",
)
class Meta:
model = CourseAllocation
fields = ['lecturer', 'courses']
fields = ["lecturer", "courses"]
def __init__(self, *args, **kwargs):
# user = kwargs.pop('user')
super(EditCourseAllocationForm, self).__init__(*args, **kwargs)
self.fields['lecturer'].queryset = User.objects.filter(is_lecturer=True)
self.fields["lecturer"].queryset = User.objects.filter(is_lecturer=True)
# Upload files to specific course
class UploadFormFile(forms.ModelForm):
class Meta:
model = Upload
fields = ('title', 'file', 'course',)
fields = (
"title",
"file",
"course",
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['file'].widget.attrs.update({'class': 'form-control'})
self.fields["title"].widget.attrs.update({"class": "form-control"})
self.fields["file"].widget.attrs.update({"class": "form-control"})
# Upload video to specific course
class UploadFormVideo(forms.ModelForm):
class Meta:
model = UploadVideo
fields = ('title', 'video', 'course',)
fields = (
"title",
"video",
"course",
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['video'].widget.attrs.update({'class': 'form-control'})
self.fields["title"].widget.attrs.update({"class": "form-control"})
self.fields["video"].widget.attrs.update({"class": "form-control"})

View File

@ -10,13 +10,13 @@ from .utils import *
YEARS = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(4, '5'),
(4, '6'),
)
(1, "1"),
(2, "2"),
(3, "3"),
(4, "4"),
(4, "5"),
(4, "6"),
)
# LEVEL_COURSE = "Level course"
BACHLOAR_DEGREE = "Bachloar"
@ -43,10 +43,10 @@ class ProgramManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (Q(title__icontains=query) |
Q(summary__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
or_lookup = Q(title__icontains=query) | Q(summary__icontains=query)
qs = qs.filter(
or_lookup
).distinct() # distinct() is often necessary with Q lookups
return qs
@ -60,19 +60,22 @@ class Program(models.Model):
return self.title
def get_absolute_url(self):
return reverse('program_detail', kwargs={'pk': self.pk})
return reverse("program_detail", kwargs={"pk": self.pk})
class CourseManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (Q(title__icontains=query) |
Q(summary__icontains=query)|
Q(code__icontains=query)|
Q(slug__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
or_lookup = (
Q(title__icontains=query)
| Q(summary__icontains=query)
| Q(code__icontains=query)
| Q(slug__icontains=query)
)
qs = qs.filter(
or_lookup
).distinct() # distinct() is often necessary with Q lookups
return qs
@ -94,11 +97,12 @@ class Course(models.Model):
return "{0} ({1})".format(self.title, self.code)
def get_absolute_url(self):
return reverse('course_detail', kwargs={'slug': self.slug})
return reverse("course_detail", kwargs={"slug": self.slug})
@property
def is_current_semester(self):
from app.models import Semester
current_semester = Semester.objects.get(is_current_semester=True)
if self.semester == current_semester.semester:
@ -111,25 +115,50 @@ def course_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(course_pre_save_receiver, sender=Course)
class CourseAllocation(models.Model):
lecturer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='allocated_lecturer')
courses = models.ManyToManyField(Course, related_name='allocated_course')
session = models.ForeignKey("app.Session", on_delete=models.CASCADE, blank=True, null=True)
lecturer = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="allocated_lecturer",
)
courses = models.ManyToManyField(Course, related_name="allocated_course")
session = models.ForeignKey(
"app.Session", on_delete=models.CASCADE, blank=True, null=True
)
def __str__(self):
return self.lecturer.get_full_name
def get_absolute_url(self):
return reverse('edit_allocated_course', kwargs={'pk': self.pk})
return reverse("edit_allocated_course", kwargs={"pk": self.pk})
class Upload(models.Model):
title = models.CharField(max_length=100)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
file = models.FileField(upload_to='course_files/', validators=[FileExtensionValidator(['pdf', 'docx', 'doc', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7zip'])])
file = models.FileField(
upload_to="course_files/",
validators=[
FileExtensionValidator(
[
"pdf",
"docx",
"doc",
"xls",
"xlsx",
"ppt",
"pptx",
"zip",
"rar",
"7zip",
]
)
],
)
updated_date = models.DateTimeField(auto_now=True, auto_now_add=False, null=True)
upload_time = models.DateTimeField(auto_now=False, auto_now_add=True, null=True)
@ -138,18 +167,18 @@ class Upload(models.Model):
def get_extension_short(self):
ext = str(self.file).split(".")
ext = ext[len(ext)-1]
ext = ext[len(ext) - 1]
if ext == 'doc' or ext == 'docx':
return 'word'
elif ext == 'pdf':
return 'pdf'
elif ext == 'xls' or ext == 'xlsx':
return 'excel'
elif ext == 'ppt' or ext == 'pptx':
return 'powerpoint'
elif ext == 'zip' or ext == 'rar' or ext == '7zip':
return 'archive'
if ext == "doc" or ext == "docx":
return "word"
elif ext == "pdf":
return "pdf"
elif ext == "xls" or ext == "xlsx":
return "excel"
elif ext == "ppt" or ext == "pptx":
return "powerpoint"
elif ext == "zip" or ext == "rar" or ext == "7zip":
return "archive"
def delete(self, *args, **kwargs):
self.file.delete()
@ -160,7 +189,12 @@ class UploadVideo(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(blank=True, unique=True)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
video = models.FileField(upload_to='course_videos/', validators=[FileExtensionValidator(['mp4', 'mkv', 'wmv', '3gp', 'f4v', 'avi', 'mp3'])])
video = models.FileField(
upload_to="course_videos/",
validators=[
FileExtensionValidator(["mp4", "mkv", "wmv", "3gp", "f4v", "avi", "mp3"])
],
)
summary = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True, null=True)
@ -168,7 +202,9 @@ class UploadVideo(models.Model):
return str(self.title)
def get_absolute_url(self):
return reverse('video_single', kwargs={'slug': self.course.slug, 'video_slug': self.slug})
return reverse(
"video_single", kwargs={"slug": self.course.slug, "video_slug": self.slug}
)
def delete(self, *args, **kwargs):
self.video.delete()
@ -179,12 +215,14 @@ def video_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(video_pre_save_receiver, sender=UploadVideo)
class CourseOffer(models.Model):
"""NOTE: Only department head can offer semester courses"""
dep_head = models.ForeignKey("accounts.DepartmentHead", on_delete=models.CASCADE)
"""NOTE: Only department head can offer semester courses"""
def __str__(self):
return "{}".format(self.dep_head)
dep_head = models.ForeignKey("accounts.DepartmentHead", on_delete=models.CASCADE)
def __str__(self):
return "{}".format(self.dep_head)

View File

@ -4,38 +4,66 @@ from .views import *
urlpatterns = [
# Program urls
path('', program_view, name='programs'),
path('<int:pk>/detail/', program_detail, name='program_detail'),
path('add/', program_add, name='add_program'),
path('<int:pk>/edit/', program_edit, name='edit_program'),
path('<int:pk>/delete/', program_delete, name='program_delete'),
path("", program_view, name="programs"),
path("<int:pk>/detail/", program_detail, name="program_detail"),
path("add/", program_add, name="add_program"),
path("<int:pk>/edit/", program_edit, name="edit_program"),
path("<int:pk>/delete/", program_delete, name="program_delete"),
# Course urls
path('course/<slug>/detail/', course_single, name='course_detail'),
path('<int:pk>/course/add/', course_add, name='course_add'),
path('course/<slug>/edit/', course_edit, name='edit_course'),
path('course/delete/<slug>/', course_delete, name='delete_course'),
path("course/<slug>/detail/", course_single, name="course_detail"),
path("<int:pk>/course/add/", course_add, name="course_add"),
path("course/<slug>/edit/", course_edit, name="edit_course"),
path("course/delete/<slug>/", course_delete, name="delete_course"),
# CourseAllocation urls
path('course/assign/', CourseAllocationFormView.as_view(), name='course_allocation'),
path('course/allocated/', course_allocation_view, name='course_allocation_view'),
path('allocated_course/<int:pk>/edit/', edit_allocated_course, name='edit_allocated_course'),
path('course/<int:pk>/deallocate/', deallocate_course, name='course_deallocate'),
path(
"course/assign/", CourseAllocationFormView.as_view(), name="course_allocation"
),
path("course/allocated/", course_allocation_view, name="course_allocation_view"),
path(
"allocated_course/<int:pk>/edit/",
edit_allocated_course,
name="edit_allocated_course",
),
path("course/<int:pk>/deallocate/", deallocate_course, name="course_deallocate"),
# File uploads urls
path('course/<slug>/documentations/upload/', handle_file_upload, name='upload_file_view'),
path('course/<slug>/documentations/<int:file_id>/edit/', handle_file_edit, name='upload_file_edit'),
path('course/<slug>/documentations/<int:file_id>/delete/', handle_file_delete, name='upload_file_delete'),
path(
"course/<slug>/documentations/upload/",
handle_file_upload,
name="upload_file_view",
),
path(
"course/<slug>/documentations/<int:file_id>/edit/",
handle_file_edit,
name="upload_file_edit",
),
path(
"course/<slug>/documentations/<int:file_id>/delete/",
handle_file_delete,
name="upload_file_delete",
),
# Video uploads urls
path('course/<slug>/video_tutorials/upload/', handle_video_upload, name='upload_video'),
path('course/<slug>/video_tutorials/<video_slug>/detail/', handle_video_single, name='video_single'),
path('course/<slug>/video_tutorials/<video_slug>/edit/', handle_video_edit, name='upload_video_edit'),
path('course/<slug>/video_tutorials/<video_slug>/delete/', handle_video_delete, name='upload_video_delete'),
path(
"course/<slug>/video_tutorials/upload/",
handle_video_upload,
name="upload_video",
),
path(
"course/<slug>/video_tutorials/<video_slug>/detail/",
handle_video_single,
name="video_single",
),
path(
"course/<slug>/video_tutorials/<video_slug>/edit/",
handle_video_edit,
name="upload_video_edit",
),
path(
"course/<slug>/video_tutorials/<video_slug>/delete/",
handle_video_delete,
name="upload_video_delete",
),
# course registration
path('course/registration/', course_registration, name='course_registration'),
path('course/drop/', course_drop, name='course_drop'),
path('my_courses/', user_course_list, name="user_course_list"),
path("course/registration/", course_registration, name="course_registration"),
path("course/drop/", course_drop, name="course_drop"),
path("my_courses/", user_course_list, name="user_course_list"),
]

View File

@ -7,7 +7,7 @@ from django.utils.text import slugify
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
return "".join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
@ -24,8 +24,7 @@ def unique_slug_generator(instance, new_slug=None):
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4)
)
slug=slug, randstr=random_string_generator(size=4)
)
return unique_slug_generator(instance, new_slug=new_slug)
return slug

View File

@ -13,8 +13,12 @@ from app.models import Session, Semester
from result.models import TakenCourse
from accounts.decorators import lecturer_required, student_required
from .forms import (
ProgramForm, CourseAddForm, CourseAllocationForm,
EditCourseAllocationForm, UploadFormFile, UploadFormVideo
ProgramForm,
CourseAddForm,
CourseAllocationForm,
EditCourseAllocationForm,
UploadFormFile,
UploadFormVideo,
)
from .models import Program, Course, CourseAllocation, Upload, UploadVideo
@ -26,51 +30,67 @@ from .models import Program, Course, CourseAllocation, Upload, UploadVideo
def program_view(request):
programs = Program.objects.all()
program_filter = request.GET.get('program_filter')
program_filter = request.GET.get("program_filter")
if program_filter:
programs = Program.objects.filter(title__icontains=program_filter)
return render(request, 'course/program_list.html', {
'title': "Programs | DjangoSMS",
'programs': programs,
})
return render(
request,
"course/program_list.html",
{
"title": "Programs | DjangoSMS",
"programs": programs,
},
)
@login_required
@lecturer_required
def program_add(request):
if request.method == 'POST':
if request.method == "POST":
form = ProgramForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, request.POST.get('title') + ' program has been created.')
return redirect('programs')
messages.success(
request, request.POST.get("title") + " program has been created."
)
return redirect("programs")
else:
messages.error(request, 'Correct the error(S) below.')
messages.error(request, "Correct the error(S) below.")
else:
form = ProgramForm()
return render(request, 'course/program_add.html', {
'title': "Add Program | DjangoSMS",
'form': form,
})
return render(
request,
"course/program_add.html",
{
"title": "Add Program | DjangoSMS",
"form": form,
},
)
@login_required
def program_detail(request, pk):
program = Program.objects.get(pk=pk)
courses = Course.objects.filter(program_id=pk).order_by('-year')
credits = Course.objects.aggregate(Sum('credit'))
courses = Course.objects.filter(program_id=pk).order_by("-year")
credits = Course.objects.aggregate(Sum("credit"))
paginator = Paginator(courses, 10)
page = request.GET.get('page')
page = request.GET.get("page")
courses = paginator.get_page(page)
return render(request, 'course/program_single.html', {
'title': program.title,
'program': program, 'courses': courses, 'credits': credits
}, )
return render(
request,
"course/program_single.html",
{
"title": program.title,
"program": program,
"courses": courses,
"credits": credits,
},
)
@login_required
@ -78,19 +98,22 @@ def program_detail(request, pk):
def program_edit(request, pk):
program = Program.objects.get(pk=pk)
if request.method == 'POST':
if request.method == "POST":
form = ProgramForm(request.POST, instance=program)
if form.is_valid():
form.save()
messages.success(request, str(request.POST.get('title')) + ' program has been updated.')
return redirect('programs')
messages.success(
request, str(request.POST.get("title")) + " program has been updated."
)
return redirect("programs")
else:
form = ProgramForm(instance=program)
return render(request, 'course/program_add.html', {
'title': "Edit Program | DjangoSMS",
'form': form
})
return render(
request,
"course/program_add.html",
{"title": "Edit Program | DjangoSMS", "form": form},
)
@login_required
@ -99,11 +122,14 @@ def program_delete(request, pk):
program = Program.objects.get(pk=pk)
title = program.title
program.delete()
messages.success(request, 'Program ' + title + ' has been deleted.')
messages.success(request, "Program " + title + " has been deleted.")
return redirect("programs")
return redirect('programs')
# ########################################################
# ########################################################
# Course views
# ########################################################
@ -116,61 +142,79 @@ def course_single(request, slug):
# lecturers = User.objects.filter(allocated_lecturer__pk=course.id)
lecturers = CourseAllocation.objects.filter(courses__pk=course.id)
return render(request, 'course/course_single.html', {
'title': course.title,
'course': course,
'files': files,
'videos': videos,
'lecturers': lecturers,
'media_url': settings.MEDIA_ROOT,
}, )
return render(
request,
"course/course_single.html",
{
"title": course.title,
"course": course,
"files": files,
"videos": videos,
"lecturers": lecturers,
"media_url": settings.MEDIA_ROOT,
},
)
@login_required
@lecturer_required
def course_add(request, pk):
users = User.objects.all()
if request.method == 'POST':
if request.method == "POST":
form = CourseAddForm(request.POST)
course_name = request.POST.get('title')
course_code = request.POST.get('code')
course_name = request.POST.get("title")
course_code = request.POST.get("code")
if form.is_valid():
form.save()
messages.success(request, (course_name + '(' + course_code + ')' + ' has been created.'))
return redirect('program_detail', pk=request.POST.get('program'))
messages.success(
request, (course_name + "(" + course_code + ")" + " has been created.")
)
return redirect("program_detail", pk=request.POST.get("program"))
else:
messages.error(request, 'Correct the error(s) below.')
messages.error(request, "Correct the error(s) below.")
else:
form = CourseAddForm(initial={'program': Program.objects.get(pk=pk)})
form = CourseAddForm(initial={"program": Program.objects.get(pk=pk)})
return render(request, 'course/course_add.html', {
'title': "Add Course | DjangoSMS",
'form': form, 'program': pk, 'users': users
}, )
return render(
request,
"course/course_add.html",
{
"title": "Add Course | DjangoSMS",
"form": form,
"program": pk,
"users": users,
},
)
@login_required
@lecturer_required
def course_edit(request, slug):
course = get_object_or_404(Course, slug=slug)
if request.method == 'POST':
if request.method == "POST":
form = CourseAddForm(request.POST, instance=course)
course_name = request.POST.get('title')
course_code = request.POST.get('code')
course_name = request.POST.get("title")
course_code = request.POST.get("code")
if form.is_valid():
form.save()
messages.success(request, (course_name + '(' + course_code + ')' + ' has been updated.'))
return redirect('program_detail', pk=request.POST.get('program'))
messages.success(
request, (course_name + "(" + course_code + ")" + " has been updated.")
)
return redirect("program_detail", pk=request.POST.get("program"))
else:
messages.error(request, 'Correct the error(s) below.')
messages.error(request, "Correct the error(s) below.")
else:
form = CourseAddForm(instance=course)
return render(request, 'course/course_add.html', {
'title': "Edit Course | DjangoSMS",
# 'form': form, 'program': pk, 'course': pk
'form': form
}, )
return render(
request,
"course/course_add.html",
{
"title": "Edit Course | DjangoSMS",
# 'form': form, 'program': pk, 'course': pk
"form": form,
},
)
@login_required
@ -179,29 +223,31 @@ def course_delete(request, slug):
course = Course.objects.get(slug=slug)
# course_name = course.title
course.delete()
messages.success(request, 'Course ' + course.title + ' has been deleted.')
messages.success(request, "Course " + course.title + " has been deleted.")
return redirect("program_detail", pk=course.program.id)
return redirect('program_detail', pk=course.program.id)
# ########################################################
# ########################################################
# Course Allocation
# ########################################################
@method_decorator([login_required], name='dispatch')
@method_decorator([login_required], name="dispatch")
class CourseAllocationFormView(CreateView):
form_class = CourseAllocationForm
template_name = 'course/course_allocation_form.html'
template_name = "course/course_allocation_form.html"
def get_form_kwargs(self):
kwargs = super(CourseAllocationFormView, self).get_form_kwargs()
kwargs['user'] = self.request.user
kwargs["user"] = self.request.user
return kwargs
def form_valid(self, form):
# if a staff has been allocated a course before update it else create new
lecturer = form.cleaned_data['lecturer']
selected_courses = form.cleaned_data['courses']
lecturer = form.cleaned_data["lecturer"]
selected_courses = form.cleaned_data["courses"]
courses = ()
for course in selected_courses:
courses += (course.pk,)
@ -214,40 +260,45 @@ class CourseAllocationFormView(CreateView):
for i in range(0, selected_courses.count()):
a.courses.add(courses[i])
a.save()
return redirect('course_allocation_view')
return redirect("course_allocation_view")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = "Assign Course | DjangoSMS"
context["title"] = "Assign Course | DjangoSMS"
return context
@login_required
def course_allocation_view(request):
allocated_courses = CourseAllocation.objects.all()
return render(request, 'course/course_allocation_view.html', {
'title': "Course Allocations | DjangoSMS",
"allocated_courses": allocated_courses
})
return render(
request,
"course/course_allocation_view.html",
{
"title": "Course Allocations | DjangoSMS",
"allocated_courses": allocated_courses,
},
)
@login_required
@lecturer_required
def edit_allocated_course(request, pk):
allocated = get_object_or_404(CourseAllocation, pk=pk)
if request.method == 'POST':
if request.method == "POST":
form = EditCourseAllocationForm(request.POST, instance=allocated)
if form.is_valid():
form.save()
messages.success(request, 'course assigned has been updated.')
return redirect('course_allocation_view')
messages.success(request, "course assigned has been updated.")
return redirect("course_allocation_view")
else:
form = EditCourseAllocationForm(instance=allocated)
return render(request, 'course/course_allocation_form.html', {
'title': "Edit Course Allocated | DjangoSMS",
'form': form, 'allocated': pk
}, )
return render(
request,
"course/course_allocation_form.html",
{"title": "Edit Course Allocated | DjangoSMS", "form": form, "allocated": pk},
)
@login_required
@ -255,8 +306,10 @@ def edit_allocated_course(request, pk):
def deallocate_course(request, pk):
course = CourseAllocation.objects.get(pk=pk)
course.delete()
messages.success(request, 'successfully deallocate!')
messages.success(request, "successfully deallocate!")
return redirect("course_allocation_view")
# ########################################################
@ -267,19 +320,22 @@ def deallocate_course(request, pk):
@lecturer_required
def handle_file_upload(request, slug):
course = Course.objects.get(slug=slug)
if request.method == 'POST':
form = UploadFormFile(request.POST, request.FILES, {'course': course})
if request.method == "POST":
form = UploadFormFile(request.POST, request.FILES, {"course": course})
# file_name = request.POST.get('name')
if form.is_valid():
form.save()
messages.success(request, (request.POST.get('title') + ' has been uploaded.'))
return redirect('course_detail', slug=slug)
messages.success(
request, (request.POST.get("title") + " has been uploaded.")
)
return redirect("course_detail", slug=slug)
else:
form = UploadFormFile()
return render(request, 'upload/upload_file_form.html', {
'title': "File Upload | DjangoSMS",
'form': form, 'course': course
})
return render(
request,
"upload/upload_file_form.html",
{"title": "File Upload | DjangoSMS", "form": form, "course": course},
)
@login_required
@ -287,19 +343,23 @@ def handle_file_upload(request, slug):
def handle_file_edit(request, slug, file_id):
course = Course.objects.get(slug=slug)
instance = Upload.objects.get(pk=file_id)
if request.method == 'POST':
if request.method == "POST":
form = UploadFormFile(request.POST, request.FILES, instance=instance)
# file_name = request.POST.get('name')
if form.is_valid():
form.save()
messages.success(request, (request.POST.get('title') + ' has been updated.'))
return redirect('course_detail', slug=slug)
messages.success(
request, (request.POST.get("title") + " has been updated.")
)
return redirect("course_detail", slug=slug)
else:
form = UploadFormFile(instance=instance)
return render(request, 'upload/upload_file_form.html', {
'title': instance.title,
'form': form, 'course': course})
return render(
request,
"upload/upload_file_form.html",
{"title": instance.title, "form": form, "course": course},
)
def handle_file_delete(request, slug, file_id):
@ -307,8 +367,9 @@ def handle_file_delete(request, slug, file_id):
# file_name = file.name
file.delete()
messages.success(request, (file.title + ' has been deleted.'))
return redirect('course_detail', slug=slug)
messages.success(request, (file.title + " has been deleted."))
return redirect("course_detail", slug=slug)
# ########################################################
# Video Upload views
@ -317,18 +378,21 @@ def handle_file_delete(request, slug, file_id):
@lecturer_required
def handle_video_upload(request, slug):
course = Course.objects.get(slug=slug)
if request.method == 'POST':
form = UploadFormVideo(request.POST, request.FILES, {'course': course})
if request.method == "POST":
form = UploadFormVideo(request.POST, request.FILES, {"course": course})
if form.is_valid():
form.save()
messages.success(request, (request.POST.get('title') + ' has been uploaded.'))
return redirect('course_detail', slug=slug)
messages.success(
request, (request.POST.get("title") + " has been uploaded.")
)
return redirect("course_detail", slug=slug)
else:
form = UploadFormVideo()
return render(request, 'upload/upload_video_form.html', {
'title': "Video Upload | DjangoSMS",
'form': form, 'course': course
})
return render(
request,
"upload/upload_video_form.html",
{"title": "Video Upload | DjangoSMS", "form": form, "course": course},
)
@login_required
@ -336,7 +400,7 @@ def handle_video_upload(request, slug):
def handle_video_single(request, slug, video_slug):
course = get_object_or_404(Course, slug=slug)
video = get_object_or_404(UploadVideo, slug=video_slug)
return render(request, 'upload/video_single.html', {'video': video})
return render(request, "upload/video_single.html", {"video": video})
@login_required
@ -344,18 +408,22 @@ def handle_video_single(request, slug, video_slug):
def handle_video_edit(request, slug, video_slug):
course = Course.objects.get(slug=slug)
instance = UploadVideo.objects.get(slug=video_slug)
if request.method == 'POST':
if request.method == "POST":
form = UploadFormVideo(request.POST, request.FILES, instance=instance)
if form.is_valid():
form.save()
messages.success(request, (request.POST.get('title') + ' has been updated.'))
return redirect('course_detail', slug=slug)
messages.success(
request, (request.POST.get("title") + " has been updated.")
)
return redirect("course_detail", slug=slug)
else:
form = UploadFormVideo(instance=instance)
return render(request, 'upload/upload_video_form.html', {
'title': instance.title,
'form': form, 'course': course})
return render(
request,
"upload/upload_video_form.html",
{"title": instance.title, "form": form, "course": course},
)
def handle_video_delete(request, slug, video_slug):
@ -363,8 +431,10 @@ def handle_video_delete(request, slug, video_slug):
# video = UploadVideo.objects.get(slug=video_slug)
video.delete()
messages.success(request, (video.title + ' has been deleted.'))
return redirect('course_detail', slug=slug)
messages.success(request, (video.title + " has been deleted."))
return redirect("course_detail", slug=slug)
# ########################################################
@ -374,10 +444,10 @@ def handle_video_delete(request, slug, video_slug):
@login_required
@student_required
def course_registration(request):
if request.method == 'POST':
if request.method == "POST":
ids = ()
data = request.POST.copy()
data.pop('csrfmiddlewaretoken', None) # remove csrf_token
data.pop("csrfmiddlewaretoken", None) # remove csrf_token
for key in data.keys():
ids = ids + (str(key),)
for s in range(0, len(ids)):
@ -385,8 +455,8 @@ def course_registration(request):
course = Course.objects.get(pk=ids[s])
obj = TakenCourse.objects.create(student=student, course=course)
obj.save()
messages.success(request, 'Courses Registered Successfully!')
return redirect('course_registration')
messages.success(request, "Courses Registered Successfully!")
return redirect("course_registration")
else:
# student = Student.objects.get(student__pk=request.user.id)
student = get_object_or_404(Student, student__id=request.user.id)
@ -396,15 +466,26 @@ def course_registration(request):
t += (i.course.pk,)
current_semester = Semester.objects.get(is_current_semester=True)
courses = Course.objects.filter(program__pk=student.department.id, level=student.level, semester=current_semester
).exclude(id__in=t).order_by('year')
all_courses = Course.objects.filter(level=student.level, program__pk=student.department.id)
courses = (
Course.objects.filter(
program__pk=student.department.id,
level=student.level,
semester=current_semester,
)
.exclude(id__in=t)
.order_by("year")
)
all_courses = Course.objects.filter(
level=student.level, program__pk=student.department.id
)
no_course_is_registered = False # Check if no course is registered
all_courses_are_registered = False
registered_courses = Course.objects.filter(level=student.level).filter(id__in=t)
if registered_courses.count() == 0: # Check if number of registered courses is 0
if (
registered_courses.count() == 0
): # Check if number of registered courses is 0
no_course_is_registered = True
if registered_courses.count() == all_courses.count():
@ -432,16 +513,16 @@ def course_registration(request):
"total_registered_credit": total_registered_credit,
"student": student,
}
return render(request, 'course/course_registration.html', context)
return render(request, "course/course_registration.html", context)
@login_required
@student_required
def course_drop(request):
if request.method == 'POST':
if request.method == "POST":
ids = ()
data = request.POST.copy()
data.pop('csrfmiddlewaretoken', None) # remove csrf_token
data.pop("csrfmiddlewaretoken", None) # remove csrf_token
for key in data.keys():
ids = ids + (str(key),)
for s in range(0, len(ids)):
@ -449,8 +530,10 @@ def course_drop(request):
course = Course.objects.get(pk=ids[s])
obj = TakenCourse.objects.get(student=student, course=course)
obj.delete()
messages.success(request, 'Successfully Dropped!')
return redirect('course_registration')
messages.success(request, "Successfully Dropped!")
return redirect("course_registration")
# ########################################################
@ -459,18 +542,22 @@ def user_course_list(request):
if request.user.is_lecturer:
courses = Course.objects.filter(allocated_course__lecturer__pk=request.user.id)
return render(request, 'course/user_course_list.html', {'courses': courses})
return render(request, "course/user_course_list.html", {"courses": courses})
elif request.user.is_student:
student = Student.objects.get(student__pk=request.user.id)
taken_courses = TakenCourse.objects.filter(student__student__id=student.student.id)
courses = Course.objects.filter(level=student.level).filter(program__pk=student.department.id)
taken_courses = TakenCourse.objects.filter(
student__student__id=student.student.id
)
courses = Course.objects.filter(level=student.level).filter(
program__pk=student.department.id
)
return render(request, 'course/user_course_list.html', {
'student': student,
'taken_courses': taken_courses,
'courses': courses
})
return render(
request,
"course/user_course_list.html",
{"student": student, "taken_courses": taken_courses, "courses": courses},
)
else:
return render(request, 'course/user_course_list.html')
return render(request, "course/user_course_list.html")

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class PaymentsConfig(AppConfig):
name = 'payments'
name = "payments"

View File

@ -3,8 +3,8 @@ from django.conf import settings
class Invoice(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
total = models.FloatField(null=True, blank=True)
amount = models.FloatField(null=True, blank=True)
payment_complete = models.BooleanField(default=False)
invoice_code = models.CharField(max_length=200, blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
total = models.FloatField(null=True, blank=True)
amount = models.FloatField(null=True, blank=True)
payment_complete = models.BooleanField(default=False)
invoice_code = models.CharField(max_length=200, blank=True, null=True)

View File

@ -2,18 +2,15 @@ from django.urls import path
from . import views
urlpatterns = [
path('', views.PaymentGetwaysView.as_view(), name='payment_gateways'),
path('paypal/', views.payment_paypal, name="paypal"),
path('stripe/', views.payment_stripe, name="stripe"),
path('coinbase/', views.payment_coinbase, name="coinbase"),
path('paylike/', views.payment_paylike, name="paylike"),
path('stripe-charge/', views.stripe_charge, name='stripe_charge'),
path('gopay-charge/', views.gopay_charge, name="gopay_charge"),
path('payment-succeed/', views.payment_succeed, name="payment-succeed"),
path('complete/', views.paymentComplete, name="complete"),
path('create-invoice/', views.create_invoice, name="create_invoice"),
path('invoice-detail/<int:id>/', views.invoice_detail, name="invoice_detail"),
path("", views.PaymentGetwaysView.as_view(), name="payment_gateways"),
path("paypal/", views.payment_paypal, name="paypal"),
path("stripe/", views.payment_stripe, name="stripe"),
path("coinbase/", views.payment_coinbase, name="coinbase"),
path("paylike/", views.payment_paylike, name="paylike"),
path("stripe-charge/", views.stripe_charge, name="stripe_charge"),
path("gopay-charge/", views.gopay_charge, name="gopay_charge"),
path("payment-succeed/", views.payment_succeed, name="payment-succeed"),
path("complete/", views.paymentComplete, name="complete"),
path("create-invoice/", views.create_invoice, name="create_invoice"),
path("invoice-detail/<int:id>/", views.invoice_detail, name="invoice_detail"),
]

View File

@ -16,126 +16,128 @@ from .models import Invoice
def payment_paypal(request):
return render(request, 'payments/paypal.html', context={})
return render(request, "payments/paypal.html", context={})
def payment_stripe(request):
return render(request, 'payments/stripe.html', context={})
return render(request, "payments/stripe.html", context={})
def payment_coinbase(request):
return render(request, 'payments/coinbase.html', context={})
return render(request, "payments/coinbase.html", context={})
def payment_paylike(request):
return render(request, 'payments/paylike.html', context={})
return render(request, "payments/paylike.html", context={})
def payment_succeed(request):
return render(request, 'payments/payment_succeed.html', context={})
return render(request, "payments/payment_succeed.html", context={})
class PaymentGetwaysView(TemplateView):
template_name = 'payments/payment_gateways.html'
template_name = "payments/payment_gateways.html"
def get_context_data(self, **kwargs):
context = super(PaymentGetwaysView, self).get_context_data(**kwargs)
context['key'] = settings.STRIPE_PUBLISHABLE_KEY
context['amount'] = 500
context['description'] = "Stripe Payment"
context['invoice_session'] = self.request.session['invoice_session']
print(context['invoice_session'])
context["key"] = settings.STRIPE_PUBLISHABLE_KEY
context["amount"] = 500
context["description"] = "Stripe Payment"
context["invoice_session"] = self.request.session["invoice_session"]
print(context["invoice_session"])
return context
def stripe_charge(request):
stripe.api_key = settings.STRIPE_SECRET_KEY
if request.method == 'POST':
if request.method == "POST":
charge = stripe.Charge.create(
amount=500,
currency='eur',
description='A Django charge',
source=request.POST['stripeToken']
currency="eur",
description="A Django charge",
source=request.POST["stripeToken"],
)
invoice_code = request.session['invoice_session']
invoice_code = request.session["invoice_session"]
invoice = Invoice.objects.get(invoice_code=invoice_code)
invoice.payment_complete = True
invoice.save()
return redirect('completed')
return redirect("completed")
# return JsonResponse({"invoice_code": invoice.invoice_code}, status=201)
# return render(request, 'payments/charge.html')
def gopay_charge(request):
if request.method == 'POST':
if request.method == "POST":
user = request.user
payments = gopay.payments({
'goid': '[PAYMENT_ID]',
'clientId': '[GOPAY_CLIENT_ID]',
'clientSecret': '[GOPAY_CLIENT_SECRET]',
'isProductionMode': False,
'scope': gopay.TokenScope.ALL,
'language': gopay.Language.ENGLISH,
'timeout': 30
})
payments = gopay.payments(
{
"goid": "[PAYMENT_ID]",
"clientId": "[GOPAY_CLIENT_ID]",
"clientSecret": "[GOPAY_CLIENT_SECRET]",
"isProductionMode": False,
"scope": gopay.TokenScope.ALL,
"language": gopay.Language.ENGLISH,
"timeout": 30,
}
)
# recurrent payment must have field ''
recurrentPayment = {
'recurrence': {
'recurrence_cycle': Recurrence.DAILY,
'recurrence_period': "7",
'recurrence_date_to': '2015-12-31'
"recurrence": {
"recurrence_cycle": Recurrence.DAILY,
"recurrence_period": "7",
"recurrence_date_to": "2015-12-31",
}
}
# pre-authorized payment must have field 'preauthorization'
preauthorizedPayment = {
'preauthorization': True
}
preauthorizedPayment = {"preauthorization": True}
response = payments.create_payment({
'payer': {
'default_payment_instrument': PaymentInstrument.BANK_ACCOUNT,
'allowed_payment_instruments': [PaymentInstrument.BANK_ACCOUNT],
'default_swift': BankSwiftCode.FIO_BANKA,
'allowed_swifts': [BankSwiftCode.FIO_BANKA, BankSwiftCode.MBANK],
'contact': {
'first_name': user.first_name,
'last_name': user.last_name,
'email': user.email,
'phone_number': user.phone,
'city': 'example city',
'street': 'Plana 67',
'postal_code': '373 01',
'country_code': 'CZE',
response = payments.create_payment(
{
"payer": {
"default_payment_instrument": PaymentInstrument.BANK_ACCOUNT,
"allowed_payment_instruments": [PaymentInstrument.BANK_ACCOUNT],
"default_swift": BankSwiftCode.FIO_BANKA,
"allowed_swifts": [BankSwiftCode.FIO_BANKA, BankSwiftCode.MBANK],
"contact": {
"first_name": user.first_name,
"last_name": user.last_name,
"email": user.email,
"phone_number": user.phone,
"city": "example city",
"street": "Plana 67",
"postal_code": "373 01",
"country_code": "CZE",
},
},
},
'amount': 150,
'currency': Currency.CZECH_CROWNS,
'order_number': '001',
'order_description': 'pojisteni01',
'items': [
{'name': 'item01', 'amount': 50},
{'name': 'item02', 'amount': 100},
],
'additional_params': [
{'name': 'invoicenumber', 'value': '2015001003'}
],
'callback': {
'return_url': 'http://www.your-url.tld/return',
'notification_url': 'http://www.your-url.tld/notify'
},
'lang': Language.CZECH, # if lang is not specified, then default lang is used
})
"amount": 150,
"currency": Currency.CZECH_CROWNS,
"order_number": "001",
"order_description": "pojisteni01",
"items": [
{"name": "item01", "amount": 50},
{"name": "item02", "amount": 100},
],
"additional_params": [{"name": "invoicenumber", "value": "2015001003"}],
"callback": {
"return_url": "http://www.your-url.tld/return",
"notification_url": "http://www.your-url.tld/notify",
},
"lang": Language.CZECH, # if lang is not specified, then default lang is used
}
)
if response.has_succeed():
print("\nPayment Succeed\n")
print("hooray, API returned " + str(response))
else:
print("\nPayment Fail\n")
print("oops, API returned " + str(response.status_code) + ": " + str(response))
print(
"oops, API returned " + str(response.status_code) + ": " + str(response)
)
return JsonResponse({"message": str(response)})
return JsonResponse({"message": "GET requested"})
@ -143,28 +145,28 @@ def gopay_charge(request):
def paymentComplete(request):
print(request.is_ajax())
if request.is_ajax() or request.method == 'POST':
invoice_id = request.session['invoice_session']
if request.is_ajax() or request.method == "POST":
invoice_id = request.session["invoice_session"]
invoice = Invoice.objects.get(id=invoice_id)
invoice.payment_complete = True
invoice.save()
# return redirect('invoice', invoice.invoice_code)
body = json.loads(request.body)
print('BODY:', body)
return JsonResponse('Payment completed!', safe=False)
print("BODY:", body)
return JsonResponse("Payment completed!", safe=False)
def create_invoice(request):
print(request.is_ajax())
if request.method == 'POST':
if request.method == "POST":
invoice = Invoice.objects.create(
user = request.user,
amount = request.POST.get('amount'),
user=request.user,
amount=request.POST.get("amount"),
total=26,
invoice_code=str(uuid.uuid4()),
)
request.session['invoice_session'] = invoice.invoice_code
return redirect('payment_gateways')
request.session["invoice_session"] = invoice.invoice_code
return redirect("payment_gateways")
# if request.is_ajax():
# invoice = Invoice.objects.create(
# user = request.user,
@ -173,12 +175,16 @@ def create_invoice(request):
# )
# return JsonResponse({'invoice': invoice}, status=201) # created
return render(request, 'invoices.html', context={
'invoices': Invoice.objects.filter(user=request.user)
})
return render(
request,
"invoices.html",
context={"invoices": Invoice.objects.filter(user=request.user)},
)
def invoice_detail(request, slug):
return render(request, 'invoice_detail.html', context={
'invoice': Invoice.objects.get(invoice_code=slug)
})
return render(
request,
"invoice_detail.html",
context={"invoice": Invoice.objects.get(invoice_code=slug)},
)

View File

@ -3,7 +3,15 @@ from django.contrib import admin
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext_lazy as _
from .models import Quiz, Progress, Question, MCQuestion, Choice, Essay_Question, Sitting
from .models import (
Quiz,
Progress,
Question,
MCQuestion,
Choice,
Essay_Question,
Sitting,
)
class ChoiceInline(admin.TabularInline):
@ -11,7 +19,6 @@ class ChoiceInline(admin.TabularInline):
class QuizAdminForm(forms.ModelForm):
class Meta:
model = Quiz
exclude = []
@ -20,19 +27,20 @@ class QuizAdminForm(forms.ModelForm):
queryset=Question.objects.all().select_subclasses(),
required=False,
label=_("Questions"),
widget=FilteredSelectMultiple(
verbose_name=_("Questions"),
is_stacked=False))
widget=FilteredSelectMultiple(verbose_name=_("Questions"), is_stacked=False),
)
def __init__(self, *args, **kwargs):
super(QuizAdminForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['questions'].initial = self.instance.question_set.all().select_subclasses()
self.fields[
"questions"
].initial = self.instance.question_set.all().select_subclasses()
def save(self, commit=True):
quiz = super(QuizAdminForm, self).save(commit=False)
quiz.save()
quiz.question_set.set(self.cleaned_data['questions'])
quiz.question_set.set(self.cleaned_data["questions"])
self.save_m2m()
return quiz
@ -40,32 +48,43 @@ class QuizAdminForm(forms.ModelForm):
class QuizAdmin(admin.ModelAdmin):
form = QuizAdminForm
list_display = ('title', )
list_display = ("title",)
# list_filter = ('category',)
search_fields = ('description', 'category', )
search_fields = (
"description",
"category",
)
class MCQuestionAdmin(admin.ModelAdmin):
list_display = ('content', )
list_display = ("content",)
# list_filter = ('category',)
fields = ('content', 'figure', 'quiz', 'explanation', 'choice_order')
fields = ("content", "figure", "quiz", "explanation", "choice_order")
search_fields = ('content', 'explanation')
filter_horizontal = ('quiz',)
search_fields = ("content", "explanation")
filter_horizontal = ("quiz",)
inlines = [ChoiceInline]
class ProgressAdmin(admin.ModelAdmin):
search_fields = ('user', 'score', )
search_fields = (
"user",
"score",
)
class EssayQuestionAdmin(admin.ModelAdmin):
list_display = ('content', )
list_display = ("content",)
# list_filter = ('category',)
fields = ('content', 'quiz', 'explanation', )
search_fields = ('content', 'explanation')
filter_horizontal = ('quiz',)
fields = (
"content",
"quiz",
"explanation",
)
search_fields = ("content", "explanation")
filter_horizontal = ("quiz",)
admin.site.register(Quiz, QuizAdmin)
admin.site.register(MCQuestion, MCQuestionAdmin)

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class QuizConfig(AppConfig):
name = 'quiz'
name = "quiz"

View File

@ -14,18 +14,20 @@ class QuestionForm(forms.Form):
def __init__(self, question, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
choice_list = [x for x in question.get_choices_list()]
self.fields["answers"] = forms.ChoiceField(choices=choice_list, widget=RadioSelect)
self.fields["answers"] = forms.ChoiceField(
choices=choice_list, widget=RadioSelect
)
class EssayForm(forms.Form):
def __init__(self, question, *args, **kwargs):
super(EssayForm, self).__init__(*args, **kwargs)
self.fields["answers"] = forms.CharField(
widget=Textarea(attrs={'style': 'width:100%'}))
widget=Textarea(attrs={"style": "width:100%"})
)
class QuizAddForm(forms.ModelForm):
class Meta:
model = Quiz
exclude = []
@ -34,30 +36,35 @@ class QuizAddForm(forms.ModelForm):
queryset=Question.objects.all().select_subclasses(),
required=False,
label=_("Questions"),
widget=FilteredSelectMultiple(
verbose_name=_("Questions"),
is_stacked=False))
widget=FilteredSelectMultiple(verbose_name=_("Questions"), is_stacked=False),
)
def __init__(self, *args, **kwargs):
super(QuizAddForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['questions'].initial = self.instance.question_set.all().select_subclasses()
self.fields[
"questions"
].initial = self.instance.question_set.all().select_subclasses()
def save(self, commit=True):
quiz = super(QuizAddForm, self).save(commit=False)
quiz.save()
quiz.question_set.set(self.cleaned_data['questions'])
quiz.question_set.set(self.cleaned_data["questions"])
self.save_m2m()
return quiz
class MCQuestionForm(forms.ModelForm):
class Meta:
model = MCQuestion
exclude = ()
MCQuestionFormSet = inlineformset_factory(
MCQuestion, Choice, form=MCQuestionForm, fields=['choice', 'correct'], can_delete=True, extra=5
MCQuestion,
Choice,
form=MCQuestionForm,
fields=["choice", "correct"],
can_delete=True,
extra=5,
)

View File

@ -4,7 +4,10 @@ import json
from django.db import models
from django.urls import reverse
from django.core.exceptions import ValidationError, ImproperlyConfigured
from django.core.validators import (MaxValueValidator, validate_comma_separated_integer_list,)
from django.core.validators import (
MaxValueValidator,
validate_comma_separated_integer_list,
)
from django.utils.translation import gettext_lazy as _
from django.utils.timezone import now
from django.conf import settings
@ -17,15 +20,15 @@ from course.models import Course
from .utils import *
CHOICE_ORDER_OPTIONS = (
('content', _('Content')),
('random', _('Random')),
('none', _('None'))
("content", _("Content")),
("random", _("Random")),
("none", _("None")),
)
CATEGORY_OPTIONS = (
('assignment', _('Assignment')),
('exam', _('Exam')),
('practice', _('Practice Quiz'))
("assignment", _("Assignment")),
("exam", _("Exam")),
("practice", _("Practice Quiz")),
)
@ -33,12 +36,15 @@ class QuizManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (Q(title__icontains=query) |
Q(description__icontains=query)|
Q(category__icontains=query)|
Q(slug__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
or_lookup = (
Q(title__icontains=query)
| Q(description__icontains=query)
| Q(category__icontains=query)
| Q(slug__icontains=query)
)
qs = qs.filter(
or_lookup
).distinct() # distinct() is often necessary with Q lookups
return qs
@ -46,42 +52,76 @@ class Quiz(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True)
title = models.CharField(verbose_name=_("Title"), max_length=60, blank=False)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField(verbose_name=_("Description"), blank=True, help_text=_("a description of the quiz"))
description = models.TextField(
verbose_name=_("Description"),
blank=True,
help_text=_("a description of the quiz"),
)
category = models.TextField(choices=CATEGORY_OPTIONS, blank=True)
random_order = models.BooleanField(blank=False, default=False, verbose_name=_("Random Order"),
help_text=_("Display the questions in a random order or as they are set?"))
random_order = models.BooleanField(
blank=False,
default=False,
verbose_name=_("Random Order"),
help_text=_("Display the questions in a random order or as they are set?"),
)
# max_questions = models.PositiveIntegerField(blank=True, null=True, verbose_name=_("Max Questions"),
# help_text=_("Number of questions to be answered on each attempt."))
answers_at_end = models.BooleanField(blank=False, default=False, verbose_name=_("Answers at end"),
help_text=_("Correct answer is NOT shown after question. Answers displayed at the end."))
answers_at_end = models.BooleanField(
blank=False,
default=False,
verbose_name=_("Answers at end"),
help_text=_(
"Correct answer is NOT shown after question. Answers displayed at the end."
),
)
exam_paper = models.BooleanField(blank=False, default=False, verbose_name=_("Exam Paper"),
help_text=_("If yes, the result of each attempt by a user will be stored. Necessary for marking."))
exam_paper = models.BooleanField(
blank=False,
default=False,
verbose_name=_("Exam Paper"),
help_text=_(
"If yes, the result of each attempt by a user will be stored. Necessary for marking."
),
)
single_attempt = models.BooleanField(blank=False, default=False, verbose_name=_("Single Attempt"),
help_text=_("If yes, only one attempt by a user will be permitted."))
single_attempt = models.BooleanField(
blank=False,
default=False,
verbose_name=_("Single Attempt"),
help_text=_("If yes, only one attempt by a user will be permitted."),
)
pass_mark = models.SmallIntegerField(blank=True, default=50, verbose_name=_("Pass Mark"), validators=[MaxValueValidator(100)],
help_text=_("Percentage required to pass exam."))
pass_mark = models.SmallIntegerField(
blank=True,
default=50,
verbose_name=_("Pass Mark"),
validators=[MaxValueValidator(100)],
help_text=_("Percentage required to pass exam."),
)
draft = models.BooleanField(blank=True, default=False, verbose_name=_("Draft"),
help_text=_("If yes, the quiz is not displayed in the quiz list and can only be taken by users who can edit quizzes."))
draft = models.BooleanField(
blank=True,
default=False,
verbose_name=_("Draft"),
help_text=_(
"If yes, the quiz is not displayed in the quiz list and can only be taken by users who can edit quizzes."
),
)
timestamp = models.DateTimeField(auto_now=True)
objects = QuizManager()
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.single_attempt is True:
self.exam_paper = True
if self.pass_mark > 100:
raise ValidationError('%s is above 100' % self.pass_mark)
raise ValidationError("%s is above 100" % self.pass_mark)
if self.pass_mark < 0:
raise ValidationError('%s is below 0' % self.pass_mark)
raise ValidationError("%s is below 0" % self.pass_mark)
super(Quiz, self).save(force_insert, force_update, *args, **kwargs)
@ -101,18 +141,18 @@ class Quiz(models.Model):
def get_absolute_url(self):
# return reverse('quiz_start_page', kwargs={'pk': self.pk})
return reverse('quiz_index', kwargs={'slug': self.course.slug})
return reverse("quiz_index", kwargs={"slug": self.course.slug})
def quiz_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(quiz_pre_save_receiver, sender=Quiz)
class ProgressManager(models.Manager):
def new_progress(self, user):
new_progress = self.create(user=user, score="")
new_progress.save()
@ -120,8 +160,14 @@ class ProgressManager(models.Manager):
class Progress(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_("User"), on_delete=models.CASCADE)
score = models.CharField(max_length=1024, verbose_name=_("Score"), validators=[validate_comma_separated_integer_list])
user = models.OneToOneField(
settings.AUTH_USER_MODEL, verbose_name=_("User"), on_delete=models.CASCADE
)
score = models.CharField(
max_length=1024,
verbose_name=_("Score"),
validators=[validate_comma_separated_integer_list],
)
objects = ProgressManager()
@ -143,7 +189,17 @@ class Progress(models.Model):
def update_score(self, question, score_to_add=0, possible_to_add=0):
# category_test = Category.objects.filter(category=question.category).exists()
if any([item is False for item in [score_to_add, possible_to_add, isinstance(score_to_add, int), isinstance(possible_to_add, int)]]):
if any(
[
item is False
for item in [
score_to_add,
possible_to_add,
isinstance(score_to_add, int),
isinstance(possible_to_add, int),
]
]
):
return _("error"), _("category does not exist or invalid score")
to_find = re.escape(str(question.quiz)) + r",(?P<score>\d+),(?P<possible>\d+),"
@ -151,10 +207,12 @@ class Progress(models.Model):
match = re.search(to_find, self.score, re.IGNORECASE)
if match:
updated_score = int(match.group('score')) + abs(score_to_add)
updated_possible = int(match.group('possible')) + abs(possible_to_add)
updated_score = int(match.group("score")) + abs(score_to_add)
updated_possible = int(match.group("possible")) + abs(possible_to_add)
new_score = ",".join([str(question.quiz), str(updated_score), str(updated_possible), ""])
new_score = ",".join(
[str(question.quiz), str(updated_score), str(updated_possible), ""]
)
# swap old score for the new one
self.score = self.score.replace(match.group(), new_score)
@ -162,28 +220,33 @@ class Progress(models.Model):
else:
# if not present but existing, add with the points passed in
self.score += ",".join([str(question.quiz), str(score_to_add), str(possible_to_add), ""])
self.score += ",".join(
[str(question.quiz), str(score_to_add), str(possible_to_add), ""]
)
self.save()
def show_exams(self):
if self.user.is_superuser:
return Sitting.objects.filter(complete=True).order_by('-end')
return Sitting.objects.filter(complete=True).order_by("-end")
else:
return Sitting.objects.filter(user=self.user, complete=True).order_by('-end')
return Sitting.objects.filter(user=self.user, complete=True).order_by(
"-end"
)
class SittingManager(models.Manager):
def new_sitting(self, user, quiz, course):
if quiz.random_order is True:
question_set = quiz.question_set.all().select_subclasses().order_by('?')
question_set = quiz.question_set.all().select_subclasses().order_by("?")
else:
question_set = quiz.question_set.all().select_subclasses()
question_set = [item.id for item in question_set]
if len(question_set) == 0:
raise ImproperlyConfigured('Question set of the quiz is empty. Please configure questions properly')
raise ImproperlyConfigured(
"Question set of the quiz is empty. Please configure questions properly"
)
# if quiz.max_questions and quiz.max_questions < len(question_set):
# question_set = question_set[:quiz.max_questions]
@ -191,43 +254,70 @@ class SittingManager(models.Manager):
questions = ",".join(map(str, question_set)) + ","
new_sitting = self.create(
user=user, quiz=quiz, course=course, question_order=questions,
question_list=questions, incorrect_questions="",
user=user,
quiz=quiz,
course=course,
question_order=questions,
question_list=questions,
incorrect_questions="",
current_score=0,
complete=False,
user_answers='{}'
user_answers="{}",
)
return new_sitting
def user_sitting(self, user, quiz, course):
if quiz.single_attempt is True and self.filter(user=user, quiz=quiz, course=course, complete=True).exists():
if (
quiz.single_attempt is True
and self.filter(user=user, quiz=quiz, course=course, complete=True).exists()
):
return False
try:
sitting = self.get(user=user, quiz=quiz, course=course, complete=False)
except Sitting.DoesNotExist:
sitting = self.new_sitting(user, quiz, course)
except Sitting.MultipleObjectsReturned:
sitting = self.filter(user=user, quiz=quiz, course=course, complete=False)[0]
sitting = self.filter(user=user, quiz=quiz, course=course, complete=False)[
0
]
return sitting
class Sitting(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_("User"), on_delete=models.CASCADE)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("User"), on_delete=models.CASCADE
)
quiz = models.ForeignKey(Quiz, verbose_name=_("Quiz"), on_delete=models.CASCADE)
course = models.ForeignKey(Course, null=True, verbose_name=_("Course"), on_delete=models.CASCADE)
course = models.ForeignKey(
Course, null=True, verbose_name=_("Course"), on_delete=models.CASCADE
)
question_order = models.CharField(max_length=1024, verbose_name=_("Question Order"),
validators=[validate_comma_separated_integer_list])
question_order = models.CharField(
max_length=1024,
verbose_name=_("Question Order"),
validators=[validate_comma_separated_integer_list],
)
question_list = models.CharField(max_length=1024, verbose_name=_("Question List"),
validators=[validate_comma_separated_integer_list])
question_list = models.CharField(
max_length=1024,
verbose_name=_("Question List"),
validators=[validate_comma_separated_integer_list],
)
incorrect_questions = models.CharField(max_length=1024, blank=True, verbose_name=_("Incorrect questions"),
validators=[validate_comma_separated_integer_list])
incorrect_questions = models.CharField(
max_length=1024,
blank=True,
verbose_name=_("Incorrect questions"),
validators=[validate_comma_separated_integer_list],
)
current_score = models.IntegerField(verbose_name=_("Current Score"))
complete = models.BooleanField(default=False, blank=False, verbose_name=_("Complete"))
user_answers = models.TextField(blank=True, default='{}', verbose_name=_("User Answers"))
complete = models.BooleanField(
default=False, blank=False, verbose_name=_("Complete")
)
user_answers = models.TextField(
blank=True, default="{}", verbose_name=_("User Answers")
)
start = models.DateTimeField(auto_now_add=True, verbose_name=_("Start"))
end = models.DateTimeField(null=True, blank=True, verbose_name=_("End"))
@ -240,7 +330,7 @@ class Sitting(models.Model):
if not self.question_list:
return False
first, _ = self.question_list.split(',', 1)
first, _ = self.question_list.split(",", 1)
question_id = int(first)
return Question.objects.get_subclass(id=question_id)
@ -248,7 +338,7 @@ class Sitting(models.Model):
if not self.question_list:
return
_, others = self.question_list.split(',', 1)
_, others = self.question_list.split(",", 1)
self.question_list = others
self.save()
@ -261,14 +351,14 @@ class Sitting(models.Model):
return self.current_score
def _question_ids(self):
return [int(n) for n in self.question_order.split(',') if n]
return [int(n) for n in self.question_order.split(",") if n]
@property
def get_percent_correct(self):
dividend = float(self.current_score)
divisor = len(self._question_ids())
if divisor < 1:
return 0 # prevent divide by zero error
return 0 # prevent divide by zero error
if dividend > divisor:
return 100
@ -287,7 +377,7 @@ class Sitting(models.Model):
def add_incorrect_question(self, question):
if len(self.incorrect_questions) > 0:
self.incorrect_questions += ','
self.incorrect_questions += ","
self.incorrect_questions += str(question.id) + ","
if self.complete:
self.add_to_score(-1)
@ -295,12 +385,12 @@ class Sitting(models.Model):
@property
def get_incorrect_questions(self):
return [int(q) for q in self.incorrect_questions.split(',') if q]
return [int(q) for q in self.incorrect_questions.split(",") if q]
def remove_incorrect_question(self, question):
current = self.get_incorrect_questions
current.remove(question.id)
self.incorrect_questions = ','.join(map(str, current))
self.incorrect_questions = ",".join(map(str, current))
self.add_to_score(1)
self.save()
@ -323,7 +413,10 @@ class Sitting(models.Model):
def get_questions(self, with_answers=False):
question_ids = self._question_ids()
questions = sorted(self.quiz.question_set.filter(id__in=question_ids).select_subclasses(), key=lambda q: question_ids.index(q.id))
questions = sorted(
self.quiz.question_set.filter(id__in=question_ids).select_subclasses(),
key=lambda q: question_ids.index(q.id),
)
if with_answers:
user_answers = json.loads(self.user_answers)
@ -348,12 +441,21 @@ class Sitting(models.Model):
class Question(models.Model):
quiz = models.ManyToManyField(Quiz, verbose_name=_("Quiz"), blank=True)
figure = models.ImageField(upload_to='uploads/%Y/%m/%d', blank=True, null=True, verbose_name=_("Figure"))
content = models.CharField(max_length=1000, blank=False,
help_text=_("Enter the question text that you want displayed"), verbose_name=_('Question'))
explanation = models.TextField(max_length=2000, blank=True,
figure = models.ImageField(
upload_to="uploads/%Y/%m/%d", blank=True, null=True, verbose_name=_("Figure")
)
content = models.CharField(
max_length=1000,
blank=False,
help_text=_("Enter the question text that you want displayed"),
verbose_name=_("Question"),
)
explanation = models.TextField(
max_length=2000,
blank=True,
help_text=_("Explanation to be shown after the question has been answered."),
verbose_name=_('Explanation'))
verbose_name=_("Explanation"),
)
objects = InheritanceManager()
@ -366,12 +468,16 @@ class Question(models.Model):
class MCQuestion(Question):
choice_order = models.CharField(
max_length=30, null=True, blank=True,
max_length=30,
null=True,
blank=True,
choices=CHOICE_ORDER_OPTIONS,
help_text=_("The order in which multichoice choice options are displayed to the user"),
verbose_name=_("Choice Order"))
help_text=_(
"The order in which multichoice choice options are displayed to the user"
),
verbose_name=_("Choice Order"),
)
def check_if_correct(self, guess):
answer = Choice.objects.get(id=guess)
@ -382,11 +488,11 @@ class MCQuestion(Question):
return False
def order_choices(self, queryset):
if self.choice_order == 'content':
return queryset.order_by('choice')
if self.choice_order == 'random':
return queryset.order_by('?')
if self.choice_order == 'none':
if self.choice_order == "content":
return queryset.order_by("choice")
if self.choice_order == "random":
return queryset.order_by("?")
if self.choice_order == "none":
return queryset.order_by()
return queryset
@ -394,8 +500,10 @@ class MCQuestion(Question):
return self.order_choices(Choice.objects.filter(question=self))
def get_choices_list(self):
return [(choice.id, choice.choice) for choice in
self.order_choices(Choice.objects.filter(question=self))]
return [
(choice.id, choice.choice)
for choice in self.order_choices(Choice.objects.filter(question=self))
]
def answer_choice_to_string(self, guess):
return Choice.objects.get(id=guess).choice
@ -406,15 +514,23 @@ class MCQuestion(Question):
class Choice(models.Model):
question = models.ForeignKey(MCQuestion, verbose_name=_("Question"), on_delete=models.CASCADE)
question = models.ForeignKey(
MCQuestion, verbose_name=_("Question"), on_delete=models.CASCADE
)
choice = models.CharField(max_length=1000, blank=False,
choice = models.CharField(
max_length=1000,
blank=False,
help_text=_("Enter the choice text that you want displayed"),
verbose_name=_("Content"))
verbose_name=_("Content"),
)
correct = models.BooleanField(blank=False, default=False,
correct = models.BooleanField(
blank=False,
default=False,
help_text=_("Is this a correct answer?"),
verbose_name=_("Correct"))
verbose_name=_("Correct"),
)
def __str__(self):
return self.choice
@ -425,7 +541,6 @@ class Choice(models.Model):
class Essay_Question(Question):
def check_if_correct(self, guess):
return False

View File

@ -2,21 +2,23 @@ from django.urls import path
from .views import *
urlpatterns = [
path('<slug>/quizzes/', quiz_list, name='quiz_index'),
path('progress/', view=QuizUserProgressView.as_view(), name='quiz_progress'),
path("<slug>/quizzes/", quiz_list, name="quiz_index"),
path("progress/", view=QuizUserProgressView.as_view(), name="quiz_progress"),
# path('marking/<int:pk>/', view=QuizMarkingList.as_view(), name='quiz_marking'),
path('marking_list/', view=QuizMarkingList.as_view(), name='quiz_marking'),
path('marking/<int:pk>/', view=QuizMarkingDetail.as_view(), name='quiz_marking_detail'),
path('<int:pk>/<slug>/take/', view=QuizTake.as_view(), name='quiz_take'),
path('<slug>/quiz_add/', QuizCreateView.as_view(), name='quiz_create'),
path('<slug>/<int:pk>/add/', QuizUpdateView.as_view(), name='quiz_update'),
path('<slug>/<int:pk>/delete/', quiz_delete, name='quiz_delete'),
path('mc-question/add/<slug>/<int:quiz_id>/', MCQuestionCreate.as_view(), name='mc_create'),
path("marking_list/", view=QuizMarkingList.as_view(), name="quiz_marking"),
path(
"marking/<int:pk>/",
view=QuizMarkingDetail.as_view(),
name="quiz_marking_detail",
),
path("<int:pk>/<slug>/take/", view=QuizTake.as_view(), name="quiz_take"),
path("<slug>/quiz_add/", QuizCreateView.as_view(), name="quiz_create"),
path("<slug>/<int:pk>/add/", QuizUpdateView.as_view(), name="quiz_update"),
path("<slug>/<int:pk>/delete/", quiz_delete, name="quiz_delete"),
path(
"mc-question/add/<slug>/<int:quiz_id>/",
MCQuestionCreate.as_view(),
name="mc_create",
),
# path('mc-question/add/<int:pk>/<quiz_pk>/', MCQuestionCreate.as_view(), name='mc_create'),
]

View File

@ -7,7 +7,7 @@ from django.utils.text import slugify
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
return "".join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
@ -24,8 +24,7 @@ def unique_slug_generator(instance, new_slug=None):
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4)
)
slug=slug, randstr=random_string_generator(size=4)
)
return unique_slug_generator(instance, new_slug=new_slug)
return slug

View File

@ -4,7 +4,16 @@ from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, render, redirect
from django.utils.decorators import method_decorator
from django.views.generic import DetailView, ListView, TemplateView, FormView, CreateView, FormView, DeleteView, UpdateView
from django.views.generic import (
DetailView,
ListView,
TemplateView,
FormView,
CreateView,
FormView,
DeleteView,
UpdateView,
)
from django.contrib import messages
from django.urls import reverse_lazy
from django.db import transaction
@ -16,58 +25,62 @@ from .models import *
from .forms import *
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class QuizCreateView(CreateView):
model = Quiz
form_class = QuizAddForm
def get_context_data(self, *args, **kwargs):
context = super(QuizCreateView, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
context["course"] = Course.objects.get(slug=self.kwargs["slug"])
if self.request.POST:
context['form'] = QuizAddForm(self.request.POST)
context["form"] = QuizAddForm(self.request.POST)
# context['quiz'] = self.request.POST.get('quiz')
else:
context['form'] = QuizAddForm(initial={'course': Course.objects.get(slug=self.kwargs['slug'])})
context["form"] = QuizAddForm(
initial={"course": Course.objects.get(slug=self.kwargs["slug"])}
)
return context
def form_valid(self, form, **kwargs):
context = self.get_context_data()
form = context['form']
form = context["form"]
with transaction.atomic():
self.object = form.save()
if form.is_valid():
form.instance = self.object
form.save()
return redirect('mc_create', slug=self.kwargs['slug'], quiz_id=form.instance.id)
return redirect(
"mc_create", slug=self.kwargs["slug"], quiz_id=form.instance.id
)
return super(QuizCreateView, self).form_invalid(form)
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class QuizUpdateView(UpdateView):
model = Quiz
form_class = QuizAddForm
def get_context_data(self, *args, **kwargs):
context = super(QuizUpdateView, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
quiz = Quiz.objects.get(pk=self.kwargs['pk'])
context["course"] = Course.objects.get(slug=self.kwargs["slug"])
quiz = Quiz.objects.get(pk=self.kwargs["pk"])
if self.request.POST:
context['form'] = QuizAddForm(self.request.POST, instance=quiz)
context["form"] = QuizAddForm(self.request.POST, instance=quiz)
else:
context['form'] = QuizAddForm(instance=quiz)
context["form"] = QuizAddForm(instance=quiz)
return context
def form_valid(self, form, **kwargs):
context = self.get_context_data()
course = context['course']
form = context['form']
course = context["course"]
form = context["form"]
with transaction.atomic():
self.object = form.save()
if form.is_valid():
form.instance = self.object
form.save()
return redirect('quiz_index', course.slug)
return redirect("quiz_index", course.slug)
return super(QuizUpdateView, self).form_invalid(form)
@ -77,54 +90,62 @@ def quiz_delete(request, slug, pk):
quiz = Quiz.objects.get(pk=pk)
course = Course.objects.get(slug=slug)
quiz.delete()
messages.success(request, f'successfuly deleted.')
return redirect('quiz_index', quiz.course.slug)
messages.success(request, f"successfuly deleted.")
return redirect("quiz_index", quiz.course.slug)
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class MCQuestionCreate(CreateView):
model = MCQuestion
form_class = MCQuestionForm
def get_context_data(self, **kwargs):
context = super(MCQuestionCreate, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
context['quiz_obj'] = Quiz.objects.get(id=self.kwargs['quiz_id'])
context['quizQuestions'] = Question.objects.filter(quiz=self.kwargs['quiz_id']).count()
context["course"] = Course.objects.get(slug=self.kwargs["slug"])
context["quiz_obj"] = Quiz.objects.get(id=self.kwargs["quiz_id"])
context["quizQuestions"] = Question.objects.filter(
quiz=self.kwargs["quiz_id"]
).count()
if self.request.POST:
context['form'] = MCQuestionForm(self.request.POST)
context['formset'] = MCQuestionFormSet(self.request.POST)
context["form"] = MCQuestionForm(self.request.POST)
context["formset"] = MCQuestionFormSet(self.request.POST)
else:
context['form'] = MCQuestionForm(initial={'quiz': self.kwargs['quiz_id']})
context['formset'] = MCQuestionFormSet()
context["form"] = MCQuestionForm(initial={"quiz": self.kwargs["quiz_id"]})
context["formset"] = MCQuestionFormSet()
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
course = context['course']
formset = context["formset"]
course = context["course"]
with transaction.atomic():
form.instance.question = self.request.POST.get('content')
form.instance.question = self.request.POST.get("content")
self.object = form.save()
if formset.is_valid():
formset.instance = self.object
formset.save()
if "another" in self.request.POST:
return redirect('mc_create', slug=self.kwargs['slug'], quiz_id=self.kwargs['quiz_id'])
return redirect('quiz_index', course.slug)
return redirect(
"mc_create",
slug=self.kwargs["slug"],
quiz_id=self.kwargs["quiz_id"],
)
return redirect("quiz_index", course.slug)
return super(MCQuestionCreate, self).form_invalid(form)
@login_required
def quiz_list(request, slug):
quizzes = Quiz.objects.filter(course__slug = slug).order_by('-timestamp')
course = Course.objects.get(slug = slug)
return render(request, 'quiz/quiz_list.html', {'quizzes': quizzes, 'course': course})
quizzes = Quiz.objects.filter(course__slug=slug).order_by("-timestamp")
course = Course.objects.get(slug=slug)
return render(
request, "quiz/quiz_list.html", {"quizzes": quizzes, "course": course}
)
# return render(request, 'quiz/quiz_list.html', {'quizzes': quizzes})
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class QuizMarkerMixin(object):
@method_decorator(login_required)
# @method_decorator(permission_required('quiz.view_sittings'))
@ -136,16 +157,16 @@ class QuizMarkerMixin(object):
class SittingFilterTitleMixin(object):
def get_queryset(self):
queryset = super(SittingFilterTitleMixin, self).get_queryset()
quiz_filter = self.request.GET.get('quiz_filter')
quiz_filter = self.request.GET.get("quiz_filter")
if quiz_filter:
queryset = queryset.filter(quiz__title__icontains=quiz_filter)
return queryset
@method_decorator([login_required], name='dispatch')
@method_decorator([login_required], name="dispatch")
class QuizUserProgressView(TemplateView):
template_name = 'progress.html'
template_name = "progress.html"
def dispatch(self, request, *args, **kwargs):
return super(QuizUserProgressView, self).dispatch(request, *args, **kwargs)
@ -153,16 +174,19 @@ class QuizUserProgressView(TemplateView):
def get_context_data(self, **kwargs):
context = super(QuizUserProgressView, self).get_context_data(**kwargs)
progress, c = Progress.objects.get_or_create(user=self.request.user)
context['cat_scores'] = progress.list_all_cat_scores
context['exams'] = progress.show_exams()
context['exams_counter'] = progress.show_exams().count()
context["cat_scores"] = progress.list_all_cat_scores
context["exams"] = progress.show_exams()
context["exams_counter"] = progress.show_exams().count()
return context
from result.models import TakenCourse
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class QuizMarkingList(QuizMarkerMixin, SittingFilterTitleMixin, ListView):
model = Sitting
# def get_context_data(self, **kwargs):
# context = super(QuizMarkingList, self).get_context_data(**kwargs)
# context['queryset_counter'] = super(QuizMarkingList, self).get_queryset().filter(complete=True).filter(course__allocated_course__lecturer__pk=self.request.user.id).count()
@ -172,24 +196,31 @@ class QuizMarkingList(QuizMarkerMixin, SittingFilterTitleMixin, ListView):
if self.request.user.is_superuser:
queryset = super(QuizMarkingList, self).get_queryset().filter(complete=True)
else:
queryset = super(QuizMarkingList, self).get_queryset().filter(quiz__course__allocated_course__lecturer__pk=self.request.user.id).filter(complete=True)
queryset = (
super(QuizMarkingList, self)
.get_queryset()
.filter(
quiz__course__allocated_course__lecturer__pk=self.request.user.id
)
.filter(complete=True)
)
# search by user
user_filter = self.request.GET.get('user_filter')
user_filter = self.request.GET.get("user_filter")
if user_filter:
queryset = queryset.filter(user__username__icontains=user_filter)
return queryset
@method_decorator([login_required, lecturer_required], name='dispatch')
@method_decorator([login_required, lecturer_required], name="dispatch")
class QuizMarkingDetail(QuizMarkerMixin, DetailView):
model = Sitting
def post(self, request, *args, **kwargs):
sitting = self.get_object()
q_to_toggle = request.POST.get('qid', None)
q_to_toggle = request.POST.get("qid", None)
if q_to_toggle:
q = Question.objects.get_subclass(id=int(q_to_toggle))
if int(q_to_toggle) in sitting.get_incorrect_questions:
@ -201,37 +232,42 @@ class QuizMarkingDetail(QuizMarkerMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(QuizMarkingDetail, self).get_context_data(**kwargs)
context['questions'] = context['sitting'].get_questions(with_answers=True)
context["questions"] = context["sitting"].get_questions(with_answers=True)
return context
# @method_decorator([login_required, student_required], name='dispatch')
@method_decorator([login_required], name='dispatch')
@method_decorator([login_required], name="dispatch")
class QuizTake(FormView):
form_class = QuestionForm
template_name = 'question.html'
result_template_name = 'result.html'
template_name = "question.html"
result_template_name = "result.html"
# single_complete_template_name = 'single_complete.html'
def dispatch(self, request, *args, **kwargs):
self.quiz = get_object_or_404(Quiz, slug=self.kwargs['slug'])
self.course = get_object_or_404(Course, pk=self.kwargs['pk'])
self.quiz = get_object_or_404(Quiz, slug=self.kwargs["slug"])
self.course = get_object_or_404(Course, pk=self.kwargs["pk"])
quizQuestions = Question.objects.filter(quiz=self.quiz).count()
course = get_object_or_404(Course, pk=self.kwargs['pk'])
course = get_object_or_404(Course, pk=self.kwargs["pk"])
if quizQuestions <= 0:
messages.warning(request, f'Question set of the quiz is empty. try later!')
return redirect('quiz_index', self.course.slug)
messages.warning(request, f"Question set of the quiz is empty. try later!")
return redirect("quiz_index", self.course.slug)
if self.quiz.draft and not request.user.has_perm('quiz.change_quiz'):
if self.quiz.draft and not request.user.has_perm("quiz.change_quiz"):
raise PermissionDenied
self.sitting = Sitting.objects.user_sitting(request.user, self.quiz, self.course)
self.sitting = Sitting.objects.user_sitting(
request.user, self.quiz, self.course
)
if self.sitting is False:
# return render(request, self.single_complete_template_name)
messages.info(request, f'You have already sat this exam and only one sitting is permitted')
return redirect('quiz_index', self.course.slug)
messages.info(
request,
f"You have already sat this exam and only one sitting is permitted",
)
return redirect("quiz_index", self.course.slug)
return super(QuizTake, self).dispatch(request, *args, **kwargs)
@ -262,18 +298,18 @@ class QuizTake(FormView):
def get_context_data(self, **kwargs):
context = super(QuizTake, self).get_context_data(**kwargs)
context['question'] = self.question
context['quiz'] = self.quiz
context['course'] = get_object_or_404(Course, pk=self.kwargs['pk'])
if hasattr(self, 'previous'):
context['previous'] = self.previous
if hasattr(self, 'progress'):
context['progress'] = self.progress
context["question"] = self.question
context["quiz"] = self.quiz
context["course"] = get_object_or_404(Course, pk=self.kwargs["pk"])
if hasattr(self, "previous"):
context["previous"] = self.previous
if hasattr(self, "progress"):
context["progress"] = self.progress
return context
def form_valid_user(self, form):
progress, c = Progress.objects.get_or_create(user=self.request.user)
guess = form.cleaned_data['answers']
guess = form.cleaned_data["answers"]
is_correct = self.question.check_if_correct(guess)
if is_correct is True:
@ -285,11 +321,11 @@ class QuizTake(FormView):
if self.quiz.answers_at_end is not True:
self.previous = {
'previous_answer': guess,
'previous_outcome': is_correct,
'previous_question': self.question,
'answers': self.question.get_choices(),
'question_type': {self.question.__class__.__name__: True}
"previous_answer": guess,
"previous_outcome": is_correct,
"previous_question": self.question,
"answers": self.question.get_choices(),
"question_type": {self.question.__class__.__name__: True},
}
else:
self.previous = {}
@ -299,23 +335,27 @@ class QuizTake(FormView):
def final_result_user(self):
results = {
'course': get_object_or_404(Course, pk=self.kwargs['pk']),
'quiz': self.quiz,
'score': self.sitting.get_current_score,
'max_score': self.sitting.get_max_score,
'percent': self.sitting.get_percent_correct,
'sitting': self.sitting,
'previous': self.previous,
'course': get_object_or_404(Course, pk=self.kwargs['pk'])
"course": get_object_or_404(Course, pk=self.kwargs["pk"]),
"quiz": self.quiz,
"score": self.sitting.get_current_score,
"max_score": self.sitting.get_max_score,
"percent": self.sitting.get_percent_correct,
"sitting": self.sitting,
"previous": self.previous,
"course": get_object_or_404(Course, pk=self.kwargs["pk"]),
}
self.sitting.mark_quiz_complete()
if self.quiz.answers_at_end:
results['questions'] = self.sitting.get_questions(with_answers=True)
results['incorrect_questions'] = self.sitting.get_incorrect_questions
results["questions"] = self.sitting.get_questions(with_answers=True)
results["incorrect_questions"] = self.sitting.get_incorrect_questions
if self.quiz.exam_paper is False or self.request.user.is_superuser or self.request.user.is_lecturer :
if (
self.quiz.exam_paper is False
or self.request.user.is_superuser
or self.request.user.is_lecturer
):
self.sitting.delete()
return render(self.request, self.result_template_name, results)

View File

@ -6,8 +6,16 @@ from .models import TakenCourse, Result
class ScoreAdmin(admin.ModelAdmin):
list_display = [
'student', 'course', 'assignment', 'mid_exam', 'quiz',
'attendance', 'final_exam', 'total', 'grade', 'comment'
"student",
"course",
"assignment",
"mid_exam",
"quiz",
"attendance",
"final_exam",
"total",
"grade",
"comment",
]

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class ResultConfig(AppConfig):
name = 'result'
name = "result"

View File

@ -6,13 +6,13 @@ from app.models import Session, Semester
from course.models import Course
YEARS = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(4, '5'),
(4, '6'),
)
(1, "1"),
(2, "2"),
(3, "3"),
(4, "4"),
(4, "5"),
(4, "6"),
)
# LEVEL_COURSE = "Level course"
BACHLOAR_DEGREE = "Bachloar"
@ -48,18 +48,18 @@ F = "F"
NG = "NG"
GRADE = (
(A_plus, "A+"),
(A, "A"),
(A_minus, "A-"),
(B_plus, "B+"),
(B, "B"),
(B_minus, "B-"),
(C_plus, "C+"),
(C, "C"),
(C_minus, "C-"),
(D, "D"),
(F, "F"),
(NG, "NG"),
(A_plus, "A+"),
(A, "A"),
(A_minus, "A-"),
(B_plus, "B+"),
(B, "B"),
(B_minus, "B-"),
(C_plus, "C+"),
(C, "C"),
(C_minus, "C-"),
(D, "D"),
(F, "F"),
(NG, "NG"),
)
PASS = "PASS"
@ -84,7 +84,7 @@ class TakenCourseManager(models.Manager):
else:
cart_obj = Cart.objects.new(user=request.user)
new_obj = True
request.session['cart_id'] = cart_obj.id
request.session["cart_id"] = cart_obj.id
return cart_obj, new_obj
def new(self, user=None):
@ -97,7 +97,9 @@ class TakenCourseManager(models.Manager):
class TakenCourse(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='taken_courses')
course = models.ForeignKey(
Course, on_delete=models.CASCADE, related_name="taken_courses"
)
assignment = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
mid_exam = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
quiz = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
@ -109,14 +111,20 @@ class TakenCourse(models.Model):
comment = models.CharField(choices=COMMENT, max_length=200, blank=True)
def get_absolute_url(self):
return reverse('course_detail', kwargs={'slug': self.course.slug})
return reverse("course_detail", kwargs={"slug": self.course.slug})
def __str__(self):
return "{0} ({1})".format(self.course.title, self.course.code)
# @staticmethod
def get_total(self, assignment, mid_exam, quiz, attendance, final_exam):
return float(assignment) + float(mid_exam) + float(quiz) + float(attendance) + float(final_exam)
return (
float(assignment)
+ float(mid_exam)
+ float(quiz)
+ float(attendance)
+ float(final_exam)
)
# @staticmethod
def get_grade(self, total):
@ -191,7 +199,11 @@ class TakenCourse(models.Model):
def calculate_gpa(self, total_credit_in_semester):
current_semester = Semester.objects.get(is_current_semester=True)
student = TakenCourse.objects.filter(student=self.student, course__level=self.student.level, course__semester=current_semester)
student = TakenCourse.objects.filter(
student=self.student,
course__level=self.student.level,
course__semester=current_semester,
)
p = 0
point = 0
for i in student:
@ -220,14 +232,16 @@ class TakenCourse(models.Model):
point = 0
p += int(credit) * point
try:
gpa = (p / total_credit_in_semester)
gpa = p / total_credit_in_semester
return round(gpa, 2)
except ZeroDivisionError:
return 0
def calculate_cgpa(self):
current_semester = Semester.objects.get(is_current_semester=True)
previousResult = Result.objects.filter(student__id=self.student.id, level__lt=self.student.level)
previousResult = Result.objects.filter(
student__id=self.student.id, level__lt=self.student.level
)
previousCGPA = 0
for i in previousResult:
if i.cgpa is not None:
@ -237,18 +251,24 @@ class TakenCourse(models.Model):
first_sem_gpa = 0.0
sec_sem_gpa = 0.0
try:
first_sem_result = Result.objects.get(student=self.student.id, semester=FIRST, level=self.student.level)
first_sem_result = Result.objects.get(
student=self.student.id, semester=FIRST, level=self.student.level
)
first_sem_gpa += first_sem_result.gpa
except:
first_sem_gpa = 0
try:
sec_sem_result = Result.objects.get(student=self.student.id, semester=SECOND, level=self.student.level)
sec_sem_result = Result.objects.get(
student=self.student.id, semester=SECOND, level=self.student.level
)
sec_sem_gpa += sec_sem_result.gpa
except:
sec_sem_gpa = 0
taken_courses = TakenCourse.objects.filter(student=self.student, student__level=self.student.level)
taken_courses = TakenCourse.objects.filter(
student=self.student, student__level=self.student.level
)
TCC = 0
TCP = 0
for i in taken_courses:

View File

@ -1,17 +1,21 @@
from django.urls import path
from .views import (
add_score, add_score_for, grade_result, assessment_result,
course_registration_form, result_sheet_pdf_view
add_score,
add_score_for,
grade_result,
assessment_result,
course_registration_form,
result_sheet_pdf_view,
)
urlpatterns = [
path('manage-score/', add_score, name='add_score'),
path('manage-score/<int:id>/', add_score_for, name='add_score_for'),
path('grade/', grade_result, name="grade_results"),
path('assessment/', assessment_result, name="ass_results"),
path('result/print/<int:id>/', result_sheet_pdf_view, name='result_sheet_pdf_view'),
path('registration/form/', course_registration_form, name='course_registration_form'),
path("manage-score/", add_score, name="add_score"),
path("manage-score/<int:id>/", add_score_for, name="add_score_for"),
path("grade/", grade_result, name="grade_results"),
path("assessment/", assessment_result, name="ass_results"),
path("result/print/<int:id>/", result_sheet_pdf_view, name="result_sheet_pdf_view"),
path(
"registration/form/", course_registration_form, name="course_registration_form"
),
]

View File

@ -12,13 +12,21 @@ from course.models import Course
from accounts.decorators import lecturer_required, student_required
from .models import TakenCourse, Result
#pdf
# pdf
from django.core.files.storage import FileSystemStorage
from django.http import HttpResponse, JsonResponse
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image, LongTable
from reportlab.platypus import (
SimpleDocTemplate,
Paragraph,
Spacer,
Table,
TableStyle,
Image,
LongTable,
)
from reportlab.lib.styles import getSampleStyleSheet, black, ParagraphStyle
from reportlab.lib.enums import TA_JUSTIFY,TA_LEFT,TA_CENTER,TA_RIGHT
from reportlab.lib.enums import TA_JUSTIFY, TA_LEFT, TA_CENTER, TA_RIGHT
from reportlab.platypus.tables import Table
from reportlab.lib.units import inch
from reportlab.lib import colors
@ -26,6 +34,7 @@ from .models import *
cm = 2.54
# ########################################################
# Score Add & Add for
# ########################################################
@ -38,15 +47,19 @@ def add_score(request):
"""
current_session = Session.objects.get(is_current_session=True)
current_semester = get_object_or_404(Semester, is_current_semester=True, session=current_session)
current_semester = get_object_or_404(
Semester, is_current_semester=True, session=current_session
)
# semester = Course.objects.filter(allocated_course__lecturer__pk=request.user.id, semester=current_semester)
courses = Course.objects.filter(allocated_course__lecturer__pk=request.user.id).filter(semester=current_semester)
courses = Course.objects.filter(
allocated_course__lecturer__pk=request.user.id
).filter(semester=current_semester)
context = {
"current_session": current_session,
"current_semester": current_semester,
"courses": courses,
}
return render(request, 'result/add_score.html', context)
return render(request, "result/add_score.html", context)
@login_required
@ -57,10 +70,13 @@ def add_score_for(request, id):
in a specific semester and session
"""
current_session = Session.objects.get(is_current_session=True)
current_semester = get_object_or_404(Semester, is_current_semester=True, session=current_session)
if request.method == 'GET':
courses = Course.objects.filter(allocated_course__lecturer__pk=request.user.id).filter(
semester=current_semester)
current_semester = get_object_or_404(
Semester, is_current_semester=True, session=current_session
)
if request.method == "GET":
courses = Course.objects.filter(
allocated_course__lecturer__pk=request.user.id
).filter(semester=current_semester)
course = Course.objects.get(pk=id)
# myclass = Class.objects.get(lecturer__pk=request.user.id)
# myclass = get_object_or_404(Class, lecturer__pk=request.user.id)
@ -68,8 +84,13 @@ def add_score_for(request, id):
# students = TakenCourse.objects.filter(course__allocated_course__lecturer__pk=request.user.id).filter(
# course__id=id).filter(student__allocated_student__lecturer__pk=request.user.id).filter(
# course__semester=current_semester)
students = TakenCourse.objects.filter(course__allocated_course__lecturer__pk=request.user.id).filter(
course__id=id).filter(course__semester=current_semester)
students = (
TakenCourse.objects.filter(
course__allocated_course__lecturer__pk=request.user.id
)
.filter(course__id=id)
.filter(course__semester=current_semester)
)
context = {
"title": "Submit Score | DjangoSMS",
"courses": courses,
@ -79,29 +100,40 @@ def add_score_for(request, id):
"current_session": current_session,
"current_semester": current_semester,
}
return render(request, 'result/add_score_for.html', context)
return render(request, "result/add_score_for.html", context)
if request.method == 'POST':
if request.method == "POST":
ids = ()
data = request.POST.copy()
data.pop('csrfmiddlewaretoken', None) # remove csrf_token
data.pop("csrfmiddlewaretoken", None) # remove csrf_token
for key in data.keys():
ids = ids + (str(key),) # gather all the all students id (i.e the keys) in a tuple
for s in range(0, len(ids)): # iterate over the list of student ids gathered above
ids = ids + (
str(key),
) # gather all the all students id (i.e the keys) in a tuple
for s in range(
0, len(ids)
): # iterate over the list of student ids gathered above
student = TakenCourse.objects.get(id=ids[s])
# print(student)
# print(student.student)
# print(student.student.department.id)
courses = Course.objects.filter(level=student.student.level).filter(program__pk=student.student.department.id).filter(
semester=current_semester) # all courses of a specific level in current semester
courses = (
Course.objects.filter(level=student.student.level)
.filter(program__pk=student.student.department.id)
.filter(semester=current_semester)
) # all courses of a specific level in current semester
total_credit_in_semester = 0
for i in courses:
if i == courses.count():
break
else:
total_credit_in_semester += int(i.credit)
score = data.getlist(ids[s]) # get list of score for current student in the loop
assignment = score[0] # subscript the list to get the fisrt value > ca score
score = data.getlist(
ids[s]
) # get list of score for current student in the loop
assignment = score[
0
] # subscript the list to get the fisrt value > ca score
mid_exam = score[1] # do the same for exam score
quiz = score[2]
attendance = score[3]
@ -113,7 +145,13 @@ def add_score_for(request, id):
obj.attendance = attendance # set current student attendance score
obj.final_exam = final_exam # set current student final_exam score
obj.total = obj.get_total(assignment=assignment, mid_exam=mid_exam, quiz=quiz, attendance=attendance, final_exam=final_exam)
obj.total = obj.get_total(
assignment=assignment,
mid_exam=mid_exam,
quiz=quiz,
attendance=attendance,
final_exam=final_exam,
)
obj.grade = obj.get_grade(total=obj.total)
# obj.total = obj.get_total(assignment, mid_exam, quiz, attendance, final_exam)
@ -129,13 +167,23 @@ def add_score_for(request, id):
cgpa = obj.calculate_cgpa()
try:
a = Result.objects.get(student=student.student, semester=current_semester, session=current_session, level=student.student.level)
a = Result.objects.get(
student=student.student,
semester=current_semester,
session=current_session,
level=student.student.level,
)
a.gpa = gpa
a.cgpa = cgpa
a.save()
except:
Result.objects.get_or_create(student=student.student, gpa=gpa, semester=current_semester,
session=current_session, level=student.student.level)
Result.objects.get_or_create(
student=student.student,
gpa=gpa,
semester=current_semester,
session=current_session,
level=student.student.level,
)
# try:
# a = Result.objects.get(student=student.student, semester=current_semester, level=student.student.level)
@ -145,9 +193,11 @@ def add_score_for(request, id):
# except:
# Result.objects.get_or_create(student=student.student, gpa=gpa, semester=current_semester, level=student.student.level)
messages.success(request, 'Successfully Recorded! ')
return HttpResponseRedirect(reverse_lazy('add_score_for', kwargs={'id': id}))
return HttpResponseRedirect(reverse_lazy('add_score_for', kwargs={'id': id}))
messages.success(request, "Successfully Recorded! ")
return HttpResponseRedirect(reverse_lazy("add_score_for", kwargs={"id": id}))
return HttpResponseRedirect(reverse_lazy("add_score_for", kwargs={"id": id}))
# ########################################################
@ -155,7 +205,9 @@ def add_score_for(request, id):
@student_required
def grade_result(request):
student = Student.objects.get(student__pk=request.user.id)
courses = TakenCourse.objects.filter(student__student__pk=request.user.id).filter(course__level=student.level)
courses = TakenCourse.objects.filter(student__student__pk=request.user.id).filter(
course__level=student.level
)
# total_credit_in_semester = 0
results = Result.objects.filter(student__student__pk=request.user.id)
@ -180,7 +232,11 @@ def grade_result(request):
for i in results:
previousLEVEL = i.level
try:
a = Result.objects.get(student__student__pk=request.user.id, level=previousLEVEL, semester="Second")
a = Result.objects.get(
student__student__pk=request.user.id,
level=previousLEVEL,
semester="Second",
)
previousCGPA = a.cgpa
break
except:
@ -191,20 +247,23 @@ def grade_result(request):
"results": results,
"sorted_result": sorted_result,
"student": student,
'total_first_semester_credit': total_first_semester_credit,
'total_sec_semester_credit': total_sec_semester_credit,
'total_first_and_second_semester_credit': total_first_semester_credit + total_sec_semester_credit,
"total_first_semester_credit": total_first_semester_credit,
"total_sec_semester_credit": total_sec_semester_credit,
"total_first_and_second_semester_credit": total_first_semester_credit
+ total_sec_semester_credit,
"previousCGPA": previousCGPA,
}
return render(request, 'result/grade_results.html', context)
return render(request, "result/grade_results.html", context)
@login_required
@student_required
def assessment_result(request):
student = Student.objects.get(student__pk=request.user.id)
courses = TakenCourse.objects.filter(student__student__pk=request.user.id, course__level=student.level)
courses = TakenCourse.objects.filter(
student__student__pk=request.user.id, course__level=student.level
)
result = Result.objects.filter(student__student__pk=request.user.id)
context = {
@ -213,7 +272,7 @@ def assessment_result(request):
"student": student,
}
return render(request, 'result/assessment_results.html', context)
return render(request, "result/assessment_results.html", context)
@login_required
@ -225,14 +284,29 @@ def result_sheet_pdf_view(request, id):
course = get_object_or_404(Course, id=id)
no_of_pass = TakenCourse.objects.filter(course__pk=id, comment="PASS").count()
no_of_fail = TakenCourse.objects.filter(course__pk=id, comment="FAIL").count()
fname = str(current_semester) + '_semester_' + str(current_session) + '_' + str(course) + '_resultSheet.pdf'
fname = (
str(current_semester)
+ "_semester_"
+ str(current_session)
+ "_"
+ str(course)
+ "_resultSheet.pdf"
)
fname = fname.replace("/", "-")
flocation = settings.MEDIA_ROOT + "/result_sheet/" + fname
doc = SimpleDocTemplate(flocation, rightMargin=0, leftMargin=6.5 * cm, topMargin=0.3 * cm, bottomMargin=0)
doc = SimpleDocTemplate(
flocation,
rightMargin=0,
leftMargin=6.5 * cm,
topMargin=0.3 * cm,
bottomMargin=0,
)
styles = getSampleStyleSheet()
styles.add(ParagraphStyle( name="ParagraphTitle", fontSize=11, fontName="FreeSansBold"))
Story = [Spacer(1,.2)]
styles.add(
ParagraphStyle(name="ParagraphTitle", fontSize=11, fontName="FreeSansBold")
)
Story = [Spacer(1, 0.2)]
style = styles["Normal"]
# picture = request.user.picture
@ -250,7 +324,7 @@ def result_sheet_pdf_view(request, id):
print("\nsettings.MEDIA_ROOT", settings.MEDIA_ROOT)
print("\nsettings.STATICFILES_DIRS[0]", settings.STATICFILES_DIRS[0])
logo = settings.STATICFILES_DIRS[0] + "/img/logo.png"
im = Image(logo, 1*inch, 1*inch)
im = Image(logo, 1 * inch, 1 * inch)
im.__setattr__("_offs_x", -200)
im.__setattr__("_offs_y", -45)
Story.append(im)
@ -261,10 +335,16 @@ def result_sheet_pdf_view(request, id):
normal.fontName = "Helvetica"
normal.fontSize = 12
normal.leading = 15
title = "<b> "+str(current_semester) + " Semester " + str(current_session) + " Result Sheet</b>"
title = (
"<b> "
+ str(current_semester)
+ " Semester "
+ str(current_session)
+ " Result Sheet</b>"
)
title = Paragraph(title.upper(), normal)
Story.append(title)
Story.append(Spacer(1,0.1*inch))
Story.append(Spacer(1, 0.1 * inch))
style = getSampleStyleSheet()
normal = style["Normal"]
@ -275,7 +355,7 @@ def result_sheet_pdf_view(request, id):
title = "<b>Course lecturer: " + request.user.get_full_name + "</b>"
title = Paragraph(title.upper(), normal)
Story.append(title)
Story.append(Spacer(1,0.1*inch))
Story.append(Spacer(1, 0.1 * inch))
normal = style["Normal"]
normal.alignment = TA_CENTER
@ -286,46 +366,74 @@ def result_sheet_pdf_view(request, id):
title = "<b>Level: </b>" + str(level.course.level)
title = Paragraph(title.upper(), normal)
Story.append(title)
Story.append(Spacer(1,.6*inch))
Story.append(Spacer(1, 0.6 * inch))
elements = []
count = 0
header = [('S/N', 'ID NO.', 'FULL NAME', 'TOTAL', 'GRADE', 'POINT', 'COMMENT')]
header = [("S/N", "ID NO.", "FULL NAME", "TOTAL", "GRADE", "POINT", "COMMENT")]
table_header = Table(header, [inch], [0.5*inch])
table_header = Table(header, [inch], [0.5 * inch])
table_header.setStyle(
TableStyle([
('BACKGROUND',(0,0),(-1,-1),colors.black),
('TEXTCOLOR',(1,0),(-1,-1),colors.white),
('TEXTCOLOR',(0,0),(0,0),colors.cyan),
('ALIGN',(0,0),(-1,-1),'CENTER'),
('VALIGN',(0,0),(-1,-1),'MIDDLE'),
('BOX',(0,0),(-1,-1),1,colors.black),
]))
TableStyle(
[
("BACKGROUND", (0, 0), (-1, -1), colors.black),
("TEXTCOLOR", (1, 0), (-1, -1), colors.white),
("TEXTCOLOR", (0, 0), (0, 0), colors.cyan),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("BOX", (0, 0), (-1, -1), 1, colors.black),
]
)
)
Story.append(table_header)
for student in result:
data = [(count+1, student.student.student.username.upper(), Paragraph(student.student.student.get_full_name.capitalize(), styles['Normal']),
student.total, student.grade, student.point, student.comment)]
data = [
(
count + 1,
student.student.student.username.upper(),
Paragraph(
student.student.student.get_full_name.capitalize(), styles["Normal"]
),
student.total,
student.grade,
student.point,
student.comment,
)
]
color = colors.black
if student.grade == 'F':
if student.grade == "F":
color = colors.red
count += 1
t_body = Table(data, colWidths=[inch])
t_body.setStyle(
TableStyle([
('INNERGRID', (0,0), (-1,-1), 0.05, colors.black),
('BOX', (0,0), (-1,-1), 0.1, colors.black),
]))
TableStyle(
[
("INNERGRID", (0, 0), (-1, -1), 0.05, colors.black),
("BOX", (0, 0), (-1, -1), 0.1, colors.black),
]
)
)
Story.append(t_body)
Story.append(Spacer(1,1*inch))
style_right = ParagraphStyle(name='right', parent=styles['Normal'], alignment=TA_RIGHT)
Story.append(Spacer(1, 1 * inch))
style_right = ParagraphStyle(
name="right", parent=styles["Normal"], alignment=TA_RIGHT
)
tbl_data = [
[Paragraph("<b>Date:</b>_____________________________", styles["Normal"]), Paragraph("<b>No. of PASS:</b> " + str(no_of_pass), style_right)],
[Paragraph("<b>Siganture / Stamp:</b> _____________________________", styles["Normal"]), Paragraph("<b>No. of FAIL: </b>" + str(no_of_fail), style_right)]]
[
Paragraph("<b>Date:</b>_____________________________", styles["Normal"]),
Paragraph("<b>No. of PASS:</b> " + str(no_of_pass), style_right),
],
[
Paragraph(
"<b>Siganture / Stamp:</b> _____________________________",
styles["Normal"],
),
Paragraph("<b>No. of FAIL: </b>" + str(no_of_fail), style_right),
],
]
tbl = Table(tbl_data)
Story.append(tbl)
@ -333,8 +441,8 @@ def result_sheet_pdf_view(request, id):
fs = FileSystemStorage(settings.MEDIA_ROOT + "/result_sheet")
with fs.open(fname) as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'inline; filename=' + fname + ''
response = HttpResponse(pdf, content_type="application/pdf")
response["Content-Disposition"] = "inline; filename=" + fname + ""
return response
return response
@ -345,16 +453,18 @@ def course_registration_form(request):
current_semester = Semester.objects.get(is_current_semester=True)
current_session = Session.objects.get(is_current_session=True)
courses = TakenCourse.objects.filter(student__student__id=request.user.id)
fname = request.user.username + '.pdf'
fname = request.user.username + ".pdf"
fname = fname.replace("/", "-")
# flocation = '/tmp/' + fname
# print(MEDIA_ROOT + "\\" + fname)
flocation = settings.MEDIA_ROOT + "/registration_form/" + fname
doc = SimpleDocTemplate(flocation, rightMargin=15, leftMargin=15, topMargin=0, bottomMargin=0)
doc = SimpleDocTemplate(
flocation, rightMargin=15, leftMargin=15, topMargin=0, bottomMargin=0
)
styles = getSampleStyleSheet()
Story = [Spacer(1,0.5)]
Story.append(Spacer(1,0.4*inch))
Story = [Spacer(1, 0.5)]
Story.append(Spacer(1, 0.4 * inch))
style = styles["Normal"]
style = getSampleStyleSheet()
@ -378,7 +488,7 @@ def course_registration_form(request):
Story.append(school_title)
style = getSampleStyleSheet()
Story.append(Spacer(1,0.1*inch))
Story.append(Spacer(1, 0.1 * inch))
department = style["Normal"]
department.alignment = TA_CENTER
department.fontName = "Helvetica"
@ -387,22 +497,38 @@ def course_registration_form(request):
department_title = "<b>DEPARTMENT OF COMPUTER SCIENCE & ENGINEERING</b>"
department_title = Paragraph(department_title, department)
Story.append(department_title)
Story.append(Spacer(1,.3*inch))
Story.append(Spacer(1, 0.3 * inch))
title = "<b><u>STUDENT COURSE REGISTRATION FORM</u></b>"
title = Paragraph(title.upper(), normal)
Story.append(title)
student = Student.objects.get(student__pk=request.user.id)
style_right = ParagraphStyle(name='right', parent=styles['Normal'])
style_right = ParagraphStyle(name="right", parent=styles["Normal"])
tbl_data = [
[Paragraph("<b>Registration Number : " + request.user.username.upper() + "</b>", styles["Normal"])],
[Paragraph("<b>Name : " + request.user.get_full_name.upper() + "</b>", styles["Normal"])],
[Paragraph("<b>Session : " + current_session.session.upper() + "</b>", styles["Normal"]), Paragraph("<b>Level: " + student.level + "</b>", styles["Normal"])
]]
[
Paragraph(
"<b>Registration Number : " + request.user.username.upper() + "</b>",
styles["Normal"],
)
],
[
Paragraph(
"<b>Name : " + request.user.get_full_name.upper() + "</b>",
styles["Normal"],
)
],
[
Paragraph(
"<b>Session : " + current_session.session.upper() + "</b>",
styles["Normal"],
),
Paragraph("<b>Level: " + student.level + "</b>", styles["Normal"]),
],
]
tbl = Table(tbl_data)
Story.append(tbl)
Story.append(Spacer(1, 0.6*inch))
Story.append(Spacer(1, 0.6 * inch))
style = getSampleStyleSheet()
semester = style["Normal"]
@ -418,44 +544,66 @@ def course_registration_form(request):
# FIRST SEMESTER
count = 0
header = [('S/No', 'Course Code', 'Course Title', 'Unit', Paragraph('Name, Siganture of course lecturer & Date', style['Normal']))]
table_header = Table(header,1*[1.4*inch], 1*[0.5*inch])
header = [
(
"S/No",
"Course Code",
"Course Title",
"Unit",
Paragraph("Name, Siganture of course lecturer & Date", style["Normal"]),
)
]
table_header = Table(header, 1 * [1.4 * inch], 1 * [0.5 * inch])
table_header.setStyle(
TableStyle([
('ALIGN',(-2,-2), (-2,-2),'CENTER'),
('VALIGN',(-2,-2), (-2,-2),'MIDDLE'),
('ALIGN',(1,0), (1,0),'CENTER'),
('VALIGN',(1,0), (1,0),'MIDDLE'),
('ALIGN',(0,0), (0,0),'CENTER'),
('VALIGN',(0,0), (0,0),'MIDDLE'),
('ALIGN',(-4,0), (-4,0),'LEFT'),
('VALIGN',(-4,0), (-4,0),'MIDDLE'),
('ALIGN',(-3,0), (-3,0),'LEFT'),
('VALIGN',(-3,0), (-3,0),'MIDDLE'),
('TEXTCOLOR',(0,-1),(-1,-1),colors.black),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
TableStyle(
[
("ALIGN", (-2, -2), (-2, -2), "CENTER"),
("VALIGN", (-2, -2), (-2, -2), "MIDDLE"),
("ALIGN", (1, 0), (1, 0), "CENTER"),
("VALIGN", (1, 0), (1, 0), "MIDDLE"),
("ALIGN", (0, 0), (0, 0), "CENTER"),
("VALIGN", (0, 0), (0, 0), "MIDDLE"),
("ALIGN", (-4, 0), (-4, 0), "LEFT"),
("VALIGN", (-4, 0), (-4, 0), "MIDDLE"),
("ALIGN", (-3, 0), (-3, 0), "LEFT"),
("VALIGN", (-3, 0), (-3, 0), "MIDDLE"),
("TEXTCOLOR", (0, -1), (-1, -1), colors.black),
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
]
)
)
Story.append(table_header)
first_semester_unit = 0
for course in courses:
if course.course.semester == FIRST:
first_semester_unit += int(course.course.credit)
data = [(count+1, course.course.code.upper(), Paragraph(course.course.title, style['Normal']), course.course.credit, '')]
data = [
(
count + 1,
course.course.code.upper(),
Paragraph(course.course.title, style["Normal"]),
course.course.credit,
"",
)
]
color = colors.black
count += 1
table_body=Table(data,1*[1.4*inch], 1*[0.3*inch])
table_body = Table(data, 1 * [1.4 * inch], 1 * [0.3 * inch])
table_body.setStyle(
TableStyle([
('ALIGN',(-2,-2), (-2,-2),'CENTER'),
('ALIGN',(1,0), (1,0),'CENTER'),
('ALIGN',(0,0), (0,0),'CENTER'),
('ALIGN',(-4,0), (-4,0),'LEFT'),
('TEXTCOLOR',(0,-1),(-1,-1),colors.black),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
TableStyle(
[
("ALIGN", (-2, -2), (-2, -2), "CENTER"),
("ALIGN", (1, 0), (1, 0), "CENTER"),
("ALIGN", (0, 0), (0, 0), "CENTER"),
("ALIGN", (-4, 0), (-4, 0), "LEFT"),
("TEXTCOLOR", (0, -1), (-1, -1), colors.black),
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
]
)
)
Story.append(table_body)
style = getSampleStyleSheet()
@ -464,12 +612,14 @@ def course_registration_form(request):
semester.fontName = "Helvetica"
semester.fontSize = 8
semester.leading = 18
semester_title = "<b>Total Second First Credit : " + str(first_semester_unit) + "</b>"
semester_title = (
"<b>Total Second First Credit : " + str(first_semester_unit) + "</b>"
)
semester_title = Paragraph(semester_title, semester)
Story.append(semester_title)
# FIRST SEMESTER ENDS HERE
Story.append(Spacer(1, 0.6*inch))
Story.append(Spacer(1, 0.6 * inch))
style = getSampleStyleSheet()
semester = style["Normal"]
@ -482,44 +632,68 @@ def course_registration_form(request):
Story.append(semester_title)
# SECOND SEMESTER
count = 0
header = [('S/No', 'Course Code', 'Course Title', 'Unit', Paragraph('<b>Name, Signature of course lecturer & Date</b>', style['Normal']))]
table_header = Table(header,1*[1.4*inch], 1*[0.5*inch])
header = [
(
"S/No",
"Course Code",
"Course Title",
"Unit",
Paragraph(
"<b>Name, Signature of course lecturer & Date</b>", style["Normal"]
),
)
]
table_header = Table(header, 1 * [1.4 * inch], 1 * [0.5 * inch])
table_header.setStyle(
TableStyle([
('ALIGN',(-2,-2), (-2,-2),'CENTER'),
('VALIGN',(-2,-2), (-2,-2),'MIDDLE'),
('ALIGN',(1,0), (1,0),'CENTER'),
('VALIGN',(1,0), (1,0),'MIDDLE'),
('ALIGN',(0,0), (0,0),'CENTER'),
('VALIGN',(0,0), (0,0),'MIDDLE'),
('ALIGN',(-4,0), (-4,0),'LEFT'),
('VALIGN',(-4,0), (-4,0),'MIDDLE'),
('ALIGN',(-3,0), (-3,0),'LEFT'),
('VALIGN',(-3,0), (-3,0),'MIDDLE'),
('TEXTCOLOR',(0,-1),(-1,-1),colors.black),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
TableStyle(
[
("ALIGN", (-2, -2), (-2, -2), "CENTER"),
("VALIGN", (-2, -2), (-2, -2), "MIDDLE"),
("ALIGN", (1, 0), (1, 0), "CENTER"),
("VALIGN", (1, 0), (1, 0), "MIDDLE"),
("ALIGN", (0, 0), (0, 0), "CENTER"),
("VALIGN", (0, 0), (0, 0), "MIDDLE"),
("ALIGN", (-4, 0), (-4, 0), "LEFT"),
("VALIGN", (-4, 0), (-4, 0), "MIDDLE"),
("ALIGN", (-3, 0), (-3, 0), "LEFT"),
("VALIGN", (-3, 0), (-3, 0), "MIDDLE"),
("TEXTCOLOR", (0, -1), (-1, -1), colors.black),
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
]
)
)
Story.append(table_header)
second_semester_unit = 0
for course in courses:
if course.course.semester == SECOND:
second_semester_unit += int(course.course.credit)
data = [(count+1, course.course.code.upper(), Paragraph(course.course.title, style['Normal']), course.course.credit, '')]
data = [
(
count + 1,
course.course.code.upper(),
Paragraph(course.course.title, style["Normal"]),
course.course.credit,
"",
)
]
color = colors.black
count += 1
table_body=Table(data,1*[1.4*inch], 1*[0.3*inch])
table_body = Table(data, 1 * [1.4 * inch], 1 * [0.3 * inch])
table_body.setStyle(
TableStyle([
('ALIGN',(-2,-2), (-2,-2),'CENTER'),
('ALIGN',(1,0), (1,0),'CENTER'),
('ALIGN',(0,0), (0,0),'CENTER'),
('ALIGN',(-4,0), (-4,0),'LEFT'),
('TEXTCOLOR',(0,-1),(-1,-1),colors.black),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
TableStyle(
[
("ALIGN", (-2, -2), (-2, -2), "CENTER"),
("ALIGN", (1, 0), (1, 0), "CENTER"),
("ALIGN", (0, 0), (0, 0), "CENTER"),
("ALIGN", (-4, 0), (-4, 0), "LEFT"),
("TEXTCOLOR", (0, -1), (-1, -1), colors.black),
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
]
)
)
Story.append(table_body)
style = getSampleStyleSheet()
@ -528,7 +702,9 @@ def course_registration_form(request):
semester.fontName = "Helvetica"
semester.fontSize = 8
semester.leading = 18
semester_title = "<b>Total Second Semester Credit : " + str(second_semester_unit) + "</b>"
semester_title = (
"<b>Total Second Semester Credit : " + str(second_semester_unit) + "</b>"
)
semester_title = Paragraph(semester_title, semester)
Story.append(semester_title)
@ -540,22 +716,28 @@ def course_registration_form(request):
certification.fontSize = 8
certification.leading = 18
student = Student.objects.get(student__pk=request.user.id)
certification_text = "CERTIFICATION OF REGISTRATION: I certify that <b>" + str(request.user.get_full_name.upper()) + "</b>\
has been duly registered for the <b>" + student.level + " level </b> of study in the department\
certification_text = (
"CERTIFICATION OF REGISTRATION: I certify that <b>"
+ str(request.user.get_full_name.upper())
+ "</b>\
has been duly registered for the <b>"
+ student.level
+ " level </b> of study in the department\
of COMPUTER SICENCE & ENGINEERING and that the courses and credits registered are as approved by the senate of the University"
)
certification_text = Paragraph(certification_text, certification)
Story.append(certification_text)
# FIRST SEMESTER ENDS HERE
logo = settings.STATICFILES_DIRS[0] + "/img/logo.png"
im_logo = Image(logo, 1*inch, 1*inch)
im_logo = Image(logo, 1 * inch, 1 * inch)
im_logo.__setattr__("_offs_x", -218)
im_logo.__setattr__("_offs_y", 480)
Story.append(im_logo)
picture = settings.BASE_DIR + request.user.get_picture()
im = Image(picture, 1.0*inch, 1.0*inch)
picture = settings.BASE_DIR + request.user.get_picture()
im = Image(picture, 1.0 * inch, 1.0 * inch)
im.__setattr__("_offs_x", 218)
im.__setattr__("_offs_y", 550)
Story.append(im)
@ -563,7 +745,7 @@ def course_registration_form(request):
doc.build(Story)
fs = FileSystemStorage(settings.MEDIA_ROOT + "/registration_form")
with fs.open(fname) as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'inline; filename='+fname+''
response = HttpResponse(pdf, content_type="application/pdf")
response["Content-Disposition"] = "inline; filename=" + fname + ""
return response
return response

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class SearchConfig(AppConfig):
name = 'search'
name = "search"

View File

@ -2,5 +2,5 @@ from django.urls import path
from .views import SearchView
urlpatterns = [
path('', SearchView.as_view(), name='query'),
path("", SearchView.as_view(), name="query"),
]

View File

@ -27,14 +27,6 @@
# '''
# search.views.py
from itertools import chain
from django.views.generic import ListView
@ -48,36 +40,31 @@ from quiz.models import Quiz
class SearchView(ListView):
template_name = 'search/search_view.html'
template_name = "search/search_view.html"
paginate_by = 20
count = 0
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['count'] = self.count or 0
context['query'] = self.request.GET.get('q')
context["count"] = self.count or 0
context["query"] = self.request.GET.get("q")
return context
def get_queryset(self):
request = self.request
query = request.GET.get('q', None)
query = request.GET.get("q", None)
if query is not None:
news_events_results = NewsAndEvents.objects.search(query)
program_results = Program.objects.search(query)
course_results = Course.objects.search(query)
quiz_results = Quiz.objects.search(query)
news_events_results = NewsAndEvents.objects.search(query)
program_results = Program.objects.search(query)
course_results = Course.objects.search(query)
quiz_results = Quiz.objects.search(query)
# combine querysets
queryset_chain = chain(
news_events_results,
program_results,
course_results,
quiz_results
news_events_results, program_results, course_results, quiz_results
)
qs = sorted(queryset_chain,
key=lambda instance: instance.pk,
reverse=True)
self.count = len(qs) # since qs is actually a list
qs = sorted(queryset_chain, key=lambda instance: instance.pk, reverse=True)
self.count = len(qs) # since qs is actually a list
return qs
return NewsAndEvents.objects.none() # just an empty queryset as default
return NewsAndEvents.objects.none() # just an empty queryset as default