diff --git a/Website/api/models.py b/Website/api/models.py index 9dc22f2..d62f9dc 100644 --- a/Website/api/models.py +++ b/Website/api/models.py @@ -18,31 +18,32 @@ class Student(models.Model): super(Student, self).save(*args, **kwargs) def __str__(self): - return f"{self.user.username}'s Profile" + return f"{self.user.first_name} {self.user.last_name} ({self.user.username})" class Assignment(models.Model): owner = models.ForeignKey(User, null=True, blank=True, related_name='aowner', on_delete=models.CASCADE) - name=models.CharField(max_length=100, primary_key=True) due_date=models.DateTimeField() # files = models.ManyToManyField(DefFiles) files=models.CharField(max_length=100, default="", blank=True) - path=models.CharField(max_length=100) - classes=models.CharField(max_length=100) - teacher=models.CharField(max_length=100) + path=models.CharField(max_length=100, default="", blank=True) + classes=models.CharField(max_length=100, default="", blank=True) + teacher=models.CharField(max_length=100, default="", blank=True) def __str__(self): - return '%s' % (self.name) + return f'{self.name}' class Class(models.Model): owner = models.ForeignKey(User, null=True, blank=True, related_name='cowner', on_delete=models.CASCADE) - teacher = models.CharField(max_length=100) + teacher = models.CharField(max_length=100, blank=True) + subject = models.CharField(max_length=50, blank=True) + period = models.PositiveIntegerField(null=True, blank=True, default=0) name = models.CharField(primary_key=True, max_length=100) id = models.CharField(max_length=8, blank=True, null=True) - description = models.CharField(default="Class Description", max_length=500) + description = models.CharField(default="Class Description", max_length=500, blank=True) repo=models.URLField(default="", blank=True) - path=models.CharField(max_length=100, default="") + path=models.CharField(max_length=100, default="", blank=True) assignments=models.ManyToManyField(Assignment, blank=True) default_file=models.CharField(max_length=100, default="", blank=True) confirmed=models.ManyToManyField(Student, blank=True, related_name='confirmed') @@ -60,7 +61,7 @@ class Class(models.Model): return super(Class, self).save(*args, **kwargs) def __str__(self): - return self.name + return f"{self.user.first_name} {self.user.last_name} ({self.user.username})" class Teacher(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) diff --git a/Website/skoolos/forms.py b/Website/skoolos/forms.py index 6374f97..e249d96 100644 --- a/Website/skoolos/forms.py +++ b/Website/skoolos/forms.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.auth.models import User -from api.models import Student, Teacher +from api.models import Student, Teacher, Class, Assignment import re class UserUpdateForm(forms.ModelForm): @@ -26,3 +26,54 @@ class TeacherUpdateForm(forms.ModelForm): class Meta: model = Teacher fields = ['git'] + +class ClassCreationForm (forms.ModelForm): + subject = forms.CharField(max_length=50) + period = forms.IntegerField(min_value=0, max_value=9) + description = forms.CharField(widget=forms.Textarea) + unconfirmed = forms.ModelMultipleChoiceField(queryset=Student.objects.all(), label="Invite students") + + + def clean_period(self): + pd = self.cleaned_data['period'] + if pd < 1 or pd > 9: + raise forms.ValidationError("Invalid period") + return pd; + + def __init__(self, *args, **kwargs): + super(ClassCreationForm, self).__init__(*args, **kwargs) + self.fields['period'].widget.attrs['min'] = 0 + # Only in case we build the form from an instance + # (otherwise, 'unconfirmed' list should be empty) + if kwargs.get('instance'): + # We get the 'initial' keyword argument or initialize it + # as a dict if it didn't exist. + initial = kwargs.setdefault('initial', {}) + # The widget for a ModelMultipleChoiceField expects + # a list of primary key for the selected data. + initial['unconfirmed'] = [t.pk for t in kwargs['instance'].unconfirmed.all()] + + # Overriding save allows us to process the value of 'unconfirmed' field + def save(self, commit=True): + # Get the unsave Pizza instance + instance = forms.ModelForm.save(self, False) + + # Prepare a 'save_m2m' method for the form, + old_save_m2m = self.save_m2m + def save_m2m(): + old_save_m2m() + # This is where we actually link the pizza with toppings + instance.topping_set.clear() + instance.topping_set.add(*self.cleaned_data['unconfirmed']) + self.save_m2m = save_m2m + + # Do we need to save all changes now? + if commit: + instance.save() + self.save_m2m() + + return instance + + class Meta: + model = Class + fields = ['subject', 'period', 'description', 'unconfirmed'] diff --git a/Website/skoolos/templates/skoolos/base.html b/Website/skoolos/templates/skoolos/base.html index 2ec152d..fa2f42c 100644 --- a/Website/skoolos/templates/skoolos/base.html +++ b/Website/skoolos/templates/skoolos/base.html @@ -34,6 +34,12 @@ + {% empty %} + {% if isTeacher %} +

Looks like you haven't made any assignments yet, hit the button in the top right to get started

+ {% else %} +

Looks like there aren't any assignments at the moment, you got lucky this time!

+ {% endif %} {% endfor %} @@ -20,6 +26,8 @@ diff --git a/Website/skoolos/templates/skoolos/createClass.html b/Website/skoolos/templates/skoolos/createClass.html new file mode 100644 index 0000000..4acb8f9 --- /dev/null +++ b/Website/skoolos/templates/skoolos/createClass.html @@ -0,0 +1,26 @@ +{% extends "skoolos/base.html" %} +{% load crispy_forms_tags %} +{% block content %} + Classes + +
+ {% csrf_token %} +
+ Create a new class + {{ classForm|crispy }} + + Use ctrl to select multiple students +
+
+ +
+
+ + +{% endblock content %} diff --git a/Website/skoolos/templates/skoolos/home.html b/Website/skoolos/templates/skoolos/home.html index 6822cb6..45dfedc 100644 --- a/Website/skoolos/templates/skoolos/home.html +++ b/Website/skoolos/templates/skoolos/home.html @@ -10,6 +10,12 @@ + {% empty %} + {% if isTeacher %} +

Looks like you haven't created any classes yet, hit the button in the top right to get started.

+ {% else %} +

Looks like you're not enrolled in any classes at the moment! Ask your teacher if you think this is wrong.

+ {% endif %} {% endfor %} {% endblock content %} diff --git a/Website/skoolos/templates/skoolos/profile_student.html b/Website/skoolos/templates/skoolos/profile_student.html index 3da2f41..947dab7 100644 --- a/Website/skoolos/templates/skoolos/profile_student.html +++ b/Website/skoolos/templates/skoolos/profile_student.html @@ -5,6 +5,7 @@
+

Student

{{ user.first_name }} {{ user.last_name }}

{{ user.email }} @@ -16,6 +17,8 @@

diff --git a/Website/skoolos/templates/skoolos/profile_teacher.html b/Website/skoolos/templates/skoolos/profile_teacher.html index 3da2f41..7c62793 100644 --- a/Website/skoolos/templates/skoolos/profile_teacher.html +++ b/Website/skoolos/templates/skoolos/profile_teacher.html @@ -5,6 +5,7 @@
+

Teacher

{{ user.first_name }} {{ user.last_name }}

{{ user.email }} @@ -16,6 +17,8 @@

    {% for class in classes %}
  • {{ class.name }}
  • + {% empty %} +
  • Not teaching any classes
  • {% endfor %}
diff --git a/Website/skoolos/urls.py b/Website/skoolos/urls.py index a028497..8fa2724 100644 --- a/Website/skoolos/urls.py +++ b/Website/skoolos/urls.py @@ -7,4 +7,6 @@ urlpatterns = [ path('', views.home, name='home'), path('profile/', views.profile, name='profile'), path("class/", views.classDetail, name="class"), + path("create-class/", views.createClass, name="create-class"), + path("create-assignment/", views.createAssignment, name="create-assignment"), ] diff --git a/Website/skoolos/views.py b/Website/skoolos/views.py index 3f67c84..c364365 100644 --- a/Website/skoolos/views.py +++ b/Website/skoolos/views.py @@ -5,7 +5,12 @@ from django.contrib import messages from django.contrib.auth.models import User -from .forms import UserUpdateForm, StudentUpdateForm, TeacherUpdateForm +from .forms import ( + UserUpdateForm, + StudentUpdateForm, + TeacherUpdateForm, + ClassCreationForm, +) from api.models import Student, Teacher, Class, Assignment @@ -14,14 +19,14 @@ from api.models import Student, Teacher, Class, Assignment @login_required() def home (request): try: - student = Student.objects.get(user=request.user) - return render(request, "skoolos/home.html", {'classes': student.confirmed.all()}) + student = request.user.student + return render(request, "skoolos/home.html", {'classes': student.confirmed.all(), 'isTeacher': False}) except Student.DoesNotExist: pass try: - teacher = Teacher.objects.get(user=request.user) - return render(request, "skoolos/home.html", {'classes': teacher.classes.all()}) + teacher = request.user.teacher + return render(request, "skoolos/home.html", {'classes': teacher.classes.all(), 'isTeacher': True}) except Teacher.DoesNotExist: pass @@ -36,38 +41,37 @@ def classDetail (request, id): classObj = Class.objects.get(id=id) try: - student = Student.objects.get(user=request.user) + student = request.user.student except Student.DoesNotExist: pass else: if classObj.confirmed.filter(user=student.user).count() != 1: return redirect('/') else: - return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all()}) + return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all(), 'isTeacher': False}) try: - teacher = Teacher.objects.get(user=request.user) - return render(request, "skoolos/home.html", {'classes': teacher.classes.all()}) + teacher = request.user.teacher except Teacher.DoesNotExist: pass else: - if classObj.confirmed.filter(user=student.user).count() != 1: + if teacher.classes.filter(id=classObj.id).count() != 1: return redirect('/') else: - return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all()}) + return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all(), 'isTeacher': True}) return redirect('/') @login_required() def profile (request): try: - student = Student.objects.get(user=request.user) + student = request.user.student return student_profile(request) except Student.DoesNotExist: pass try: - teacher = Teacher.objects.get(user=request.user) + teacher = request.user.teacher return teacher_profile(request) except Teacher.DoesNotExist: pass @@ -91,7 +95,8 @@ def student_profile (request): context = { 'userForm': userForm, 'profileForm': profileForm, - 'classes': request.user.student.confirmed.all() + 'classes': request.user.student.confirmed.all(), + 'isTeacher': False, } return render(request, 'skoolos/profile_student.html', context) @@ -113,7 +118,47 @@ def teacher_profile (request): context = { 'userForm': userForm, 'profileForm': profileForm, - 'classes': request.user.teacher.classes.all() + 'classes': request.user.teacher.classes.all(), + 'isTeacher': True, } return render(request, 'skoolos/profile_teacher.html', context) + +@login_required() +def createClass (request): + try: + teacher = request.user.teacher + except Teacher.DoesNotExist: + pass + else: + return createClassHelper(request) + + return redirect('/') + +def createClassHelper(request): + teacher = request.user.teacher + + if request.method == "POST": + userForm = UserUpdateForm(request.POST, instance=request.user) + profileForm = TeacherUpdateForm(request.POST, + instance=request.user.teacher) + if userForm.is_valid() and profileForm.is_valid(): + userForm.save() + profileForm.save() + messages.success(request, "Your account has been updated!") + return redirect('profile') + else: + classForm = ClassCreationForm() + + context = { + 'teacher': teacher, + 'classes': teacher.classes.all(), + 'classForm': classForm + + } + + return render(request, "skoolos/createClass.html", context) + +@login_required() +def createAssignment (request): + pass