From 8c7ada75f38c88e5c456e6ebd7b57f0f9bdbfdbd Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 00:19:58 -0300 Subject: [PATCH 01/56] change dev branch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c3a8581..a993f79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ deploy: script: bash scripts/homolog-deploy.sh skip_cleanup: true on: - branch: develop + branch: dev # deploy to production enviroment - provider: script From 59da60a5cd57dbbdd0943bd64e0e6f148efdb5dd Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 16:45:22 -0300 Subject: [PATCH 02/56] Refactoring account app --- README.md | 1 + pgtbl/accounts/forms.py | 69 ---- pgtbl/accounts/forms/__init__.py | 3 + pgtbl/accounts/forms/password_reset_form.py | 28 ++ pgtbl/accounts/forms/user_creation_form.py | 30 ++ pgtbl/accounts/forms/user_form.py | 22 ++ pgtbl/accounts/models/__init__.py | 2 + pgtbl/accounts/models/password_reset.py | 54 +++ pgtbl/accounts/{models.py => models/user.py} | 53 --- pgtbl/accounts/views.py | 348 ------------------ pgtbl/accounts/views/__init__.py | 7 + pgtbl/accounts/views/delete_profile_view.py | 38 ++ pgtbl/accounts/views/edit_password_view.py | 46 +++ pgtbl/accounts/views/edit_profile_view.py | 46 +++ pgtbl/accounts/views/profile_view.py | 91 +++++ pgtbl/accounts/views/register_view.py | 55 +++ .../views/reset_password_confirm_view.py | 60 +++ pgtbl/accounts/views/reset_password_view.py | 56 +++ 18 files changed, 539 insertions(+), 470 deletions(-) delete mode 100644 pgtbl/accounts/forms.py create mode 100644 pgtbl/accounts/forms/__init__.py create mode 100644 pgtbl/accounts/forms/password_reset_form.py create mode 100644 pgtbl/accounts/forms/user_creation_form.py create mode 100644 pgtbl/accounts/forms/user_form.py create mode 100644 pgtbl/accounts/models/__init__.py create mode 100644 pgtbl/accounts/models/password_reset.py rename pgtbl/accounts/{models.py => models/user.py} (79%) delete mode 100644 pgtbl/accounts/views.py create mode 100644 pgtbl/accounts/views/__init__.py create mode 100644 pgtbl/accounts/views/delete_profile_view.py create mode 100644 pgtbl/accounts/views/edit_password_view.py create mode 100644 pgtbl/accounts/views/edit_profile_view.py create mode 100644 pgtbl/accounts/views/profile_view.py create mode 100644 pgtbl/accounts/views/register_view.py create mode 100644 pgtbl/accounts/views/reset_password_confirm_view.py create mode 100644 pgtbl/accounts/views/reset_password_view.py diff --git a/README.md b/README.md index 165fac2..11ca9a6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/bcbcac621e1847e7af8e61bc202a03c6)](https://www.codacy.com/app/VictorArnaud/TBL?utm_source=github.com&utm_medium=referral&utm_content=TeamBasedLearning/TBL&utm_campaign=Badge_Grade) [![Build Status](https://travis-ci.org/VictorArnaud/TBL.svg?branch=master)](https://travis-ci.org/VictorArnaud/TBL) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/bcbcac621e1847e7af8e61bc202a03c6)](https://www.codacy.com/app/VictorArnaud/TBL?utm_source=github.com&utm_medium=referral&utm_content=TeamBasedLearning/TBL&utm_campaign=Badge_Coverage) # DocumentaĆ§Ć£o do PGTBL: Plataforma gerenciadora de Team Based Learning. diff --git a/pgtbl/accounts/forms.py b/pgtbl/accounts/forms.py deleted file mode 100644 index 67e91ab..0000000 --- a/pgtbl/accounts/forms.py +++ /dev/null @@ -1,69 +0,0 @@ -from django.contrib.auth.forms import UserCreationForm as CreationForm -from django.utils.translation import ugettext_lazy as _ -from django.contrib.auth import get_user_model -from django import forms - -# Get the user from settings -User = get_user_model() - - -class UserCreationForm(CreationForm): - """ - Create a form to add a new user that work with django admin. - """ - - CHOICES = ( - (True, _('Teacher')), - (False, _('Student')) - ) - - is_teacher = forms.ChoiceField(choices=CHOICES) - - class Meta: - model = User - # password and password confirmation has in the UserCrationForm - fields = [ - 'name', - 'username', - 'email', - 'is_teacher', - ] - - -class UserForm(forms.ModelForm): - """ - Create a form that work with django admin. - """ - - class Meta: - model = User - fields = [ - 'username', - 'email', - 'name', - 'is_teacher', - 'is_active', - 'is_staff' - ] - - -class PasswordResetForm(forms.Form): - """ - Form to reset the user password. - """ - - email = forms.EmailField(label='E-mail', required=True) - - def clean_email(self): - """ - Verify if the email exists in the system and return it. - """ - - email = self.cleaned_data['email'] - - if User.objects.filter(email=email).exists(): - return email - - raise forms.ValidationError( - _('There is no user found with this email') - ) diff --git a/pgtbl/accounts/forms/__init__.py b/pgtbl/accounts/forms/__init__.py new file mode 100644 index 0000000..616da24 --- /dev/null +++ b/pgtbl/accounts/forms/__init__.py @@ -0,0 +1,3 @@ +from .user_form import UserForm +from .user_creation_form import UserCreationForm +from .password_reset_form import PasswordResetForm diff --git a/pgtbl/accounts/forms/password_reset_form.py b/pgtbl/accounts/forms/password_reset_form.py new file mode 100644 index 0000000..4e31d08 --- /dev/null +++ b/pgtbl/accounts/forms/password_reset_form.py @@ -0,0 +1,28 @@ +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth import get_user_model +from django import forms + +# Get the user from settings +User = get_user_model() + + +class PasswordResetForm(forms.Form): + """ + Form to reset the user password. + """ + + email = forms.EmailField(label='E-mail', required=True) + + def clean_email(self): + """ + Verify if the email exists in the system and return it. + """ + + email = self.cleaned_data['email'] + + if User.objects.filter(email=email).exists(): + return email + + raise forms.ValidationError( + _('There is no user found with this email') + ) diff --git a/pgtbl/accounts/forms/user_creation_form.py b/pgtbl/accounts/forms/user_creation_form.py new file mode 100644 index 0000000..a85aedf --- /dev/null +++ b/pgtbl/accounts/forms/user_creation_form.py @@ -0,0 +1,30 @@ +from django.contrib.auth.forms import UserCreationForm as CreationForm +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth import get_user_model +from django import forms + +# Get the user from settings +User = get_user_model() + + +class UserCreationForm(CreationForm): + """ + Create a form to add a new user that work with django admin. + """ + + CHOICES = ( + (True, _('Teacher')), + (False, _('Student')) + ) + + is_teacher = forms.ChoiceField(choices=CHOICES) + + class Meta: + model = User + # password and password confirmation has in the UserCrationForm + fields = [ + 'name', + 'username', + 'email', + 'is_teacher' + ] diff --git a/pgtbl/accounts/forms/user_form.py b/pgtbl/accounts/forms/user_form.py new file mode 100644 index 0000000..d66652c --- /dev/null +++ b/pgtbl/accounts/forms/user_form.py @@ -0,0 +1,22 @@ +from django.contrib.auth import get_user_model +from django import forms + +# Get the user from settings +User = get_user_model() + + +class UserForm(forms.ModelForm): + """ + Create a form that work with django admin. + """ + + class Meta: + model = User + fields = [ + 'username', + 'email', + 'name', + 'is_teacher', + 'is_active', + 'is_staff' + ] diff --git a/pgtbl/accounts/models/__init__.py b/pgtbl/accounts/models/__init__.py new file mode 100644 index 0000000..ed5822d --- /dev/null +++ b/pgtbl/accounts/models/__init__.py @@ -0,0 +1,2 @@ +from .user import User +from .password_reset import PasswordReset diff --git a/pgtbl/accounts/models/password_reset.py b/pgtbl/accounts/models/password_reset.py new file mode 100644 index 0000000..76f4707 --- /dev/null +++ b/pgtbl/accounts/models/password_reset.py @@ -0,0 +1,54 @@ +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.db import models + + +class PasswordReset(models.Model): + """ + Create a password reset key to reset and get a new password. + """ + + # User who requested the new password. + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name=_('User'), + related_name="password_resets" + ) + + # Unique key to reset password. + key = models.CharField( + _('Key'), + max_length=100, + unique=True + ) + + # Date to create a link to reset password. + created_at = models.DateTimeField( + _('Created at'), + auto_now_add=True + ) + + # Indicates if the link was already used to not be used again + confirmed = models.BooleanField( + _('Confirmed?'), + default=False, + blank=True + ) + + def __str__(self): + """ + Returns the object as a string, the attribute that will represent + the object. + """ + + return '{0} - {1}'.format(self.user, self.created_at) + + class Meta: + """ + Some information about user class. + """ + + verbose_name = _('New password') + verbose_name_plural = _('New passwords') + ordering = ['-created_at'] diff --git a/pgtbl/accounts/models.py b/pgtbl/accounts/models/user.py similarity index 79% rename from pgtbl/accounts/models.py rename to pgtbl/accounts/models/user.py index 1ea0f3f..f5e711d 100644 --- a/pgtbl/accounts/models.py +++ b/pgtbl/accounts/models/user.py @@ -1,10 +1,8 @@ -# Django imports from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import ( AbstractBaseUser, PermissionsMixin, UserManager ) from django.core import validators -from django.conf import settings from django.db import models # External imports @@ -170,57 +168,6 @@ class Meta: ordering = ('email',) -class PasswordReset(models.Model): - """ - Create a password reset key to reset and get a new password. - """ - - # User who requested the new password. - user = models.ForeignKey( - settings.AUTH_USER_MODEL, - on_delete=models.CASCADE, - verbose_name=_('User'), - related_name="password_resets" - ) - - # Unique key to reset password. - key = models.CharField( - _('Key'), - max_length=100, - unique=True - ) - - # Date to create a link to reset password. - created_at = models.DateTimeField( - _('Created at'), - auto_now_add=True - ) - - # Indicates if the link was already used to not be used again - confirmed = models.BooleanField( - _('Confirmed?'), - default=False, - blank=True - ) - - def __str__(self): - """ - Returns the object as a string, the attribute that will represent - the object. - """ - - return '{0} - {1}'.format(self.user, self.created_at) - - class Meta: - """ - Some information about user class. - """ - - verbose_name = _('New password') - verbose_name_plural = _('New passwords') - ordering = ['-created_at'] - - def set_roles_to_the_new_user(instance, created, **kwargs): """ Insert the created user into a specific group. diff --git a/pgtbl/accounts/views.py b/pgtbl/accounts/views.py deleted file mode 100644 index fa7c319..0000000 --- a/pgtbl/accounts/views.py +++ /dev/null @@ -1,348 +0,0 @@ -# Django imports -from django.contrib.auth.forms import PasswordChangeForm, SetPasswordForm -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.http.response import HttpResponseRedirect -from django.contrib.auth import login, authenticate -from django.core.urlresolvers import reverse_lazy -from django.contrib.auth import get_user_model -from django.shortcuts import get_object_or_404 -from django.contrib import messages -from django.views.generic import ( - CreateView, ListView, UpdateView, FormView, DeleteView -) - -# Application imoports -from disciplines.models import Discipline -from core.email import send_email_template -from core.utils import generate_hash_key -from .forms import UserCreationForm, PasswordResetForm -from .models import PasswordReset - -# Get the custom user from settings -User = get_user_model() - - -class ProfileView(LoginRequiredMixin, ListView): - """ - Class to read a profile user and his disciplines. - """ - - paginate_by = 6 - template_name = 'accounts/profile.html' - context_object_name = 'disciplines' - - def get_queryset(self): - """ - If user is a student get the disciplines that he is taking - If user is a teacher get the created disciplines and disciplines - that he is monitor - """ - - queryset = self.filter_student_disciplines() - - if self.request.user.is_teacher: - queryset = self.filter_teacher_disciplines() - - return queryset - - def filter_teacher_disciplines(self): - """ - Get disciplines that teacher created or is a monitor. - """ - - created_disciplines = Discipline.objects.filter( - teacher=self.request.user - ) - - monitor_disciplines = Discipline.objects.filter( - monitors=self.request.user - ) - - # Join the created disciplines list and monitor disciplines list - queryset = [] - for discipline in created_disciplines: - queryset.append(discipline) - - for discipline in monitor_disciplines: - queryset.append(discipline) - - # Get the filter by key argument from url - filtered = self.request.GET.get('filter') - - if filtered == 'created': - queryset = created_disciplines - elif filtered == 'monitor': - queryset = monitor_disciplines - - return queryset - - def filter_student_disciplines(self): - """ - Get the students disciplines that he is taking - """ - - student_disciplines = Discipline.objects.filter( - students=self.request.user - ) - - monitor_disciplines = Discipline.objects.filter( - monitors=self.request.user - ) - - queryset = [] - for discipline in student_disciplines: - queryset.append(discipline) - - for discipline in monitor_disciplines: - queryset.append(discipline) - - # Get the filter by key argument from url - filtered = self.request.GET.get('filter') - - if filtered == 'student': - queryset = student_disciplines - elif filtered == 'monitor': - queryset = monitor_disciplines - - return queryset - - -class RegisterView(CreateView): - """ - Class to create a new user. - """ - - model = User - template_name = 'accounts/register.html' - form_class = UserCreationForm - - # Redirect to profile - success_url = reverse_lazy('accounts:profile') - - def form_valid(self, form): - """ - Receive the form already validated. - Logs the user into the system. - """ - - # Get the user saved by form. - user = form.save() - - user = authenticate( - username=user.username, - password=form.cleaned_data['password1'] - ) - login(self.request, user) - - if user.is_teacher: - messages.success( - self.request, - _("Teacher created successfully.") - ) - else: - messages.success( - self.request, - _("Student created successfully.") - ) - - return HttpResponseRedirect(self.success_url) - - -class EditProfileView(LoginRequiredMixin, UpdateView): - """ - Edit personal information from user. - """ - - model = User - template_name = 'accounts/edit_information.html' - - # Generate the forms with this fields - fields = ['photo', 'name', 'username', 'email', 'institution', 'course'] - - # Redirect to profile - success_url = reverse_lazy('accounts:profile') - - def get_object(self): - """ - Search a ID or slug from url and return a object from model. - In this case return the current user logged from model. - """ - - return self.request.user - - def form_valid(self, form): - """ - Get the form validated, send successfully message and return the - success_url. - """ - - messages.success( - self.request, - _("User updated successfully.") - ) - - # Redirect to success_url - return super(EditProfileView, self).form_valid(form) - - -class DeleteProfileView(LoginRequiredMixin, DeleteView): - """ - Delete the user account - """ - - model = User - - # Redirect to home page - success_url = reverse_lazy('core:home') - - def get_object(self): - """ - Search a ID or slug from url and return a object from model. - In this case return the current user logged from model. - """ - - return self.request.user - - def get_success_url(self): - """ - Redirect to success_url and show a message. - """ - - messages.success(self.request, _("Accounts deleted successfully.")) - - # Redirect to success_url - return super(DeleteProfileView, self).get_success_url() - - -class EditPasswordView(LoginRequiredMixin, FormView): - """ - Edit user password. - """ - - template_name = 'accounts/edit_password.html' - - # Redirect to profile - success_url = reverse_lazy('accounts:profile') - - # Generate the PasswordChangeForm from django - form_class = PasswordChangeForm - - def get_form_kwargs(self): - """ - Generates the arguments that will be passed to the form. - """ - - # Get the kwargs from the original class FormView - kwargs = super(EditPasswordView, self).get_form_kwargs() - - # Insert the parameter logged user into the form template - kwargs['user'] = self.request.user - return kwargs - - def form_valid(self, form): - """ - Receive the form already validated. - """ - - # In this case when you insert new kwargs, you need to save - # the instance again - form.save() - - messages.success(self.request, _("Password updated successfully.")) - - # Redirect to success_url - return super(EditPasswordView, self).form_valid(form) - - -class ResetPasswordView(FormView): - """ - Reset the user password and send email. - """ - - template_name = 'accounts/reset_password.html' - - # Use the PasswordResetForm - form_class = PasswordResetForm - - # Redirect to home page - success_url = reverse_lazy('core:home') - - def form_valid(self, form): - """ - Validated form and send email. - """ - - user = User.objects.get(email=form.cleaned_data['email']) - - # Generate unique key to reset password - key = generate_hash_key(user.username) - reset_password = PasswordReset(user=user, key=key) - reset_password.save() - - # Send email - send_email_template( - subject=_('Requesting new password'), - template='accounts/reset_password_email.html', - context={'reset_password': reset_password}, - recipient_list=[user.email], - ) - - messages.success( - self.request, - _("An email was sent with more details on how to create a new password") - ) - - # Redirect to success_url - return super(ResetPasswordView, self).form_valid(form) - - -class ResetPasswordConfirmView(FormView): - """ - Insert new password from email link. - """ - - template_name = 'accounts/reset_password_confirm.html' - - # Use SetPasswordForm from django - form_class = SetPasswordForm - - # Redirect to login page. - success_url = reverse_lazy('accounts:login') - - def get_form_kwargs(self): - """ - Insert arguments inside form. - """ - - # Get all arguments kwargs from SetPasswordForm - kwargs = super(ResetPasswordConfirmView, self).get_form_kwargs() - - # Get the user with kwargs key to reset his password - reset = get_object_or_404( - PasswordReset, - key=self.kwargs.get('key') - ) - - # Change user and data from form - kwargs['user'] = reset.user - kwargs['data'] = self.request.POST or None - - return kwargs - - def form_valid(self, form): - """ - Validated form and reset password. - """ - - # In this case when you insert new kwargs, you need to save - # the instance again - form.save() - - messages.success( - self.request, - _("Your password was successfully updated.") - ) - - # Redirect to success_url - return super(ResetPasswordConfirmView, self).form_valid(form) diff --git a/pgtbl/accounts/views/__init__.py b/pgtbl/accounts/views/__init__.py new file mode 100644 index 0000000..de8b1dd --- /dev/null +++ b/pgtbl/accounts/views/__init__.py @@ -0,0 +1,7 @@ +from .profile_view import ProfileView +from .register_view import RegisterView +from .edit_profile_view import EditProfileView +from .delete_profile_view import DeleteProfileView +from .edit_password_view import EditPasswordView +from .reset_password_confirm_view import ResetPasswordConfirmView +from .reset_password_view import ResetPasswordView diff --git a/pgtbl/accounts/views/delete_profile_view.py b/pgtbl/accounts/views/delete_profile_view.py new file mode 100644 index 0000000..c511ba8 --- /dev/null +++ b/pgtbl/accounts/views/delete_profile_view.py @@ -0,0 +1,38 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages +from django.views.generic import DeleteView + +# Get the custom user from settings +User = get_user_model() + + +class DeleteProfileView(LoginRequiredMixin, DeleteView): + """ + Delete the user account + """ + + model = User + + # Redirect to home page + success_url = reverse_lazy('core:home') + + def get_object(self): + """ + Search a ID or slug from url and return a object from model. + In this case return the current user logged from model. + """ + + return self.request.user + + def get_success_url(self): + """ + Redirect to success_url and show a message. + """ + + messages.success(self.request, _("Accounts deleted successfully.")) + + # Redirect to success_url + return super(DeleteProfileView, self).get_success_url() diff --git a/pgtbl/accounts/views/edit_password_view.py b/pgtbl/accounts/views/edit_password_view.py new file mode 100644 index 0000000..03d894f --- /dev/null +++ b/pgtbl/accounts/views/edit_password_view.py @@ -0,0 +1,46 @@ +from django.contrib.auth.forms import PasswordChangeForm +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import FormView + + +class EditPasswordView(LoginRequiredMixin, FormView): + """ + Edit user password. + """ + + template_name = 'accounts/edit_password.html' + + # Redirect to profile + success_url = reverse_lazy('accounts:profile') + + # Generate the PasswordChangeForm from django + form_class = PasswordChangeForm + + def get_form_kwargs(self): + """ + Generates the arguments that will be passed to the form. + """ + + # Get the kwargs from the original class FormView + kwargs = super(EditPasswordView, self).get_form_kwargs() + + # Insert the parameter logged user into the form template + kwargs['user'] = self.request.user + return kwargs + + def form_valid(self, form): + """ + Receive the form already validated. + """ + + # In this case when you insert new kwargs, you need to save + # the instance again + form.save() + + messages.success(self.request, _("Password updated successfully.")) + + # Redirect to success_url + return super(EditPasswordView, self).form_valid(form) diff --git a/pgtbl/accounts/views/edit_profile_view.py b/pgtbl/accounts/views/edit_profile_view.py new file mode 100644 index 0000000..8f9c9d8 --- /dev/null +++ b/pgtbl/accounts/views/edit_profile_view.py @@ -0,0 +1,46 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages +from django.views.generic import UpdateView + +# Get the custom user from settings +User = get_user_model() + + +class EditProfileView(LoginRequiredMixin, UpdateView): + """ + Edit personal information from user. + """ + + model = User + template_name = 'accounts/edit_information.html' + + # Generate the forms with this fields + fields = ['photo', 'name', 'username', 'email', 'institution', 'course'] + + # Redirect to profile + success_url = reverse_lazy('accounts:profile') + + def get_object(self): + """ + Search a ID or slug from url and return a object from model. + In this case return the current user logged from model. + """ + + return self.request.user + + def form_valid(self, form): + """ + Get the form validated, send successfully message and return the + success_url. + """ + + messages.success( + self.request, + _("User updated successfully.") + ) + + # Redirect to success_url + return super(EditProfileView, self).form_valid(form) diff --git a/pgtbl/accounts/views/profile_view.py b/pgtbl/accounts/views/profile_view.py new file mode 100644 index 0000000..2d62cc8 --- /dev/null +++ b/pgtbl/accounts/views/profile_view.py @@ -0,0 +1,91 @@ +# Django imports +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +# Application imoports +from disciplines.models import Discipline + + +class ProfileView(LoginRequiredMixin, ListView): + """ + Class to read a profile user and his disciplines. + """ + + paginate_by = 6 + template_name = 'accounts/profile.html' + context_object_name = 'disciplines' + + def get_queryset(self): + """ + If user is a student get the disciplines that he is taking + If user is a teacher get the created disciplines and disciplines + that he is monitor + """ + + queryset = self.filter_student_disciplines() + + if self.request.user.is_teacher: + queryset = self.filter_teacher_disciplines() + + return queryset + + def filter_teacher_disciplines(self): + """ + Get disciplines that teacher created or is a monitor. + """ + + created_disciplines = Discipline.objects.filter( + teacher=self.request.user + ) + + monitor_disciplines = Discipline.objects.filter( + monitors=self.request.user + ) + + # Join the created disciplines list and monitor disciplines list + queryset = [] + for discipline in created_disciplines: + queryset.append(discipline) + + for discipline in monitor_disciplines: + queryset.append(discipline) + + # Get the filter by key argument from url + filtered = self.request.GET.get('filter') + + if filtered == 'created': + queryset = created_disciplines + elif filtered == 'monitor': + queryset = monitor_disciplines + + return queryset + + def filter_student_disciplines(self): + """ + Get the students disciplines that he is taking + """ + + student_disciplines = Discipline.objects.filter( + students=self.request.user + ) + + monitor_disciplines = Discipline.objects.filter( + monitors=self.request.user + ) + + queryset = [] + for discipline in student_disciplines: + queryset.append(discipline) + + for discipline in monitor_disciplines: + queryset.append(discipline) + + # Get the filter by key argument from url + filtered = self.request.GET.get('filter') + + if filtered == 'student': + queryset = student_disciplines + elif filtered == 'monitor': + queryset = monitor_disciplines + + return queryset diff --git a/pgtbl/accounts/views/register_view.py b/pgtbl/accounts/views/register_view.py new file mode 100644 index 0000000..26f0ad5 --- /dev/null +++ b/pgtbl/accounts/views/register_view.py @@ -0,0 +1,55 @@ +# Django imports +from django.utils.translation import ugettext_lazy as _ +from django.http.response import HttpResponseRedirect +from django.contrib.auth import login, authenticate +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages +from django.views.generic import CreateView + +# Application imoports +from accounts.forms import UserCreationForm + +# Get the custom user from settings +User = get_user_model() + + +class RegisterView(CreateView): + """ + Class to create a new user. + """ + + model = User + template_name = 'accounts/register.html' + form_class = UserCreationForm + + # Redirect to profile + success_url = reverse_lazy('accounts:profile') + + def form_valid(self, form): + """ + Receive the form already validated. + Logs the user into the system. + """ + + # Get the user saved by form. + user = form.save() + + user = authenticate( + username=user.username, + password=form.cleaned_data['password1'] + ) + login(self.request, user) + + if user.is_teacher: + messages.success( + self.request, + _("Teacher created successfully.") + ) + else: + messages.success( + self.request, + _("Student created successfully.") + ) + + return HttpResponseRedirect(self.success_url) diff --git a/pgtbl/accounts/views/reset_password_confirm_view.py b/pgtbl/accounts/views/reset_password_confirm_view.py new file mode 100644 index 0000000..60f575a --- /dev/null +++ b/pgtbl/accounts/views/reset_password_confirm_view.py @@ -0,0 +1,60 @@ +from django.contrib.auth.forms import SetPasswordForm +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.shortcuts import get_object_or_404 +from django.contrib import messages +from django.views.generic import FormView + +# Application imoports +from accounts.models import PasswordReset + + +class ResetPasswordConfirmView(FormView): + """ + Insert new password from email link. + """ + + template_name = 'accounts/reset_password_confirm.html' + + # Use SetPasswordForm from django + form_class = SetPasswordForm + + # Redirect to login page. + success_url = reverse_lazy('accounts:login') + + def get_form_kwargs(self): + """ + Insert arguments inside form. + """ + + # Get all arguments kwargs from SetPasswordForm + kwargs = super(ResetPasswordConfirmView, self).get_form_kwargs() + + # Get the user with kwargs key to reset his password + reset = get_object_or_404( + PasswordReset, + key=self.kwargs.get('key') + ) + + # Change user and data from form + kwargs['user'] = reset.user + kwargs['data'] = self.request.POST or None + + return kwargs + + def form_valid(self, form): + """ + Validated form and reset password. + """ + + # In this case when you insert new kwargs, you need to save + # the instance again + form.save() + + messages.success( + self.request, + _("Your password was successfully updated.") + ) + + # Redirect to success_url + return super(ResetPasswordConfirmView, self).form_valid(form) diff --git a/pgtbl/accounts/views/reset_password_view.py b/pgtbl/accounts/views/reset_password_view.py new file mode 100644 index 0000000..833558e --- /dev/null +++ b/pgtbl/accounts/views/reset_password_view.py @@ -0,0 +1,56 @@ +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages +from django.views.generic import FormView + +# Application imoports +from core.email import send_email_template +from core.utils import generate_hash_key +from accounts.forms import PasswordResetForm +from accounts.models import PasswordReset + +# Get the custom user from settings +User = get_user_model() + + +class ResetPasswordView(FormView): + """ + Reset the user password and send email. + """ + + template_name = 'accounts/reset_password.html' + + # Use the PasswordResetForm + form_class = PasswordResetForm + + # Redirect to home page + success_url = reverse_lazy('core:home') + + def form_valid(self, form): + """ + Validated form and send email. + """ + + user = User.objects.get(email=form.cleaned_data['email']) + + # Generate unique key to reset password + key = generate_hash_key(user.username) + reset_password = PasswordReset(user=user, key=key) + reset_password.save() + + # Send email + send_email_template( + subject=_('Requesting new password'), + template='accounts/reset_password_email.html', + context={'reset_password': reset_password}, + recipient_list=[user.email], + ) + + messages.success( + self.request, + _("An email was sent with more details on how to create a new password") + ) + + # Redirect to success_url + return super(ResetPasswordView, self).form_valid(form) From a489fa0676e9d0973bfecb4e42b1791ecb23583e Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 16:59:51 -0300 Subject: [PATCH 03/56] Refactoring core app --- pgtbl/core/forms/__init__.py | 1 + .../{forms.py => forms/send_email_form.py} | 0 pgtbl/core/models/__init__.py | 2 + pgtbl/core/{models.py => models/news.py} | 28 +------ pgtbl/core/models/tag.py | 29 ++++++++ pgtbl/core/views/__init__.py | 3 + .../{views.py => views/home_page_view.py} | 74 +------------------ pgtbl/core/views/news_detail_view.py | 7 ++ pgtbl/core/views/news_list_view.py | 61 +++++++++++++++ 9 files changed, 108 insertions(+), 97 deletions(-) create mode 100644 pgtbl/core/forms/__init__.py rename pgtbl/core/{forms.py => forms/send_email_form.py} (100%) create mode 100644 pgtbl/core/models/__init__.py rename pgtbl/core/{models.py => models/news.py} (73%) create mode 100644 pgtbl/core/models/tag.py create mode 100644 pgtbl/core/views/__init__.py rename pgtbl/core/{views.py => views/home_page_view.py} (50%) create mode 100644 pgtbl/core/views/news_detail_view.py create mode 100644 pgtbl/core/views/news_list_view.py diff --git a/pgtbl/core/forms/__init__.py b/pgtbl/core/forms/__init__.py new file mode 100644 index 0000000..2d83206 --- /dev/null +++ b/pgtbl/core/forms/__init__.py @@ -0,0 +1 @@ +from .send_email_form import SendEmailForm diff --git a/pgtbl/core/forms.py b/pgtbl/core/forms/send_email_form.py similarity index 100% rename from pgtbl/core/forms.py rename to pgtbl/core/forms/send_email_form.py diff --git a/pgtbl/core/models/__init__.py b/pgtbl/core/models/__init__.py new file mode 100644 index 0000000..9141cf8 --- /dev/null +++ b/pgtbl/core/models/__init__.py @@ -0,0 +1,2 @@ +from .tag import Tag +from .news import News diff --git a/pgtbl/core/models.py b/pgtbl/core/models/news.py similarity index 73% rename from pgtbl/core/models.py rename to pgtbl/core/models/news.py index 097a13d..935c388 100644 --- a/pgtbl/core/models.py +++ b/pgtbl/core/models/news.py @@ -1,32 +1,6 @@ from django.utils.translation import ugettext_lazy as _ from django.db import models - - -class Tag(models.Model): - """ - Tags for improve system features. - """ - - title = models.CharField( - _('Tag'), - max_length=20 - ) - - slug = models.SlugField( - _('Identify'), - max_length=100 - ) - - def __str__(self): - """ - String format of object. - """ - - return self.title - - class Meta: - verbose_name = _("Tag") - verbose_name_plural = _("Tags") +from .tag import Tag class News(models.Model): diff --git a/pgtbl/core/models/tag.py b/pgtbl/core/models/tag.py new file mode 100644 index 0000000..3f400ba --- /dev/null +++ b/pgtbl/core/models/tag.py @@ -0,0 +1,29 @@ +from django.utils.translation import ugettext_lazy as _ +from django.db import models + + +class Tag(models.Model): + """ + Tags for improve system features. + """ + + title = models.CharField( + _('Tag'), + max_length=20 + ) + + slug = models.SlugField( + _('Identify'), + max_length=100 + ) + + def __str__(self): + """ + String format of object. + """ + + return self.title + + class Meta: + verbose_name = _("Tag") + verbose_name_plural = _("Tags") diff --git a/pgtbl/core/views/__init__.py b/pgtbl/core/views/__init__.py new file mode 100644 index 0000000..bfe88ee --- /dev/null +++ b/pgtbl/core/views/__init__.py @@ -0,0 +1,3 @@ +from .home_page_view import HomePageView +from .news_list_view import NewsListView +from .news_detail_view import NewsDetailView diff --git a/pgtbl/core/views.py b/pgtbl/core/views/home_page_view.py similarity index 50% rename from pgtbl/core/views.py rename to pgtbl/core/views/home_page_view.py index 8ebf504..768e0cc 100644 --- a/pgtbl/core/views.py +++ b/pgtbl/core/views/home_page_view.py @@ -1,16 +1,13 @@ -# Django app from django.utils.translation import ugettext_lazy as _ -from django.views.generic import ListView, DetailView from django.core.urlresolvers import reverse_lazy from django.contrib import messages from django.conf import settings -from django.db.models import Q # Core app -from .email import send_email_template -from .generics import FormListView -from .forms import SendEmailForm -from .models import News +from core.email import send_email_template +from core.generics import FormListView +from core.forms import SendEmailForm +from core.models import News class HomePageView(FormListView): @@ -75,66 +72,3 @@ def form_valid(self, form): # Redirect to success_url return super(HomePageView, self).form_valid(form) - - -class NewsListView(ListView): - paginate_by = 6 - template_name = 'core/news_list.html' - context_object_name = 'news_list' - - def get_queryset(self): - """ - Get the all news from model database. - """ - - queryset = News.objects.all() - - # Get the tag by key argument from url - tag = self.kwargs.get('tag', '') - - if tag: - # Verify if the tag url slug contains the specific tag and get all - # elemente with that tag - queryset = queryset.filter(tags__slug__icontains=tag) - - # Get searched news - queryset = self.search_news(queryset) - - return queryset - - def get_context_data(self, **kwargs): - """ - Insert more elements into context data to template. - """ - - context = super(NewsListView, self).get_context_data() - context['home'] = False - - # Get the tag by key argument from url - tag = self.kwargs.get('tag', '') - if tag: - context['tag'] = tag - - return context - - def search_news(self, news_list): - """ - Search from news list the specific news - """ - - query = self.request.GET.get("q_info") - - if query: - # Verify if news title and content contains the query specify - # by user and filter all news that satisfies this - news_list = news_list.filter( - Q(title__icontains=query) | - Q(content__icontains=query) - ).distinct() - - return news_list - - -class NewsDetailView(DetailView): - model = News - template_name = 'core/news_details.html' diff --git a/pgtbl/core/views/news_detail_view.py b/pgtbl/core/views/news_detail_view.py new file mode 100644 index 0000000..3c86b84 --- /dev/null +++ b/pgtbl/core/views/news_detail_view.py @@ -0,0 +1,7 @@ +from django.views.generic import DetailView +from core.models import News + + +class NewsDetailView(DetailView): + model = News + template_name = 'core/news_details.html' diff --git a/pgtbl/core/views/news_list_view.py b/pgtbl/core/views/news_list_view.py new file mode 100644 index 0000000..1d7d679 --- /dev/null +++ b/pgtbl/core/views/news_list_view.py @@ -0,0 +1,61 @@ +from django.views.generic import ListView +from django.db.models import Q +from core.models import News + + +class NewsListView(ListView): + paginate_by = 6 + template_name = 'core/news_list.html' + context_object_name = 'news_list' + + def get_queryset(self): + """ + Get the all news from model database. + """ + + queryset = News.objects.all() + + # Get the tag by key argument from url + tag = self.kwargs.get('tag', '') + + if tag: + # Verify if the tag url slug contains the specific tag and get all + # elemente with that tag + queryset = queryset.filter(tags__slug__icontains=tag) + + # Get searched news + queryset = self.search_news(queryset) + + return queryset + + def get_context_data(self, **kwargs): + """ + Insert more elements into context data to template. + """ + + context = super(NewsListView, self).get_context_data() + context['home'] = False + + # Get the tag by key argument from url + tag = self.kwargs.get('tag', '') + if tag: + context['tag'] = tag + + return context + + def search_news(self, news_list): + """ + Search from news list the specific news + """ + + query = self.request.GET.get("q_info") + + if query: + # Verify if news title and content contains the query specify + # by user and filter all news that satisfies this + news_list = news_list.filter( + Q(title__icontains=query) | + Q(content__icontains=query) + ).distinct() + + return news_list From a38acb8ec62cf625c8795a9089536ed0dd6ed62a Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 20:05:40 -0300 Subject: [PATCH 04/56] Finish refactoring accounts --- ...it_password.py => test_password_update.py} | 2 +- .../{test_register.py => test_user_create.py} | 2 +- ...est_delete_user.py => test_user_delete.py} | 2 +- ...{test_edit_user.py => test_user_update.py} | 2 +- pgtbl/accounts/urls.py | 24 +++++++++---------- pgtbl/accounts/views/__init__.py | 10 ++++---- ...ssword_view.py => password_update_view.py} | 6 ++--- .../{register_view.py => user_create_view.py} | 2 +- ...te_profile_view.py => user_delete_view.py} | 4 ++-- .../{profile_view.py => user_detail_view.py} | 2 +- ...it_profile_view.py => user_update_view.py} | 4 ++-- 11 files changed, 30 insertions(+), 30 deletions(-) rename pgtbl/accounts/tests/{test_edit_password.py => test_password_update.py} (98%) rename pgtbl/accounts/tests/{test_register.py => test_user_create.py} (99%) rename pgtbl/accounts/tests/{test_delete_user.py => test_user_delete.py} (97%) rename pgtbl/accounts/tests/{test_edit_user.py => test_user_update.py} (98%) rename pgtbl/accounts/views/{edit_password_view.py => password_update_view.py} (86%) rename pgtbl/accounts/views/{register_view.py => user_create_view.py} (97%) rename pgtbl/accounts/views/{delete_profile_view.py => user_delete_view.py} (88%) rename pgtbl/accounts/views/{profile_view.py => user_detail_view.py} (97%) rename pgtbl/accounts/views/{edit_profile_view.py => user_update_view.py} (91%) diff --git a/pgtbl/accounts/tests/test_edit_password.py b/pgtbl/accounts/tests/test_password_update.py similarity index 98% rename from pgtbl/accounts/tests/test_edit_password.py rename to pgtbl/accounts/tests/test_password_update.py index 3b65a01..6bdb81b 100644 --- a/pgtbl/accounts/tests/test_edit_password.py +++ b/pgtbl/accounts/tests/test_password_update.py @@ -8,7 +8,7 @@ User = get_user_model() -class EditPasswordTestCase(TestCase): +class PasswordUpdateTestCase(TestCase): """ Test to edit password from user. """ diff --git a/pgtbl/accounts/tests/test_register.py b/pgtbl/accounts/tests/test_user_create.py similarity index 99% rename from pgtbl/accounts/tests/test_register.py rename to pgtbl/accounts/tests/test_user_create.py index 949e6c8..cf235c8 100644 --- a/pgtbl/accounts/tests/test_register.py +++ b/pgtbl/accounts/tests/test_user_create.py @@ -9,7 +9,7 @@ User = get_user_model() -class RegisterTestCase(TestCase): +class UserCreateTestCase(TestCase): """ Test to register a new user into the system. """ diff --git a/pgtbl/accounts/tests/test_delete_user.py b/pgtbl/accounts/tests/test_user_delete.py similarity index 97% rename from pgtbl/accounts/tests/test_delete_user.py rename to pgtbl/accounts/tests/test_user_delete.py index f1158f4..b17531f 100644 --- a/pgtbl/accounts/tests/test_delete_user.py +++ b/pgtbl/accounts/tests/test_user_delete.py @@ -7,7 +7,7 @@ User = get_user_model() -class DeleteUserTestCase(TestCase): +class UserDeleteTestCase(TestCase): """ Test to delete a user account. """ diff --git a/pgtbl/accounts/tests/test_edit_user.py b/pgtbl/accounts/tests/test_user_update.py similarity index 98% rename from pgtbl/accounts/tests/test_edit_user.py rename to pgtbl/accounts/tests/test_user_update.py index 4bb6b0d..f9d5dd3 100644 --- a/pgtbl/accounts/tests/test_edit_user.py +++ b/pgtbl/accounts/tests/test_user_update.py @@ -8,7 +8,7 @@ User = get_user_model() -class EditUserTestCase(TestCase): +class UserUpdateTestCase(TestCase): """ Test to edit personal information from user. """ diff --git a/pgtbl/accounts/urls.py b/pgtbl/accounts/urls.py index 277af50..303d0e0 100644 --- a/pgtbl/accounts/urls.py +++ b/pgtbl/accounts/urls.py @@ -8,27 +8,27 @@ # / url( r'^$', - views.ProfileView.as_view(), + views.UserDetailView.as_view(), name='profile' ), - # edit/ + # update/ url( - r'^edit/$', - views.EditProfileView.as_view(), + r'^update/$', + views.UserUpdateView.as_view(), name='update-user' ), - # edit-password/ - url( - r'^edit-password/$', - views.EditPasswordView.as_view(), - name='update-password' - ), # delete/ url( r'^delete/$', - views.DeleteProfileView.as_view(), + views.UserDeleteView.as_view(), name='delete-user' ), + # password-update/ + url( + r'^password-update/$', + views.PasswordUpdateView.as_view(), + name='update-password' + ), ] urlpatterns = [ @@ -52,7 +52,7 @@ # /register/ url( r'^register/$', - views.RegisterView.as_view(), + views.UserCreateView.as_view(), name='register' ), # /reset-password/ diff --git a/pgtbl/accounts/views/__init__.py b/pgtbl/accounts/views/__init__.py index de8b1dd..330b6b6 100644 --- a/pgtbl/accounts/views/__init__.py +++ b/pgtbl/accounts/views/__init__.py @@ -1,7 +1,7 @@ -from .profile_view import ProfileView -from .register_view import RegisterView -from .edit_profile_view import EditProfileView -from .delete_profile_view import DeleteProfileView -from .edit_password_view import EditPasswordView +from .user_detail_view import UserDetailView +from .user_create_view import UserCreateView +from .user_update_view import UserUpdateView +from .user_delete_view import UserDeleteView +from .password_update_view import PasswordUpdateView from .reset_password_confirm_view import ResetPasswordConfirmView from .reset_password_view import ResetPasswordView diff --git a/pgtbl/accounts/views/edit_password_view.py b/pgtbl/accounts/views/password_update_view.py similarity index 86% rename from pgtbl/accounts/views/edit_password_view.py rename to pgtbl/accounts/views/password_update_view.py index 03d894f..5762016 100644 --- a/pgtbl/accounts/views/edit_password_view.py +++ b/pgtbl/accounts/views/password_update_view.py @@ -6,7 +6,7 @@ from django.views.generic import FormView -class EditPasswordView(LoginRequiredMixin, FormView): +class PasswordUpdateView(LoginRequiredMixin, FormView): """ Edit user password. """ @@ -25,7 +25,7 @@ def get_form_kwargs(self): """ # Get the kwargs from the original class FormView - kwargs = super(EditPasswordView, self).get_form_kwargs() + kwargs = super(PasswordUpdateView, self).get_form_kwargs() # Insert the parameter logged user into the form template kwargs['user'] = self.request.user @@ -43,4 +43,4 @@ def form_valid(self, form): messages.success(self.request, _("Password updated successfully.")) # Redirect to success_url - return super(EditPasswordView, self).form_valid(form) + return super(PasswordUpdateView, self).form_valid(form) diff --git a/pgtbl/accounts/views/register_view.py b/pgtbl/accounts/views/user_create_view.py similarity index 97% rename from pgtbl/accounts/views/register_view.py rename to pgtbl/accounts/views/user_create_view.py index 26f0ad5..abe33df 100644 --- a/pgtbl/accounts/views/register_view.py +++ b/pgtbl/accounts/views/user_create_view.py @@ -14,7 +14,7 @@ User = get_user_model() -class RegisterView(CreateView): +class UserCreateView(CreateView): """ Class to create a new user. """ diff --git a/pgtbl/accounts/views/delete_profile_view.py b/pgtbl/accounts/views/user_delete_view.py similarity index 88% rename from pgtbl/accounts/views/delete_profile_view.py rename to pgtbl/accounts/views/user_delete_view.py index c511ba8..06829af 100644 --- a/pgtbl/accounts/views/delete_profile_view.py +++ b/pgtbl/accounts/views/user_delete_view.py @@ -9,7 +9,7 @@ User = get_user_model() -class DeleteProfileView(LoginRequiredMixin, DeleteView): +class UserDeleteView(LoginRequiredMixin, DeleteView): """ Delete the user account """ @@ -35,4 +35,4 @@ def get_success_url(self): messages.success(self.request, _("Accounts deleted successfully.")) # Redirect to success_url - return super(DeleteProfileView, self).get_success_url() + return super(UserDeleteView, self).get_success_url() diff --git a/pgtbl/accounts/views/profile_view.py b/pgtbl/accounts/views/user_detail_view.py similarity index 97% rename from pgtbl/accounts/views/profile_view.py rename to pgtbl/accounts/views/user_detail_view.py index 2d62cc8..b4707d8 100644 --- a/pgtbl/accounts/views/profile_view.py +++ b/pgtbl/accounts/views/user_detail_view.py @@ -6,7 +6,7 @@ from disciplines.models import Discipline -class ProfileView(LoginRequiredMixin, ListView): +class UserDetailView(LoginRequiredMixin, ListView): """ Class to read a profile user and his disciplines. """ diff --git a/pgtbl/accounts/views/edit_profile_view.py b/pgtbl/accounts/views/user_update_view.py similarity index 91% rename from pgtbl/accounts/views/edit_profile_view.py rename to pgtbl/accounts/views/user_update_view.py index 8f9c9d8..8d2f724 100644 --- a/pgtbl/accounts/views/edit_profile_view.py +++ b/pgtbl/accounts/views/user_update_view.py @@ -9,7 +9,7 @@ User = get_user_model() -class EditProfileView(LoginRequiredMixin, UpdateView): +class UserUpdateView(LoginRequiredMixin, UpdateView): """ Edit personal information from user. """ @@ -43,4 +43,4 @@ def form_valid(self, form): ) # Redirect to success_url - return super(EditProfileView, self).form_valid(form) + return super(UserUpdateView, self).form_valid(form) From ac03708c09e0895da258589b7980c3a4f2f81f64 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 20:15:23 -0300 Subject: [PATCH 05/56] Finish refactoring core --- .../static/{core => home}/css/contact.css | 0 .../core/static/{core => home}/css/footer.css | 0 pgtbl/core/static/{core => home}/css/home.css | 0 .../static/{core => home}/css/parallax.css | 0 .../static/{core => home}/css/timeline.css | 0 .../static/{core => home}/img/parallax.jpg | Bin .../css/news_home.css => news/css/home.css} | 0 .../css/news_list.css => news/css/list.css} | 0 pgtbl/core/templates/core/base.html | 2 +- pgtbl/core/templates/core/home.html | 29 ------------------ .../templates/{core => home}/contact.html | 0 .../templates/{core => home}/features.html | 0 .../core/templates/{core => home}/footer.html | 0 pgtbl/core/templates/home/home.html | 29 ++++++++++++++++++ .../templates/{core => home}/parallax.html | 0 .../news_details.html => news/details.html} | 2 +- .../{core/news_list.html => news/list.html} | 2 +- pgtbl/core/templates/{core => news}/news.html | 0 pgtbl/core/tests/__init__.py | 0 pgtbl/core/tests/test_home_view.py | 12 ++++---- pgtbl/core/tests/test_news_page.py | 4 +-- pgtbl/core/views/home_page_view.py | 2 +- pgtbl/core/views/news_detail_view.py | 2 +- pgtbl/core/views/news_list_view.py | 2 +- 24 files changed, 43 insertions(+), 43 deletions(-) rename pgtbl/core/static/{core => home}/css/contact.css (100%) rename pgtbl/core/static/{core => home}/css/footer.css (100%) rename pgtbl/core/static/{core => home}/css/home.css (100%) rename pgtbl/core/static/{core => home}/css/parallax.css (100%) rename pgtbl/core/static/{core => home}/css/timeline.css (100%) rename pgtbl/core/static/{core => home}/img/parallax.jpg (100%) rename pgtbl/core/static/{core/css/news_home.css => news/css/home.css} (100%) rename pgtbl/core/static/{core/css/news_list.css => news/css/list.css} (100%) delete mode 100644 pgtbl/core/templates/core/home.html rename pgtbl/core/templates/{core => home}/contact.html (100%) rename pgtbl/core/templates/{core => home}/features.html (100%) rename pgtbl/core/templates/{core => home}/footer.html (100%) create mode 100644 pgtbl/core/templates/home/home.html rename pgtbl/core/templates/{core => home}/parallax.html (100%) rename pgtbl/core/templates/{core/news_details.html => news/details.html} (97%) rename pgtbl/core/templates/{core/news_list.html => news/list.html} (97%) rename pgtbl/core/templates/{core => news}/news.html (100%) create mode 100644 pgtbl/core/tests/__init__.py diff --git a/pgtbl/core/static/core/css/contact.css b/pgtbl/core/static/home/css/contact.css similarity index 100% rename from pgtbl/core/static/core/css/contact.css rename to pgtbl/core/static/home/css/contact.css diff --git a/pgtbl/core/static/core/css/footer.css b/pgtbl/core/static/home/css/footer.css similarity index 100% rename from pgtbl/core/static/core/css/footer.css rename to pgtbl/core/static/home/css/footer.css diff --git a/pgtbl/core/static/core/css/home.css b/pgtbl/core/static/home/css/home.css similarity index 100% rename from pgtbl/core/static/core/css/home.css rename to pgtbl/core/static/home/css/home.css diff --git a/pgtbl/core/static/core/css/parallax.css b/pgtbl/core/static/home/css/parallax.css similarity index 100% rename from pgtbl/core/static/core/css/parallax.css rename to pgtbl/core/static/home/css/parallax.css diff --git a/pgtbl/core/static/core/css/timeline.css b/pgtbl/core/static/home/css/timeline.css similarity index 100% rename from pgtbl/core/static/core/css/timeline.css rename to pgtbl/core/static/home/css/timeline.css diff --git a/pgtbl/core/static/core/img/parallax.jpg b/pgtbl/core/static/home/img/parallax.jpg similarity index 100% rename from pgtbl/core/static/core/img/parallax.jpg rename to pgtbl/core/static/home/img/parallax.jpg diff --git a/pgtbl/core/static/core/css/news_home.css b/pgtbl/core/static/news/css/home.css similarity index 100% rename from pgtbl/core/static/core/css/news_home.css rename to pgtbl/core/static/news/css/home.css diff --git a/pgtbl/core/static/core/css/news_list.css b/pgtbl/core/static/news/css/list.css similarity index 100% rename from pgtbl/core/static/core/css/news_list.css rename to pgtbl/core/static/news/css/list.css diff --git a/pgtbl/core/templates/core/base.html b/pgtbl/core/templates/core/base.html index 2b80dd7..6e6f122 100644 --- a/pgtbl/core/templates/core/base.html +++ b/pgtbl/core/templates/core/base.html @@ -14,7 +14,7 @@ - + {% block css %}{% endblock %} diff --git a/pgtbl/core/templates/core/home.html b/pgtbl/core/templates/core/home.html deleted file mode 100644 index 4a27d1c..0000000 --- a/pgtbl/core/templates/core/home.html +++ /dev/null @@ -1,29 +0,0 @@ - -{% extends "core/base.html" %} - - -{% load static %} - -{% block css %} - - - - - - -{% endblock %} - -{% block body %} -
- {% include 'core/navbar.html' %} -
-
- {% include 'core/parallax.html' %} - {% include 'core/features.html' %} - {% include 'core/news.html' %} - {% include 'core/contact.html' %} -
-
- {% include 'core/footer.html' %} -
-{% endblock %} diff --git a/pgtbl/core/templates/core/contact.html b/pgtbl/core/templates/home/contact.html similarity index 100% rename from pgtbl/core/templates/core/contact.html rename to pgtbl/core/templates/home/contact.html diff --git a/pgtbl/core/templates/core/features.html b/pgtbl/core/templates/home/features.html similarity index 100% rename from pgtbl/core/templates/core/features.html rename to pgtbl/core/templates/home/features.html diff --git a/pgtbl/core/templates/core/footer.html b/pgtbl/core/templates/home/footer.html similarity index 100% rename from pgtbl/core/templates/core/footer.html rename to pgtbl/core/templates/home/footer.html diff --git a/pgtbl/core/templates/home/home.html b/pgtbl/core/templates/home/home.html new file mode 100644 index 0000000..ad4ac31 --- /dev/null +++ b/pgtbl/core/templates/home/home.html @@ -0,0 +1,29 @@ + +{% extends "core/base.html" %} + + +{% load static %} + +{% block css %} + + + + + + +{% endblock %} + +{% block body %} +
+ {% include 'core/navbar.html' %} +
+
+ {% include 'home/parallax.html' %} + {% include 'home/features.html' %} + {% include 'news/news.html' %} + {% include 'home/contact.html' %} +
+
+ {% include 'home/footer.html' %} +
+{% endblock %} diff --git a/pgtbl/core/templates/core/parallax.html b/pgtbl/core/templates/home/parallax.html similarity index 100% rename from pgtbl/core/templates/core/parallax.html rename to pgtbl/core/templates/home/parallax.html diff --git a/pgtbl/core/templates/core/news_details.html b/pgtbl/core/templates/news/details.html similarity index 97% rename from pgtbl/core/templates/core/news_details.html rename to pgtbl/core/templates/news/details.html index 64d5b14..28e033c 100644 --- a/pgtbl/core/templates/core/news_details.html +++ b/pgtbl/core/templates/news/details.html @@ -3,7 +3,7 @@ {% load i18n %} {% block css %} - + {% endblock %} {% block body %} diff --git a/pgtbl/core/templates/core/news_list.html b/pgtbl/core/templates/news/list.html similarity index 97% rename from pgtbl/core/templates/core/news_list.html rename to pgtbl/core/templates/news/list.html index 6a88a27..4890214 100644 --- a/pgtbl/core/templates/core/news_list.html +++ b/pgtbl/core/templates/news/list.html @@ -3,7 +3,7 @@ {% load i18n %} {% block css %} - + {% endblock %} {% block body %} diff --git a/pgtbl/core/templates/core/news.html b/pgtbl/core/templates/news/news.html similarity index 100% rename from pgtbl/core/templates/core/news.html rename to pgtbl/core/templates/news/news.html diff --git a/pgtbl/core/tests/__init__.py b/pgtbl/core/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/core/tests/test_home_view.py b/pgtbl/core/tests/test_home_view.py index 4188c30..91ddc01 100644 --- a/pgtbl/core/tests/test_home_view.py +++ b/pgtbl/core/tests/test_home_view.py @@ -29,10 +29,10 @@ def test_templates_used(self): response = self.client.get(reverse('core:home')) self.assertTemplateUsed(response, 'core/base.html') - self.assertTemplateUsed(response, 'core/home.html') + self.assertTemplateUsed(response, 'home/home.html') self.assertTemplateUsed(response, 'core/navbar.html') - self.assertTemplateUsed(response, 'core/parallax.html') - self.assertTemplateUsed(response, 'core/features.html') - self.assertTemplateUsed(response, 'core/news.html') - self.assertTemplateUsed(response, 'core/contact.html') - self.assertTemplateUsed(response, 'core/footer.html') + self.assertTemplateUsed(response, 'home/parallax.html') + self.assertTemplateUsed(response, 'home/features.html') + self.assertTemplateUsed(response, 'news/news.html') + self.assertTemplateUsed(response, 'home/contact.html') + self.assertTemplateUsed(response, 'home/footer.html') diff --git a/pgtbl/core/tests/test_news_page.py b/pgtbl/core/tests/test_news_page.py index 088923a..a944749 100644 --- a/pgtbl/core/tests/test_news_page.py +++ b/pgtbl/core/tests/test_news_page.py @@ -70,7 +70,7 @@ def test_news_list_templates_used(self): response = self.client.get(reverse('core:news')) self.assertTemplateUsed(response, 'core/base.html') - self.assertTemplateUsed(response, 'core/news_list.html') + self.assertTemplateUsed(response, 'news/list.html') def test_to_access_the_news_url_with_tag(self): """ @@ -107,4 +107,4 @@ def test_news_details_templates_used(self): url = reverse('core:news-details', kwargs={'slug': self.news1.slug}) response = self.client.get(url) self.assertTemplateUsed(response, 'core/base.html') - self.assertTemplateUsed(response, 'core/news_details.html') + self.assertTemplateUsed(response, 'news/details.html') diff --git a/pgtbl/core/views/home_page_view.py b/pgtbl/core/views/home_page_view.py index 768e0cc..fcb8793 100644 --- a/pgtbl/core/views/home_page_view.py +++ b/pgtbl/core/views/home_page_view.py @@ -15,7 +15,7 @@ class HomePageView(FormListView): Home page of application. """ - template_name = 'core/home.html' + template_name = 'home/home.html' context_object_name = 'news_list' # Get the SendEmailForm diff --git a/pgtbl/core/views/news_detail_view.py b/pgtbl/core/views/news_detail_view.py index 3c86b84..014640a 100644 --- a/pgtbl/core/views/news_detail_view.py +++ b/pgtbl/core/views/news_detail_view.py @@ -4,4 +4,4 @@ class NewsDetailView(DetailView): model = News - template_name = 'core/news_details.html' + template_name = 'news/details.html' diff --git a/pgtbl/core/views/news_list_view.py b/pgtbl/core/views/news_list_view.py index 1d7d679..f3e545e 100644 --- a/pgtbl/core/views/news_list_view.py +++ b/pgtbl/core/views/news_list_view.py @@ -5,7 +5,7 @@ class NewsListView(ListView): paginate_by = 6 - template_name = 'core/news_list.html' + template_name = 'news/list.html' context_object_name = 'news_list' def get_queryset(self): From 397653f088d240c6a2277f0df880d1aa88dfec69 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 21:16:40 -0300 Subject: [PATCH 06/56] Refactoring discipline models and forms --- pgtbl/disciplines/forms.py | 63 ------------------- pgtbl/disciplines/forms/__init__.py | 3 + .../forms/discipline_enter_form.py | 14 +++++ pgtbl/disciplines/forms/discipline_form.py | 25 ++++++++ .../forms/discipline_update_form.py | 22 +++++++ pgtbl/disciplines/models/__init__.py | 1 + .../{models.py => models/discipline.py} | 0 pgtbl/disciplines/tests/__init__.py | 0 pgtbl/disciplines/views.py | 8 +-- 9 files changed, 69 insertions(+), 67 deletions(-) delete mode 100644 pgtbl/disciplines/forms.py create mode 100644 pgtbl/disciplines/forms/__init__.py create mode 100644 pgtbl/disciplines/forms/discipline_enter_form.py create mode 100644 pgtbl/disciplines/forms/discipline_form.py create mode 100644 pgtbl/disciplines/forms/discipline_update_form.py create mode 100644 pgtbl/disciplines/models/__init__.py rename pgtbl/disciplines/{models.py => models/discipline.py} (100%) create mode 100644 pgtbl/disciplines/tests/__init__.py diff --git a/pgtbl/disciplines/forms.py b/pgtbl/disciplines/forms.py deleted file mode 100644 index 1f47f09..0000000 --- a/pgtbl/disciplines/forms.py +++ /dev/null @@ -1,63 +0,0 @@ -from django.utils.translation import ugettext_lazy as _ -from django.contrib.auth import get_user_model -from django import forms - -# App imports -from pagedown.widgets import PagedownWidget -from .models import Discipline - -# # Get the custom user from settings -User = get_user_model() - - -class DisciplineForm(forms.ModelForm): - """ - Form to create a new discipline. - """ - - class Meta: - model = Discipline - fields = [ - 'title', 'course', 'description', 'classroom', - 'password', 'students_limit', 'monitors_limit' - ] - - # Widgets about some fields - widgets = { - 'password': forms.PasswordInput(), - 'description': PagedownWidget( - css=("core/css/markdown.css"), - show_preview=False - ) - } - - -class DisciplineEditForm(forms.ModelForm): - """ - Form to create a new discipline. - """ - description = forms.CharField( - widget=PagedownWidget( - css=("core/css/markdown.css"), - show_preview=False - ) - ) - - class Meta: - model = Discipline - fields = [ - 'title', 'course', 'description', 'classroom', - 'password', 'students_limit', 'monitors_limit' - ] - - -class EnterDisciplineForm(forms.Form): - """ - Form to insert students and monitors in the discipline. - """ - - password = forms.CharField( - label=_('Access Password'), - max_length=30, - widget=forms.PasswordInput - ) diff --git a/pgtbl/disciplines/forms/__init__.py b/pgtbl/disciplines/forms/__init__.py new file mode 100644 index 0000000..319e401 --- /dev/null +++ b/pgtbl/disciplines/forms/__init__.py @@ -0,0 +1,3 @@ +from .discipline_enter_form import DisciplineEnterForm +from .discipline_form import DisciplineForm +from .discipline_update_form import DisciplineUpdateForm diff --git a/pgtbl/disciplines/forms/discipline_enter_form.py b/pgtbl/disciplines/forms/discipline_enter_form.py new file mode 100644 index 0000000..9c9b0cb --- /dev/null +++ b/pgtbl/disciplines/forms/discipline_enter_form.py @@ -0,0 +1,14 @@ +from django.utils.translation import ugettext_lazy as _ +from django import forms + + +class DisciplineEnterForm(forms.Form): + """ + Form to insert students and monitors in the discipline. + """ + + password = forms.CharField( + label=_('Access Password'), + max_length=30, + widget=forms.PasswordInput + ) diff --git a/pgtbl/disciplines/forms/discipline_form.py b/pgtbl/disciplines/forms/discipline_form.py new file mode 100644 index 0000000..90969df --- /dev/null +++ b/pgtbl/disciplines/forms/discipline_form.py @@ -0,0 +1,25 @@ +from django import forms +from pagedown.widgets import PagedownWidget +from disciplines.models import Discipline + + +class DisciplineForm(forms.ModelForm): + """ + Form to create a new discipline. + """ + + class Meta: + model = Discipline + fields = [ + 'title', 'course', 'description', 'classroom', + 'password', 'students_limit', 'monitors_limit' + ] + + # Widgets about some fields + widgets = { + 'password': forms.PasswordInput(), + 'description': PagedownWidget( + css=("core/css/markdown.css"), + show_preview=False + ) + } diff --git a/pgtbl/disciplines/forms/discipline_update_form.py b/pgtbl/disciplines/forms/discipline_update_form.py new file mode 100644 index 0000000..5b6ec22 --- /dev/null +++ b/pgtbl/disciplines/forms/discipline_update_form.py @@ -0,0 +1,22 @@ +from django import forms +from pagedown.widgets import PagedownWidget +from disciplines.models import Discipline + + +class DisciplineUpdateForm(forms.ModelForm): + """ + Form to create a new discipline. + """ + description = forms.CharField( + widget=PagedownWidget( + css=("core/css/markdown.css"), + show_preview=False + ) + ) + + class Meta: + model = Discipline + fields = [ + 'title', 'course', 'description', 'classroom', + 'password', 'students_limit', 'monitors_limit' + ] diff --git a/pgtbl/disciplines/models/__init__.py b/pgtbl/disciplines/models/__init__.py new file mode 100644 index 0000000..9168dfb --- /dev/null +++ b/pgtbl/disciplines/models/__init__.py @@ -0,0 +1 @@ +from .discipline import Discipline diff --git a/pgtbl/disciplines/models.py b/pgtbl/disciplines/models/discipline.py similarity index 100% rename from pgtbl/disciplines/models.py rename to pgtbl/disciplines/models/discipline.py diff --git a/pgtbl/disciplines/tests/__init__.py b/pgtbl/disciplines/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/disciplines/views.py b/pgtbl/disciplines/views.py index 9633916..0b768fc 100644 --- a/pgtbl/disciplines/views.py +++ b/pgtbl/disciplines/views.py @@ -24,7 +24,7 @@ from core.utils import order # Discipline app -from .forms import DisciplineForm, DisciplineEditForm, EnterDisciplineForm +from .forms import DisciplineForm, DisciplineUpdateForm, DisciplineEnterForm from .models import Discipline # Get the custom user from settings @@ -86,7 +86,7 @@ class UpdateDisciplineView(LoginRequiredMixin, model = Discipline template_name = 'disciplines/form.html' - form_class = DisciplineEditForm + form_class = DisciplineUpdateForm success_url = reverse_lazy('accounts:profile') # Permissions @@ -168,7 +168,7 @@ def get_context_data(self, **kwargs): """ context = super(ListDisciplineView, self).get_context_data(**kwargs) - context['form'] = EnterDisciplineForm() + context['form'] = DisciplineEnterForm() return context def get_queryset(self): @@ -205,7 +205,7 @@ class EnterDisciplineView(LoginRequiredMixin, FormView): Insert students or monitors inside discipline. """ - form_class = EnterDisciplineForm + form_class = DisciplineEnterForm success_url = reverse_lazy('accounts:profile') template_name = 'disciplines/list.html' From 5c74c874591d199bf035110346424e0623884ec3 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 21:34:22 -0300 Subject: [PATCH 07/56] Rename discipline view classes --- pgtbl/disciplines/urls.py | 50 ++++++++++++++++++++++---------------- pgtbl/disciplines/views.py | 43 +++++++++++++++----------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/pgtbl/disciplines/urls.py b/pgtbl/disciplines/urls.py index bb32cdc..3b2eb46 100644 --- a/pgtbl/disciplines/urls.py +++ b/pgtbl/disciplines/urls.py @@ -7,73 +7,76 @@ # create-discipline/ url( r'^create-discipline/$', - views.CreateDisciplineView.as_view(), + views.DisciplineCreateView.as_view(), name='create' ), # list-discipline/ url( r'^list-discipline/$', - views.ListDisciplineView.as_view(), + views.DisciplineListView.as_view(), name='search' ), # update-discipline// url( r'^update-discipline/(?P[\w_-]+)/$', - views.UpdateDisciplineView.as_view(), + views.DisciplineUpdateView.as_view(), name='update' ), # delete-discipline// url( r'^delete-discipline/(?P[\w_-]+)/$', - views.DeleteDisciplineView.as_view(), + views.DisciplineDeleteView.as_view(), name='delete' ), # enter-discipline// url( r'^enter-discipline/(?P[\w_-]+)/$', - views.EnterDisciplineView.as_view(), + views.DisciplineEnterView.as_view(), name='enter' ), # / url( r'^(?P[\w_-]+)/$', - views.ShowDisciplineView.as_view(), + views.DisciplineDetailView.as_view(), name='details' ), # /closed/ url( r'^(?P[\w_-]+)/close/$', - views.CloseDisciplineView.as_view(), + views.DisciplineCloseView.as_view(), name='close' ), - # /students/ +] + +student_patterns = [ + # / url( - r'^(?P[\w_-]+)/students/$', + r'^$', views.StudentListView.as_view(), name='students' ), - # /students//remove + # /remove url( - r'^(?P[\w_-]+)/students/(?P[0-9]+)/remove/$', - views.RemoveStudentView.as_view(), + r'^(?P[0-9]+)/remove/$', + views.StudentRemoveView.as_view(), name='remove-student' ), - # /students/add/ + # add/ url( - r'^(?P[\w_-]+)/students/add/$', - views.ListUsersView.as_view(), + r'^add/$', + views.UsersListView.as_view(), name='users' ), - # /students/add// + # add// url( - r'^(?P[\w_-]+)/students/add/(?P[0-9]+)/$', - views.InsertStudentView.as_view(), + r'^add/(?P[0-9]+)/$', + views.StudentInsertView.as_view(), name='insert-students' ), - # /students//change + # /change url( - r'^(?P[\w_-]+)/students/(?P[0-9]+)/change/$', - views.ChangeStudentView.as_view(), + r'^(?P[0-9]+)/change/$', + views.StudentChangeView.as_view(), name='change-student' ), ] @@ -81,4 +84,9 @@ urlpatterns = [ # /profile/... url(r'^profile/', include(discipline_patterns)), + # /profile//students/... + url( + r'^profile/(?P[\w_-]+)/students/', + include(student_patterns) + ), ] diff --git a/pgtbl/disciplines/views.py b/pgtbl/disciplines/views.py index 0b768fc..afc6ecc 100644 --- a/pgtbl/disciplines/views.py +++ b/pgtbl/disciplines/views.py @@ -1,8 +1,3 @@ -""" -The list of user disciplines is in accounts.views.ProfileView -Disciplines functionalities -""" - # Django app from django.views.generic import ( CreateView, UpdateView, DeleteView, DetailView, @@ -31,7 +26,7 @@ User = get_user_model() -class CreateDisciplineView(LoginRequiredMixin, +class DisciplineCreateView(LoginRequiredMixin, ModelPermissionMixin, CreateView): """ @@ -74,10 +69,10 @@ def form_valid(self, form): messages.success(self.request, _('Discipline created successfully.')) # Redirect to success url - return super(CreateDisciplineView, self).form_valid(form) + return super(DisciplineCreateView, self).form_valid(form) -class UpdateDisciplineView(LoginRequiredMixin, +class DisciplineUpdateView(LoginRequiredMixin, PermissionMixin, UpdateView): """ @@ -123,10 +118,10 @@ def form_valid(self, form): messages.success(self.request, _("Discipline updated successfully.")) # Redirect to success_url. - return super(UpdateDisciplineView, self).form_valid(form) + return super(DisciplineUpdateView, self).form_valid(form) -class DeleteDisciplineView(LoginRequiredMixin, +class DisciplineDeleteView(LoginRequiredMixin, PermissionMixin, DeleteView): """ @@ -150,10 +145,10 @@ def get_success_url(self): messages.success(self.request, _("Discipline deleted successfully.")) # Redirect to success_url - return super(DeleteDisciplineView, self).get_success_url() + return super(DisciplineDeleteView, self).get_success_url() -class ListDisciplineView(LoginRequiredMixin, ListView): +class DisciplineListView(LoginRequiredMixin, ListView): """ View to search a discipline and enter it. """ @@ -167,7 +162,7 @@ def get_context_data(self, **kwargs): Insert a form inside discipline list. """ - context = super(ListDisciplineView, self).get_context_data(**kwargs) + context = super(DisciplineListView, self).get_context_data(**kwargs) context['form'] = DisciplineEnterForm() return context @@ -200,7 +195,7 @@ def search_disciplines(self, disciplines): return disciplines -class EnterDisciplineView(LoginRequiredMixin, FormView): +class DisciplineEnterView(LoginRequiredMixin, FormView): """ Insert students or monitors inside discipline. """ @@ -218,7 +213,7 @@ def form_valid(self, form): if success: # Redirect to success_url - return super(EnterDisciplineView, self).form_valid(form) + return super(DisciplineEnterView, self).form_valid(form) # Redirect to same page with error. redirect_url = reverse_lazy('disciplines:search') @@ -316,9 +311,9 @@ def insert_student(self, discipline): return True -class ShowDisciplineView(LoginRequiredMixin, - PermissionMixin, - DetailView): +class DisciplineDetailView(LoginRequiredMixin, + PermissionMixin, + DetailView): """ View to show a specific discipline. """ @@ -330,7 +325,7 @@ class ShowDisciplineView(LoginRequiredMixin, ] -class CloseDisciplineView(LoginRequiredMixin, +class DisciplineCloseView(LoginRequiredMixin, PermissionMixin, DeleteView): @@ -434,7 +429,7 @@ def students_filter(self, queryset): return queryset -class RemoveStudentView(LoginRequiredMixin, +class StudentRemoveView(LoginRequiredMixin, PermissionMixin, DeleteView): """ @@ -530,7 +525,7 @@ def remove_from_discipline(self, user, is_teacher=True): return success_url -class ListUsersView(LoginRequiredMixin, +class UsersListView(LoginRequiredMixin, PermissionMixin, ListView): """ @@ -551,7 +546,7 @@ def get_context_data(self, **kwargs): Insert form into list view. """ - context = super(ListUsersView, self).get_context_data(**kwargs) + context = super(UsersListView, self).get_context_data(**kwargs) context['discipline'] = self.get_discipline() return context @@ -610,7 +605,7 @@ def search(self, users): return users -class InsertStudentView(LoginRequiredMixin, +class StudentInsertView(LoginRequiredMixin, PermissionMixin, ObjectRedirectView): """ @@ -723,7 +718,7 @@ def insert_student(self, user, discipline): return True -class ChangeStudentView(LoginRequiredMixin, +class StudentChangeView(LoginRequiredMixin, PermissionMixin, ObjectRedirectView): """ From 7855d679596b7d41b610d95a6ad8dfb691a00835 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 21:42:47 -0300 Subject: [PATCH 08/56] rename discipline test cases --- .../{test_create_discipline.py => test_discipline_create.py} | 2 +- .../{test_delete_discipline.py => test_discipline_delete.py} | 2 +- .../{test_show_discipline.py => test_discipline_detail.py} | 4 ++-- .../{test_enter_discipline.py => test_discipline_enter.py} | 2 +- .../{test_list_discipline.py => test_discipline_list.py} | 2 +- .../{test_update_discipline.py => test_discipline_update.py} | 2 +- ...test_change_students_status.py => test_students_change.py} | 4 ++-- .../{test_insert_students.py => test_students_insert.py} | 4 ++-- pgtbl/disciplines/tests/test_students_list.py | 2 +- .../{test_remove_students.py => test_students_remove.py} | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) rename pgtbl/disciplines/tests/{test_create_discipline.py => test_discipline_create.py} (99%) rename pgtbl/disciplines/tests/{test_delete_discipline.py => test_discipline_delete.py} (98%) rename pgtbl/disciplines/tests/{test_show_discipline.py => test_discipline_detail.py} (96%) rename pgtbl/disciplines/tests/{test_enter_discipline.py => test_discipline_enter.py} (99%) rename pgtbl/disciplines/tests/{test_list_discipline.py => test_discipline_list.py} (99%) rename pgtbl/disciplines/tests/{test_update_discipline.py => test_discipline_update.py} (99%) rename pgtbl/disciplines/tests/{test_change_students_status.py => test_students_change.py} (98%) rename pgtbl/disciplines/tests/{test_insert_students.py => test_students_insert.py} (99%) rename pgtbl/disciplines/tests/{test_remove_students.py => test_students_remove.py} (99%) diff --git a/pgtbl/disciplines/tests/test_create_discipline.py b/pgtbl/disciplines/tests/test_discipline_create.py similarity index 99% rename from pgtbl/disciplines/tests/test_create_discipline.py rename to pgtbl/disciplines/tests/test_discipline_create.py index f39219d..e7eb5a2 100644 --- a/pgtbl/disciplines/tests/test_create_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_create.py @@ -8,7 +8,7 @@ User = get_user_model() -class CreateDisciplineTestCase(TestCase): +class DisciplineCreateTestCase(TestCase): """ Test to create a new discipline by teacher. """ diff --git a/pgtbl/disciplines/tests/test_delete_discipline.py b/pgtbl/disciplines/tests/test_discipline_delete.py similarity index 98% rename from pgtbl/disciplines/tests/test_delete_discipline.py rename to pgtbl/disciplines/tests/test_discipline_delete.py index 7d33094..35862ea 100644 --- a/pgtbl/disciplines/tests/test_delete_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_delete.py @@ -7,7 +7,7 @@ User = get_user_model() -class DeleteDisciplineTestCase(TestCase): +class DisciplineDeleteTestCase(TestCase): """ Test to delete a disciplina. """ diff --git a/pgtbl/disciplines/tests/test_show_discipline.py b/pgtbl/disciplines/tests/test_discipline_detail.py similarity index 96% rename from pgtbl/disciplines/tests/test_show_discipline.py rename to pgtbl/disciplines/tests/test_discipline_detail.py index eae28e6..97f9b9e 100644 --- a/pgtbl/disciplines/tests/test_show_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_detail.py @@ -4,13 +4,13 @@ from disciplines.models import Discipline from model_mommy import mommy from core.test_utils import ( - check_messages, list_transform, user_factory + check_messages, user_factory ) User = get_user_model() -class ShowDisciplineTestCase(TestCase): +class DisciplineDetailTestCase(TestCase): """ Tests to view disciplines details. """ diff --git a/pgtbl/disciplines/tests/test_enter_discipline.py b/pgtbl/disciplines/tests/test_discipline_enter.py similarity index 99% rename from pgtbl/disciplines/tests/test_enter_discipline.py rename to pgtbl/disciplines/tests/test_discipline_enter.py index 3b77f1e..4318902 100644 --- a/pgtbl/disciplines/tests/test_enter_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_enter.py @@ -10,7 +10,7 @@ User = get_user_model() -class EnterDisciplineTestCase(TestCase): +class DisciplineEnterTestCase(TestCase): """ Tests to enter in discipline. """ diff --git a/pgtbl/disciplines/tests/test_list_discipline.py b/pgtbl/disciplines/tests/test_discipline_list.py similarity index 99% rename from pgtbl/disciplines/tests/test_list_discipline.py rename to pgtbl/disciplines/tests/test_discipline_list.py index 0855a10..d1b8dd4 100644 --- a/pgtbl/disciplines/tests/test_list_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_list.py @@ -10,7 +10,7 @@ User = get_user_model() -class ListDisciplineTestCase(TestCase): +class DisciplineListTestCase(TestCase): """ Tests to view all disciplines and search or filter discipline. """ diff --git a/pgtbl/disciplines/tests/test_update_discipline.py b/pgtbl/disciplines/tests/test_discipline_update.py similarity index 99% rename from pgtbl/disciplines/tests/test_update_discipline.py rename to pgtbl/disciplines/tests/test_discipline_update.py index 15b5979..9f1f341 100644 --- a/pgtbl/disciplines/tests/test_update_discipline.py +++ b/pgtbl/disciplines/tests/test_discipline_update.py @@ -8,7 +8,7 @@ User = get_user_model() -class UpdateDisciplineTestCase(TestCase): +class DisciplineUpdateTestCase(TestCase): """ Test to update discipline by teacher. """ diff --git a/pgtbl/disciplines/tests/test_change_students_status.py b/pgtbl/disciplines/tests/test_students_change.py similarity index 98% rename from pgtbl/disciplines/tests/test_change_students_status.py rename to pgtbl/disciplines/tests/test_students_change.py index 430d625..5563573 100644 --- a/pgtbl/disciplines/tests/test_change_students_status.py +++ b/pgtbl/disciplines/tests/test_students_change.py @@ -4,13 +4,13 @@ from disciplines.models import Discipline from model_mommy import mommy from core.test_utils import ( - list_transform, check_messages, user_factory + check_messages, user_factory ) User = get_user_model() -class ChangeStudentTestCase(TestCase): +class StudentChangeTestCase(TestCase): """ Tests to change student to monitor or monitor to student. """ diff --git a/pgtbl/disciplines/tests/test_insert_students.py b/pgtbl/disciplines/tests/test_students_insert.py similarity index 99% rename from pgtbl/disciplines/tests/test_insert_students.py rename to pgtbl/disciplines/tests/test_students_insert.py index 49d6caa..400ae8c 100644 --- a/pgtbl/disciplines/tests/test_insert_students.py +++ b/pgtbl/disciplines/tests/test_students_insert.py @@ -10,9 +10,9 @@ User = get_user_model() -class ListUsersTestCase(TestCase): +class StudentInsertTestCase(TestCase): """ - Test case to list all available users that can be inserted into discipline + Test case to insert students into discipline """ def setUp(self): diff --git a/pgtbl/disciplines/tests/test_students_list.py b/pgtbl/disciplines/tests/test_students_list.py index dbbac45..196313b 100644 --- a/pgtbl/disciplines/tests/test_students_list.py +++ b/pgtbl/disciplines/tests/test_students_list.py @@ -10,7 +10,7 @@ User = get_user_model() -class ListDisciplineTestCase(TestCase): +class StudentsListTestCase(TestCase): """ Tests to view all students and monitors from discipline. """ diff --git a/pgtbl/disciplines/tests/test_remove_students.py b/pgtbl/disciplines/tests/test_students_remove.py similarity index 99% rename from pgtbl/disciplines/tests/test_remove_students.py rename to pgtbl/disciplines/tests/test_students_remove.py index e0416c6..26fb6d3 100644 --- a/pgtbl/disciplines/tests/test_remove_students.py +++ b/pgtbl/disciplines/tests/test_students_remove.py @@ -10,7 +10,7 @@ User = get_user_model() -class RemoveStudentsTestCase(TestCase): +class StudentsRemoveTestCase(TestCase): """ Test to remove students or monitors from discipline. """ From 6d0a25d87c0ec75a18933ebd1c810c029c568651 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 22:12:12 -0300 Subject: [PATCH 09/56] Refactoring discipline views --- pgtbl/disciplines/views.py | 841 ------------------ pgtbl/disciplines/views/__init__.py | 12 + .../views/discipline_close_view.py | 40 + .../views/discipline_create_view.py | 55 ++ .../views/discipline_delete_view.py | 35 + .../views/discipline_detail_view.py | 19 + .../views/discipline_enter_view.py | 126 +++ .../disciplines/views/discipline_list_view.py | 53 ++ .../views/discipline_update_view.py | 59 ++ .../disciplines/views/student_change_view.py | 137 +++ .../disciplines/views/student_insert_view.py | 126 +++ pgtbl/disciplines/views/student_list_view.py | 77 ++ .../disciplines/views/student_remove_view.py | 109 +++ pgtbl/disciplines/views/users_list_view.py | 91 ++ 14 files changed, 939 insertions(+), 841 deletions(-) delete mode 100644 pgtbl/disciplines/views.py create mode 100644 pgtbl/disciplines/views/__init__.py create mode 100644 pgtbl/disciplines/views/discipline_close_view.py create mode 100644 pgtbl/disciplines/views/discipline_create_view.py create mode 100644 pgtbl/disciplines/views/discipline_delete_view.py create mode 100644 pgtbl/disciplines/views/discipline_detail_view.py create mode 100644 pgtbl/disciplines/views/discipline_enter_view.py create mode 100644 pgtbl/disciplines/views/discipline_list_view.py create mode 100644 pgtbl/disciplines/views/discipline_update_view.py create mode 100644 pgtbl/disciplines/views/student_change_view.py create mode 100644 pgtbl/disciplines/views/student_insert_view.py create mode 100644 pgtbl/disciplines/views/student_list_view.py create mode 100644 pgtbl/disciplines/views/student_remove_view.py create mode 100644 pgtbl/disciplines/views/users_list_view.py diff --git a/pgtbl/disciplines/views.py b/pgtbl/disciplines/views.py deleted file mode 100644 index afc6ecc..0000000 --- a/pgtbl/disciplines/views.py +++ /dev/null @@ -1,841 +0,0 @@ -# Django app -from django.views.generic import ( - CreateView, UpdateView, DeleteView, DetailView, - ListView, FormView -) - -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import get_object_or_404, redirect -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib.auth import get_user_model -from django.utils.text import slugify -from django.contrib import messages -from django.db.models import Q - -# Core app -from core.permissions import ModelPermissionMixin, PermissionMixin -from core.generics import ObjectRedirectView -from core.utils import order - -# Discipline app -from .forms import DisciplineForm, DisciplineUpdateForm, DisciplineEnterForm -from .models import Discipline - -# Get the custom user from settings -User = get_user_model() - - -class DisciplineCreateView(LoginRequiredMixin, - ModelPermissionMixin, - CreateView): - """ - View to create a new discipline. - """ - - model = Discipline - template_name = 'disciplines/form.html' - form_class = DisciplineForm - success_url = reverse_lazy('accounts:profile') - - # Permissions - failure_redirect_path = reverse_lazy('accounts:profile') - permissions_required = [ - 'create_discipline' - ] - - def form_valid(self, form): - """ - Receive the form already validated to create a discipline. - """ - - # Specifies who is the creator of the discipline - form.instance.teacher = self.request.user - # Save the instance to slugify - form.save() - - # Autocomplete slug url with id-title-classroom - form.instance.slug = slugify( - str(form.instance.id) + - "-" + - form.instance.title + - "-" + - form.instance.classroom - ) - - # Save slug - form.save() - - messages.success(self.request, _('Discipline created successfully.')) - - # Redirect to success url - return super(DisciplineCreateView, self).form_valid(form) - - -class DisciplineUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a specific discipline. - """ - - model = Discipline - template_name = 'disciplines/form.html' - form_class = DisciplineUpdateForm - success_url = reverse_lazy('accounts:profile') - - # Permissions - failure_redirect_path = reverse_lazy('accounts:profile') - permissions_required = [ - 'change_own_discipline' - ] - - def form_valid(self, form): - """ - Receive the form already validated. - """ - - # Autocomplete slug url with id-title-classroom - form.instance.slug = slugify( - str(form.instance.id) + - "-" + - form.instance.title + - "-" + - form.instance.classroom - ) - - discipline = Discipline.objects.get(slug=self.kwargs.get('slug', '')) - - modify_student_limit = ( - discipline.students_limit < form.instance.students_limit - ) - - if modify_student_limit and discipline.is_closed: - form.instance.is_closed = False - - form.save() - - messages.success(self.request, _("Discipline updated successfully.")) - - # Redirect to success_url. - return super(DisciplineUpdateView, self).form_valid(form) - - -class DisciplineDeleteView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific discipline. - """ - - model = Discipline - success_url = reverse_lazy('accounts:profile') - - # Permissions - failure_redirect_path = reverse_lazy('accounts:profile') - permissions_required = [ - 'change_own_discipline' - ] - - def get_success_url(self): - """ - Redirect to success_url and show a message. - """ - - messages.success(self.request, _("Discipline deleted successfully.")) - - # Redirect to success_url - return super(DisciplineDeleteView, self).get_success_url() - - -class DisciplineListView(LoginRequiredMixin, ListView): - """ - View to search a discipline and enter it. - """ - - template_name = 'disciplines/list.html' - paginate_by = 10 - context_object_name = 'disciplines' - - def get_context_data(self, **kwargs): - """ - Insert a form inside discipline list. - """ - - context = super(DisciplineListView, self).get_context_data(**kwargs) - context['form'] = DisciplineEnterForm() - return context - - def get_queryset(self): - """ - Get the discipline queryset from model database. - """ - - user = self.request.user - - # Disciplines available for user - queryset = Discipline.objects.available(user) - - queryset = order(self, queryset) - - queryset = self.search_disciplines(queryset) - - return queryset - - def search_disciplines(self, disciplines): - """ - Search from disciplines a specific discipline. - """ - - # From url after search get the ?q_info=... - query = self.request.GET.get("q_info") - if query: - disciplines = Discipline.objects.search(query) - - return disciplines - - -class DisciplineEnterView(LoginRequiredMixin, FormView): - """ - Insert students or monitors inside discipline. - """ - - form_class = DisciplineEnterForm - success_url = reverse_lazy('accounts:profile') - template_name = 'disciplines/list.html' - - def form_valid(self, form): - """ - Form to insert students and monitors in the discipline. - """ - - success = self.enter_discipline(form) - - if success: - # Redirect to success_url - return super(DisciplineEnterView, self).form_valid(form) - - # Redirect to same page with error. - redirect_url = reverse_lazy('disciplines:search') - - return redirect(redirect_url) - - def enter_discipline(self, form): - """ - Verify if the password is correct and insert user in the discipline. - """ - - try: - discipline = Discipline.objects.get( - Q(password=form.cleaned_data['password']), - Q(slug=self.kwargs.get('slug', '')) - ) - except Exception: - messages.error( - self.request, - _("Incorrect Password.") - ) - - return False - - if discipline.is_closed: - messages.error( - self.request, - _("Discipline is closed.") - ) - - return False - - if self.request.user.is_teacher: - success = self.insert_monitor(discipline) - else: - success = self.insert_student(discipline) - - if success: - messages.success( - self.request, - _("You have been entered into the discipline: {0}" - .format(discipline.title)) - ) - - return True - - return False - - def insert_monitor(self, discipline): - """ - If user is a teacher, he will have all permission of monitor - If monitor number is bigger than monitors limit, can't enter. - """ - - if discipline.monitors.count() >= discipline.monitors_limit: - messages.error( - self.request, - _("There are no more vacancies to monitor") - ) - - return False - - if self.request.user.id == discipline.teacher.id: - messages.error( - self.request, - _("You can't get into your own discipline.") - ) - - return False - - discipline.monitors.add(self.request.user) - - return True - - def insert_student(self, discipline): - """ - If user is a student, he will have all permission of student - If students number is bigger than student limit of discipline, close it - """ - - if discipline.students.count() >= discipline.students_limit: - if not discipline.is_closed: - discipline.is_closed = True - discipline.save() - - messages.error( - self.request, - _("Crowded discipline.") - ) - - return False - - discipline.students.add(self.request.user) - - return True - - -class DisciplineDetailView(LoginRequiredMixin, - PermissionMixin, - DetailView): - """ - View to show a specific discipline. - """ - - model = Discipline - template_name = 'disciplines/details.html' - permissions_required = [ - 'show_discipline_permission' - ] - - -class DisciplineCloseView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - - model = Discipline - template_name = 'disciplines/details.html' - permissions_required = [ - 'show_discipline_permission', - 'change_own_discipline' - ] - - def delete(self, request, *args, **kwargs): - """ - Close or open discipline. - """ - - discipline = self.get_object() - - redirect_url = reverse_lazy( - 'disciplines:details', - kwargs={'slug': discipline.slug} - ) - - if discipline.is_closed: - discipline.is_closed = False - else: - discipline.is_closed = True - - discipline.save() - - return redirect(redirect_url) - - -class StudentListView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Insert, delete and list all students from specific discipline. - """ - - template_name = 'disciplines/students.html' - paginate_by = 12 - context_object_name = 'students' - permissions_required = [ - 'show_discipline_students_permission' - ] - - def get_queryset(self): - """ - List all students and monitors from discipline. - """ - - self.discipline = self.get_discipline() - - students = self.discipline.students.all() - monitors = self.discipline.monitors.all() - - # Insert monitors and students into one queryset - queryset = [] - for student in students: - queryset.append(student) - - for monitor in monitors: - queryset.append(monitor) - - queryset = self.students_filter(queryset) - - return queryset - - def get_discipline(self): - """ - Get the specific discipline. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert discipline instance into student list. - """ - - context = super(StudentListView, self).get_context_data(**kwargs) - context['discipline'] = self.discipline - return context - - def students_filter(self, queryset): - """ - Filter by monitor or students - """ - - filtered = self.request.GET.get('filter') - if filtered == 'students': - queryset = self.discipline.students.all() - elif filtered == 'monitors': - queryset = self.discipline.monitors.all() - - return queryset - - -class StudentRemoveView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - Remove student from discipline. - """ - - template_name = 'disciplines/students.html' - permissions_required = [ - 'show_discipline_permission' - ] - - def get_object(self): - """ - Get discipline by url slug - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def delete(self, request, *args, **kwargs): - """ - Redirect to success url after remove the specific student - from discipline. - """ - - user = get_object_or_404( - User, - pk=self.kwargs.get('pk', '') - ) - - discipline = self.get_object() - - is_logged_user = (self.request.user.id == user.id) - is_teacher = (self.request.user.id == discipline.teacher.id) - - if is_logged_user or is_teacher: - success_url = self.remove_from_discipline(user, is_teacher) - return redirect(success_url) - - redirect_url = reverse_lazy( - 'disciplines:students', - kwargs={'slug': discipline.slug} - ) - - messages.error( - self.request, - _("You can't remove {0} from {1}" - .format(user.get_short_name(), discipline.title)) - ) - - return redirect(redirect_url) - - def remove_from_discipline(self, user, is_teacher=True): - """ - Remove user from discipline. - """ - - discipline = self.get_object() - - if user in discipline.students.all(): - discipline.students.remove(user) - - if discipline.is_closed: - discipline.is_closed = False - discipline.save() - else: - discipline.monitors.remove(user) - - if is_teacher: - messages.success( - self.request, - _("You have removed {0} from {1}" - .format(user.get_short_name(), discipline.title)) - ) - - success_url = reverse_lazy( - 'disciplines:students', - kwargs={'slug': discipline.slug} - ) - else: - messages.success( - self.request, - _("You left the discipline {0}" - .format(discipline.title)) - ) - - success_url = reverse_lazy('accounts:profile') - - return success_url - - -class UsersListView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - List of all user to insert into discipline, can search user by name, - username, or email - """ - - template_name = 'disciplines/users.html' - context_object_name = 'users' - ordering = 'name' - paginate_by = 12 - permissions_required = [ - 'change_own_discipline' - ] - - def get_context_data(self, **kwargs): - """ - Insert form into list view. - """ - - context = super(UsersListView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - return context - - def get_discipline(self): - """ - Get the specific discipline. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_queryset(self, **kwargs): - """ - Insert only available users, can't insert discipline teacher and users - that are inside the discipline. - """ - - discipline = self.get_discipline() - queryset = [] - - users = User.objects.all() - - students = [] - for student in discipline.students.all(): - students.append(student) - - for monitor in discipline.monitors.all(): - students.append(monitor) - - for user in users: - if user not in students and user != discipline.teacher: - queryset.append(user) - - queryset = self.search(queryset) - - return queryset - - def search(self, users): - """ - Search a specific user to insert into the discipline. - """ - - # From url after search get the ?q_info=... - query = self.request.GET.get("q_info") - if query: - users = User.objects.filter( - Q(name__icontains=query) | - Q(username__icontains=query) | - Q(email__icontains=query) - ) - - return users - - -class StudentInsertView(LoginRequiredMixin, - PermissionMixin, - ObjectRedirectView): - """ - Insert a student or monitor inside discipline by teacher. - """ - - template_name = 'disciplines/users.html' - permissions_required = [ - 'change_own_discipline' - ] - - def get_object(self): - """ - Get discipline by url slug - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_success_url(self): - """ - Create a success url to redirect. - """ - - discipline = self.get_object() - - success_url = reverse_lazy( - 'disciplines:users', - kwargs={'slug': discipline.slug} - ) - - return success_url - - def action(self, request, *args, **kwargs): - """ - Insert a user into discipline. - """ - - user = get_object_or_404( - User, - pk=self.kwargs.get('pk', '') - ) - - discipline = self.get_object() - - if user.is_teacher: - success = self.insert_monitor(user, discipline) - else: - success = self.insert_student(user, discipline) - - if success: - messages.success( - self.request, - _("{0} was inserted in the discipline: {1}" - .format(user.get_short_name(), discipline.title)) - ) - - return redirect(self.get_success_url()) - - def insert_monitor(self, user, discipline): - """ - If user is a teacher, he will have all permission of monitor - If monitor number is bigger than monitors limit, can't enter. - """ - - if discipline.monitors.count() >= discipline.monitors_limit: - messages.error( - self.request, - _("There are no more vacancies to monitor") - ) - - return False - - if user == discipline.teacher: - messages.error( - self.request, - _("You can't get into your own discipline.") - ) - - return False - - discipline.monitors.add(user) - - return True - - def insert_student(self, user, discipline): - """ - If user is a student, he will have all permission of student - If students number is bigger than student limit of discipline, close it - """ - - if discipline.students.count() >= discipline.students_limit: - if not discipline.is_closed: - discipline.is_closed = True - discipline.save() - - messages.error( - self.request, - _("Crowded discipline.") - ) - - return False - - discipline.students.add(user) - - return True - - -class StudentChangeView(LoginRequiredMixin, - PermissionMixin, - ObjectRedirectView): - """ - Change student to monitor or monitor to student if the monitor is no a - teacher. - """ - - template_name = 'disciplines/students.html' - permissions_required = [ - 'change_own_discipline' - ] - - def get_object(self): - """ - Get discipline by url slug - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_success_url(self): - """ - Create a success url to redirect. - """ - - discipline = self.get_object() - - success_url = reverse_lazy( - 'disciplines:students', - kwargs={'slug': discipline.slug} - ) - - return success_url - - def action(self, request, *args, **kwargs): - """ - Insert a user into discipline. - """ - - user = get_object_or_404( - User, - pk=self.kwargs.get('pk', '') - ) - - discipline = self.get_object() - - success = self.change_user(user, discipline) - - if success: - messages.success(self.request, _("Successful modification")) - - return redirect(self.get_success_url()) - - def change_user(self, user, discipline): - """ - Change user to monitor or student. - """ - - if user.is_teacher: - messages.error( - self.request, - _("You can't turn a teacher into a student.") - ) - - return False - - if user in discipline.students.all(): - exceeded = self.monitor_limit_exceeded(discipline) - - if not exceeded: - discipline.students.remove(user) - discipline.monitors.add(user) - else: - return False - else: - exceeded = self.student_limit_exceeded(discipline) - - if not exceeded: - discipline.monitors.remove(user) - discipline.students.add(user) - else: - return False - - return True - - def student_limit_exceeded(self, discipline): - """ - Verify if student limit exceeded. - """ - - if discipline.students.count() >= discipline.students_limit: - - messages.error( - self.request, - _("Student limit exceeded.") - ) - - return True - - return False - - def monitor_limit_exceeded(self, discipline): - """ - Verify if monitor limit exceeded. - """ - - if discipline.monitors.count() >= discipline.monitors_limit: - - messages.error( - self.request, - _("Monitor limit exceeded.") - ) - - return True - - return False diff --git a/pgtbl/disciplines/views/__init__.py b/pgtbl/disciplines/views/__init__.py new file mode 100644 index 0000000..74968a6 --- /dev/null +++ b/pgtbl/disciplines/views/__init__.py @@ -0,0 +1,12 @@ +from .discipline_close_view import DisciplineCloseView +from .discipline_create_view import DisciplineCreateView +from .discipline_delete_view import DisciplineDeleteView +from .discipline_detail_view import DisciplineDetailView +from .discipline_enter_view import DisciplineEnterView +from .discipline_list_view import DisciplineListView +from .discipline_update_view import DisciplineUpdateView +from .student_change_view import StudentChangeView +from .student_insert_view import StudentInsertView +from .student_list_view import StudentListView +from .student_remove_view import StudentRemoveView +from .users_list_view import UsersListView diff --git a/pgtbl/disciplines/views/discipline_close_view.py b/pgtbl/disciplines/views/discipline_close_view.py new file mode 100644 index 0000000..b61f9bd --- /dev/null +++ b/pgtbl/disciplines/views/discipline_close_view.py @@ -0,0 +1,40 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.core.urlresolvers import reverse_lazy +from django.views.generic import DeleteView +from django.shortcuts import redirect + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + + +class DisciplineCloseView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + + model = Discipline + template_name = 'disciplines/details.html' + permissions_required = [ + 'show_discipline_permission', + 'change_own_discipline' + ] + + def delete(self, request, *args, **kwargs): + """ + Close or open discipline. + """ + + discipline = self.get_object() + + redirect_url = reverse_lazy( + 'disciplines:details', + kwargs={'slug': discipline.slug} + ) + + if discipline.is_closed: + discipline.is_closed = False + else: + discipline.is_closed = True + + discipline.save() + + return redirect(redirect_url) diff --git a/pgtbl/disciplines/views/discipline_create_view.py b/pgtbl/disciplines/views/discipline_create_view.py new file mode 100644 index 0000000..4033759 --- /dev/null +++ b/pgtbl/disciplines/views/discipline_create_view.py @@ -0,0 +1,55 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import CreateView +from django.utils.text import slugify +from django.contrib import messages +from core.permissions import ModelPermissionMixin +from disciplines.forms import DisciplineForm +from disciplines.models import Discipline + + +class DisciplineCreateView(LoginRequiredMixin, + ModelPermissionMixin, + CreateView): + """ + View to create a new discipline. + """ + + model = Discipline + template_name = 'disciplines/form.html' + form_class = DisciplineForm + success_url = reverse_lazy('accounts:profile') + + # Permissions + failure_redirect_path = reverse_lazy('accounts:profile') + permissions_required = [ + 'create_discipline' + ] + + def form_valid(self, form): + """ + Receive the form already validated to create a discipline. + """ + + # Specifies who is the creator of the discipline + form.instance.teacher = self.request.user + # Save the instance to slugify + form.save() + + # Autocomplete slug url with id-title-classroom + form.instance.slug = slugify( + str(form.instance.id) + + "-" + + form.instance.title + + "-" + + form.instance.classroom + ) + + # Save slug + form.save() + + messages.success(self.request, _('Discipline created successfully.')) + + # Redirect to success url + return super(DisciplineCreateView, self).form_valid(form) diff --git a/pgtbl/disciplines/views/discipline_delete_view.py b/pgtbl/disciplines/views/discipline_delete_view.py new file mode 100644 index 0000000..12333e0 --- /dev/null +++ b/pgtbl/disciplines/views/discipline_delete_view.py @@ -0,0 +1,35 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import DeleteView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + + +class DisciplineDeleteView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific discipline. + """ + + model = Discipline + success_url = reverse_lazy('accounts:profile') + + # Permissions + failure_redirect_path = reverse_lazy('accounts:profile') + permissions_required = [ + 'change_own_discipline' + ] + + def get_success_url(self): + """ + Redirect to success_url and show a message. + """ + + messages.success(self.request, _("Discipline deleted successfully.")) + + # Redirect to success_url + return super(DisciplineDeleteView, self).get_success_url() diff --git a/pgtbl/disciplines/views/discipline_detail_view.py b/pgtbl/disciplines/views/discipline_detail_view.py new file mode 100644 index 0000000..ade46e0 --- /dev/null +++ b/pgtbl/disciplines/views/discipline_detail_view.py @@ -0,0 +1,19 @@ +from django.views.generic import DetailView +from django.contrib.auth.mixins import LoginRequiredMixin + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + + +class DisciplineDetailView(LoginRequiredMixin, + PermissionMixin, + DetailView): + """ + View to show a specific discipline. + """ + + model = Discipline + template_name = 'disciplines/details.html' + permissions_required = [ + 'show_discipline_permission' + ] diff --git a/pgtbl/disciplines/views/discipline_enter_view.py b/pgtbl/disciplines/views/discipline_enter_view.py new file mode 100644 index 0000000..97fadd0 --- /dev/null +++ b/pgtbl/disciplines/views/discipline_enter_view.py @@ -0,0 +1,126 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import FormView +from django.shortcuts import redirect +from django.contrib import messages +from django.db.models import Q + +from disciplines.forms import DisciplineEnterForm +from disciplines.models import Discipline + + +class DisciplineEnterView(LoginRequiredMixin, FormView): + """ + Insert students or monitors inside discipline. + """ + + form_class = DisciplineEnterForm + success_url = reverse_lazy('accounts:profile') + template_name = 'disciplines/list.html' + + def form_valid(self, form): + """ + Form to insert students and monitors in the discipline. + """ + + success = self.enter_discipline(form) + + if success: + # Redirect to success_url + return super(DisciplineEnterView, self).form_valid(form) + + # Redirect to same page with error. + redirect_url = reverse_lazy('disciplines:search') + + return redirect(redirect_url) + + def enter_discipline(self, form): + """ + Verify if the password is correct and insert user in the discipline. + """ + + try: + discipline = Discipline.objects.get( + Q(password=form.cleaned_data['password']), + Q(slug=self.kwargs.get('slug', '')) + ) + except Exception: + messages.error( + self.request, + _("Incorrect Password.") + ) + + return False + + if discipline.is_closed: + messages.error( + self.request, + _("Discipline is closed.") + ) + + return False + + if self.request.user.is_teacher: + success = self.insert_monitor(discipline) + else: + success = self.insert_student(discipline) + + if success: + messages.success( + self.request, + _("You have been entered into the discipline: {0}" + .format(discipline.title)) + ) + + return True + + return False + + def insert_monitor(self, discipline): + """ + If user is a teacher, he will have all permission of monitor + If monitor number is bigger than monitors limit, can't enter. + """ + + if discipline.monitors.count() >= discipline.monitors_limit: + messages.error( + self.request, + _("There are no more vacancies to monitor") + ) + + return False + + if self.request.user.id == discipline.teacher.id: + messages.error( + self.request, + _("You can't get into your own discipline.") + ) + + return False + + discipline.monitors.add(self.request.user) + + return True + + def insert_student(self, discipline): + """ + If user is a student, he will have all permission of student + If students number is bigger than student limit of discipline, close it + """ + + if discipline.students.count() >= discipline.students_limit: + if not discipline.is_closed: + discipline.is_closed = True + discipline.save() + + messages.error( + self.request, + _("Crowded discipline.") + ) + + return False + + discipline.students.add(self.request.user) + + return True diff --git a/pgtbl/disciplines/views/discipline_list_view.py b/pgtbl/disciplines/views/discipline_list_view.py new file mode 100644 index 0000000..0a04cbe --- /dev/null +++ b/pgtbl/disciplines/views/discipline_list_view.py @@ -0,0 +1,53 @@ +from django.views.generic import ListView +from django.contrib.auth.mixins import LoginRequiredMixin + +from core.utils import order +from disciplines.models import Discipline +from disciplines.forms import DisciplineEnterForm + + +class DisciplineListView(LoginRequiredMixin, ListView): + """ + View to search a discipline and enter it. + """ + + template_name = 'disciplines/list.html' + paginate_by = 10 + context_object_name = 'disciplines' + + def get_context_data(self, **kwargs): + """ + Insert a form inside discipline list. + """ + + context = super(DisciplineListView, self).get_context_data(**kwargs) + context['form'] = DisciplineEnterForm() + return context + + def get_queryset(self): + """ + Get the discipline queryset from model database. + """ + + user = self.request.user + + # Disciplines available for user + queryset = Discipline.objects.available(user) + + queryset = order(self, queryset) + + queryset = self.search_disciplines(queryset) + + return queryset + + def search_disciplines(self, disciplines): + """ + Search from disciplines a specific discipline. + """ + + # From url after search get the ?q_info=... + query = self.request.GET.get("q_info") + if query: + disciplines = Discipline.objects.search(query) + + return disciplines diff --git a/pgtbl/disciplines/views/discipline_update_view.py b/pgtbl/disciplines/views/discipline_update_view.py new file mode 100644 index 0000000..7da0cd4 --- /dev/null +++ b/pgtbl/disciplines/views/discipline_update_view.py @@ -0,0 +1,59 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import UpdateView +from django.utils.text import slugify +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.forms import DisciplineUpdateForm +from disciplines.models import Discipline + + +class DisciplineUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a specific discipline. + """ + + model = Discipline + template_name = 'disciplines/form.html' + form_class = DisciplineUpdateForm + success_url = reverse_lazy('accounts:profile') + + # Permissions + failure_redirect_path = reverse_lazy('accounts:profile') + permissions_required = [ + 'change_own_discipline' + ] + + def form_valid(self, form): + """ + Receive the form already validated. + """ + + # Autocomplete slug url with id-title-classroom + form.instance.slug = slugify( + str(form.instance.id) + + "-" + + form.instance.title + + "-" + + form.instance.classroom + ) + + discipline = Discipline.objects.get(slug=self.kwargs.get('slug', '')) + + modify_student_limit = ( + discipline.students_limit < form.instance.students_limit + ) + + if modify_student_limit and discipline.is_closed: + form.instance.is_closed = False + + form.save() + + messages.success(self.request, _("Discipline updated successfully.")) + + # Redirect to success_url. + return super(DisciplineUpdateView, self).form_valid(form) diff --git a/pgtbl/disciplines/views/student_change_view.py b/pgtbl/disciplines/views/student_change_view.py new file mode 100644 index 0000000..0412c2f --- /dev/null +++ b/pgtbl/disciplines/views/student_change_view.py @@ -0,0 +1,137 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages + +# Core app +from core.permissions import PermissionMixin +from core.generics import ObjectRedirectView +from disciplines.models import Discipline + +# Get the custom user from settings +User = get_user_model() + + +class StudentChangeView(LoginRequiredMixin, + PermissionMixin, + ObjectRedirectView): + """ + Change student to monitor or monitor to student if the monitor is no a + teacher. + """ + + template_name = 'disciplines/students.html' + permissions_required = [ + 'change_own_discipline' + ] + + def get_object(self): + """ + Get discipline by url slug + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_success_url(self): + """ + Create a success url to redirect. + """ + + discipline = self.get_object() + + success_url = reverse_lazy( + 'disciplines:students', + kwargs={'slug': discipline.slug} + ) + + return success_url + + def action(self, request, *args, **kwargs): + """ + Insert a user into discipline. + """ + + user = get_object_or_404( + User, + pk=self.kwargs.get('pk', '') + ) + + discipline = self.get_object() + + success = self.change_user(user, discipline) + + if success: + messages.success(self.request, _("Successful modification")) + + return redirect(self.get_success_url()) + + def change_user(self, user, discipline): + """ + Change user to monitor or student. + """ + + if user.is_teacher: + messages.error( + self.request, + _("You can't turn a teacher into a student.") + ) + + return False + + if user in discipline.students.all(): + exceeded = self.monitor_limit_exceeded(discipline) + + if not exceeded: + discipline.students.remove(user) + discipline.monitors.add(user) + else: + return False + else: + exceeded = self.student_limit_exceeded(discipline) + + if not exceeded: + discipline.monitors.remove(user) + discipline.students.add(user) + else: + return False + + return True + + def student_limit_exceeded(self, discipline): + """ + Verify if student limit exceeded. + """ + + if discipline.students.count() >= discipline.students_limit: + + messages.error( + self.request, + _("Student limit exceeded.") + ) + + return True + + return False + + def monitor_limit_exceeded(self, discipline): + """ + Verify if monitor limit exceeded. + """ + + if discipline.monitors.count() >= discipline.monitors_limit: + + messages.error( + self.request, + _("Monitor limit exceeded.") + ) + + return True + + return False diff --git a/pgtbl/disciplines/views/student_insert_view.py b/pgtbl/disciplines/views/student_insert_view.py new file mode 100644 index 0000000..7f3db7c --- /dev/null +++ b/pgtbl/disciplines/views/student_insert_view.py @@ -0,0 +1,126 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages + +from core.permissions import PermissionMixin +from core.generics import ObjectRedirectView +from disciplines.models import Discipline + +# Get the custom user from settings +User = get_user_model() + + +class StudentInsertView(LoginRequiredMixin, + PermissionMixin, + ObjectRedirectView): + """ + Insert a student or monitor inside discipline by teacher. + """ + + template_name = 'disciplines/users.html' + permissions_required = [ + 'change_own_discipline' + ] + + def get_object(self): + """ + Get discipline by url slug + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_success_url(self): + """ + Create a success url to redirect. + """ + + discipline = self.get_object() + + success_url = reverse_lazy( + 'disciplines:users', + kwargs={'slug': discipline.slug} + ) + + return success_url + + def action(self, request, *args, **kwargs): + """ + Insert a user into discipline. + """ + + user = get_object_or_404( + User, + pk=self.kwargs.get('pk', '') + ) + + discipline = self.get_object() + + if user.is_teacher: + success = self.insert_monitor(user, discipline) + else: + success = self.insert_student(user, discipline) + + if success: + messages.success( + self.request, + _("{0} was inserted in the discipline: {1}" + .format(user.get_short_name(), discipline.title)) + ) + + return redirect(self.get_success_url()) + + def insert_monitor(self, user, discipline): + """ + If user is a teacher, he will have all permission of monitor + If monitor number is bigger than monitors limit, can't enter. + """ + + if discipline.monitors.count() >= discipline.monitors_limit: + messages.error( + self.request, + _("There are no more vacancies to monitor") + ) + + return False + + if user == discipline.teacher: + messages.error( + self.request, + _("You can't get into your own discipline.") + ) + + return False + + discipline.monitors.add(user) + + return True + + def insert_student(self, user, discipline): + """ + If user is a student, he will have all permission of student + If students number is bigger than student limit of discipline, close it + """ + + if discipline.students.count() >= discipline.students_limit: + if not discipline.is_closed: + discipline.is_closed = True + discipline.save() + + messages.error( + self.request, + _("Crowded discipline.") + ) + + return False + + discipline.students.add(user) + + return True diff --git a/pgtbl/disciplines/views/student_list_view.py b/pgtbl/disciplines/views/student_list_view.py new file mode 100644 index 0000000..71dc0b0 --- /dev/null +++ b/pgtbl/disciplines/views/student_list_view.py @@ -0,0 +1,77 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404 +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + + +class StudentListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Insert, delete and list all students from specific discipline. + """ + + template_name = 'disciplines/students.html' + paginate_by = 12 + context_object_name = 'students' + permissions_required = [ + 'show_discipline_students_permission' + ] + + def get_queryset(self): + """ + List all students and monitors from discipline. + """ + + self.discipline = self.get_discipline() + + students = self.discipline.students.all() + monitors = self.discipline.monitors.all() + + # Insert monitors and students into one queryset + queryset = [] + for student in students: + queryset.append(student) + + for monitor in monitors: + queryset.append(monitor) + + queryset = self.students_filter(queryset) + + return queryset + + def get_discipline(self): + """ + Get the specific discipline. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert discipline instance into student list. + """ + + context = super(StudentListView, self).get_context_data(**kwargs) + context['discipline'] = self.discipline + return context + + def students_filter(self, queryset): + """ + Filter by monitor or students + """ + + filtered = self.request.GET.get('filter') + if filtered == 'students': + queryset = self.discipline.students.all() + elif filtered == 'monitors': + queryset = self.discipline.monitors.all() + + return queryset diff --git a/pgtbl/disciplines/views/student_remove_view.py b/pgtbl/disciplines/views/student_remove_view.py new file mode 100644 index 0000000..3a933c6 --- /dev/null +++ b/pgtbl/disciplines/views/student_remove_view.py @@ -0,0 +1,109 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.views.generic import DeleteView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + +# Get the custom user from settings +User = get_user_model() + + +class StudentRemoveView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + Remove student from discipline. + """ + + template_name = 'disciplines/students.html' + permissions_required = [ + 'show_discipline_permission' + ] + + def get_object(self): + """ + Get discipline by url slug + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def delete(self, request, *args, **kwargs): + """ + Redirect to success url after remove the specific student + from discipline. + """ + + user = get_object_or_404( + User, + pk=self.kwargs.get('pk', '') + ) + + discipline = self.get_object() + + is_logged_user = (self.request.user.id == user.id) + is_teacher = (self.request.user.id == discipline.teacher.id) + + if is_logged_user or is_teacher: + success_url = self.remove_from_discipline(user, is_teacher) + return redirect(success_url) + + redirect_url = reverse_lazy( + 'disciplines:students', + kwargs={'slug': discipline.slug} + ) + + messages.error( + self.request, + _("You can't remove {0} from {1}" + .format(user.get_short_name(), discipline.title)) + ) + + return redirect(redirect_url) + + def remove_from_discipline(self, user, is_teacher=True): + """ + Remove user from discipline. + """ + + discipline = self.get_object() + + if user in discipline.students.all(): + discipline.students.remove(user) + + if discipline.is_closed: + discipline.is_closed = False + discipline.save() + else: + discipline.monitors.remove(user) + + if is_teacher: + messages.success( + self.request, + _("You have removed {0} from {1}" + .format(user.get_short_name(), discipline.title)) + ) + + success_url = reverse_lazy( + 'disciplines:students', + kwargs={'slug': discipline.slug} + ) + else: + messages.success( + self.request, + _("You left the discipline {0}" + .format(discipline.title)) + ) + + success_url = reverse_lazy('accounts:profile') + + return success_url diff --git a/pgtbl/disciplines/views/users_list_view.py b/pgtbl/disciplines/views/users_list_view.py new file mode 100644 index 0000000..fecb34e --- /dev/null +++ b/pgtbl/disciplines/views/users_list_view.py @@ -0,0 +1,91 @@ +from django.views.generic import ListView +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404 +from django.contrib.auth import get_user_model +from django.db.models import Q + +from core.permissions import PermissionMixin +from disciplines.models import Discipline + +# Get the custom user from settings +User = get_user_model() + + +class UsersListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + List of all user to insert into discipline, can search user by name, + username, or email + """ + + template_name = 'disciplines/users.html' + context_object_name = 'users' + ordering = 'name' + paginate_by = 12 + permissions_required = [ + 'change_own_discipline' + ] + + def get_context_data(self, **kwargs): + """ + Insert form into list view. + """ + + context = super(UsersListView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + return context + + def get_discipline(self): + """ + Get the specific discipline. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_queryset(self, **kwargs): + """ + Insert only available users, can't insert discipline teacher and users + that are inside the discipline. + """ + + discipline = self.get_discipline() + queryset = [] + + users = User.objects.all() + + students = [] + for student in discipline.students.all(): + students.append(student) + + for monitor in discipline.monitors.all(): + students.append(monitor) + + for user in users: + if user not in students and user != discipline.teacher: + queryset.append(user) + + queryset = self.search(queryset) + + return queryset + + def search(self, users): + """ + Search a specific user to insert into the discipline. + """ + + # From url after search get the ?q_info=... + query = self.request.GET.get("q_info") + if query: + users = User.objects.filter( + Q(name__icontains=query) | + Q(username__icontains=query) | + Q(email__icontains=query) + ) + + return users From cb255ae260c0e0eeef2926632834c1a25af62d49 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 22:17:24 -0300 Subject: [PATCH 10/56] Reorganize discipline css --- .../static/students/css/delete.css | 32 +++++++++++++++++++ .../students.css => students/css/list.css} | 0 .../templates/disciplines/remove_student.html | 2 +- .../templates/disciplines/students.html | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 pgtbl/disciplines/static/students/css/delete.css rename pgtbl/disciplines/static/{disciplines/css/students.css => students/css/list.css} (100%) diff --git a/pgtbl/disciplines/static/students/css/delete.css b/pgtbl/disciplines/static/students/css/delete.css new file mode 100644 index 0000000..89a1655 --- /dev/null +++ b/pgtbl/disciplines/static/students/css/delete.css @@ -0,0 +1,32 @@ +.modal { + top: 40px; +} + +.modal-content { + background-color: transparent; + border-radius: 10px; +} + +.modal-header { + background-color: #263238 !important; + border-top-left-radius: 10px; + border-top-right-radius: 10px; +} + +.modal-body { + background-color: white; +} + +.modal-footer { + background-color: #263238 !important; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} + +.modal-title { + color: white; +} + +.close, .close:hover { + color: white; +} diff --git a/pgtbl/disciplines/static/disciplines/css/students.css b/pgtbl/disciplines/static/students/css/list.css similarity index 100% rename from pgtbl/disciplines/static/disciplines/css/students.css rename to pgtbl/disciplines/static/students/css/list.css diff --git a/pgtbl/disciplines/templates/disciplines/remove_student.html b/pgtbl/disciplines/templates/disciplines/remove_student.html index 9fd780d..e72f3ae 100644 --- a/pgtbl/disciplines/templates/disciplines/remove_student.html +++ b/pgtbl/disciplines/templates/disciplines/remove_student.html @@ -2,7 +2,7 @@ {% load static %} {% block css %} - + {% endblock %} diff --git a/pgtbl/disciplines/templates/disciplines/students.html b/pgtbl/disciplines/templates/disciplines/students.html index 43ec7f4..42c762b 100644 --- a/pgtbl/disciplines/templates/disciplines/students.html +++ b/pgtbl/disciplines/templates/disciplines/students.html @@ -4,7 +4,7 @@ {% block css %} - + {% endblock %} {% block breadcrumb %} From 2664eafeaa399aa41d0d9cc341a84b46824131fe Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 22:23:35 -0300 Subject: [PATCH 11/56] Refactoring discipline templates --- .../templates/{disciplines/students.html => students/list.html} | 2 +- .../{disciplines/remove_student.html => students/remove.html} | 0 .../disciplines/templates/{disciplines => students}/users.html | 2 +- pgtbl/disciplines/tests/test_students_list.py | 2 +- pgtbl/disciplines/views/student_change_view.py | 2 +- pgtbl/disciplines/views/student_insert_view.py | 2 +- pgtbl/disciplines/views/student_list_view.py | 2 +- pgtbl/disciplines/views/student_remove_view.py | 2 +- pgtbl/disciplines/views/users_list_view.py | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename pgtbl/disciplines/templates/{disciplines/students.html => students/list.html} (98%) rename pgtbl/disciplines/templates/{disciplines/remove_student.html => students/remove.html} (100%) rename pgtbl/disciplines/templates/{disciplines => students}/users.html (98%) diff --git a/pgtbl/disciplines/templates/disciplines/students.html b/pgtbl/disciplines/templates/students/list.html similarity index 98% rename from pgtbl/disciplines/templates/disciplines/students.html rename to pgtbl/disciplines/templates/students/list.html index 42c762b..25fabcf 100644 --- a/pgtbl/disciplines/templates/disciplines/students.html +++ b/pgtbl/disciplines/templates/students/list.html @@ -144,7 +144,7 @@

- {% include 'disciplines/remove_student.html' %} + {% include 'students/remove.html' %} {% empty %}

{% trans 'There is no students in this class.' %}

{% endfor %} diff --git a/pgtbl/disciplines/templates/disciplines/remove_student.html b/pgtbl/disciplines/templates/students/remove.html similarity index 100% rename from pgtbl/disciplines/templates/disciplines/remove_student.html rename to pgtbl/disciplines/templates/students/remove.html diff --git a/pgtbl/disciplines/templates/disciplines/users.html b/pgtbl/disciplines/templates/students/users.html similarity index 98% rename from pgtbl/disciplines/templates/disciplines/users.html rename to pgtbl/disciplines/templates/students/users.html index 469035b..20954a9 100644 --- a/pgtbl/disciplines/templates/disciplines/users.html +++ b/pgtbl/disciplines/templates/students/users.html @@ -1,4 +1,4 @@ -{% extends 'disciplines/students.html' %} +{% extends 'students/list.html' %} {% load static %} {% load i18n %} diff --git a/pgtbl/disciplines/tests/test_students_list.py b/pgtbl/disciplines/tests/test_students_list.py index 196313b..e75dd91 100644 --- a/pgtbl/disciplines/tests/test_students_list.py +++ b/pgtbl/disciplines/tests/test_students_list.py @@ -60,7 +60,7 @@ def test_status_code_200(self): response = self.client.get(self.url) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'disciplines/students.html') + self.assertTemplateUsed(response, 'students/list.html') def test_context(self): """ diff --git a/pgtbl/disciplines/views/student_change_view.py b/pgtbl/disciplines/views/student_change_view.py index 0412c2f..f3d4150 100644 --- a/pgtbl/disciplines/views/student_change_view.py +++ b/pgtbl/disciplines/views/student_change_view.py @@ -22,7 +22,7 @@ class StudentChangeView(LoginRequiredMixin, teacher. """ - template_name = 'disciplines/students.html' + template_name = 'students/list.html' permissions_required = [ 'change_own_discipline' ] diff --git a/pgtbl/disciplines/views/student_insert_view.py b/pgtbl/disciplines/views/student_insert_view.py index 7f3db7c..f236f31 100644 --- a/pgtbl/disciplines/views/student_insert_view.py +++ b/pgtbl/disciplines/views/student_insert_view.py @@ -20,7 +20,7 @@ class StudentInsertView(LoginRequiredMixin, Insert a student or monitor inside discipline by teacher. """ - template_name = 'disciplines/users.html' + template_name = 'students/users.html' permissions_required = [ 'change_own_discipline' ] diff --git a/pgtbl/disciplines/views/student_list_view.py b/pgtbl/disciplines/views/student_list_view.py index 71dc0b0..680566d 100644 --- a/pgtbl/disciplines/views/student_list_view.py +++ b/pgtbl/disciplines/views/student_list_view.py @@ -13,7 +13,7 @@ class StudentListView(LoginRequiredMixin, Insert, delete and list all students from specific discipline. """ - template_name = 'disciplines/students.html' + template_name = 'students/list.html' paginate_by = 12 context_object_name = 'students' permissions_required = [ diff --git a/pgtbl/disciplines/views/student_remove_view.py b/pgtbl/disciplines/views/student_remove_view.py index 3a933c6..8404ad7 100644 --- a/pgtbl/disciplines/views/student_remove_view.py +++ b/pgtbl/disciplines/views/student_remove_view.py @@ -20,7 +20,7 @@ class StudentRemoveView(LoginRequiredMixin, Remove student from discipline. """ - template_name = 'disciplines/students.html' + template_name = 'students/list.html' permissions_required = [ 'show_discipline_permission' ] diff --git a/pgtbl/disciplines/views/users_list_view.py b/pgtbl/disciplines/views/users_list_view.py index fecb34e..c8675e0 100644 --- a/pgtbl/disciplines/views/users_list_view.py +++ b/pgtbl/disciplines/views/users_list_view.py @@ -19,7 +19,7 @@ class UsersListView(LoginRequiredMixin, username, or email """ - template_name = 'disciplines/users.html' + template_name = 'students/users.html' context_object_name = 'users' ordering = 'name' paginate_by = 12 From 6454edac0d9e65a9bc2f34fb055c9efb0fb0d166 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 22:54:38 -0300 Subject: [PATCH 12/56] Refactoring groups --- pgtbl/groups/forms/__init__.py | 1 + .../{forms.py => forms/student_group_form.py} | 2 +- pgtbl/groups/models/__init__.py | 1 + pgtbl/groups/{models.py => models/group.py} | 1 - pgtbl/groups/tests/__init__.py | 0 ..._create_groups.py => test_group_create.py} | 2 +- ..._delete_groups.py => test_group_delete.py} | 2 +- ...test_list_groups.py => test_group_list.py} | 2 +- ..._update_groups.py => test_group_update.py} | 2 +- pgtbl/groups/urls.py | 16 +- pgtbl/groups/views.py | 681 ------------------ pgtbl/groups/views/__init__.py | 8 + pgtbl/groups/views/group_create_view.py | 95 +++ pgtbl/groups/views/group_delete_view.py | 68 ++ pgtbl/groups/views/group_list_view.py | 76 ++ pgtbl/groups/views/group_provide_view.py | 84 +++ pgtbl/groups/views/group_update_view.py | 88 +++ pgtbl/groups/views/student_insert_view.py | 119 +++ .../views/student_list_available_view.py | 110 +++ pgtbl/groups/views/student_remove_view.py | 110 +++ 20 files changed, 773 insertions(+), 695 deletions(-) create mode 100644 pgtbl/groups/forms/__init__.py rename pgtbl/groups/{forms.py => forms/student_group_form.py} (86%) create mode 100644 pgtbl/groups/models/__init__.py rename pgtbl/groups/{models.py => models/group.py} (99%) create mode 100644 pgtbl/groups/tests/__init__.py rename pgtbl/groups/tests/{test_create_groups.py => test_group_create.py} (99%) rename pgtbl/groups/tests/{test_delete_groups.py => test_group_delete.py} (99%) rename pgtbl/groups/tests/{test_list_groups.py => test_group_list.py} (99%) rename pgtbl/groups/tests/{test_update_groups.py => test_group_update.py} (99%) delete mode 100644 pgtbl/groups/views.py create mode 100644 pgtbl/groups/views/__init__.py create mode 100644 pgtbl/groups/views/group_create_view.py create mode 100644 pgtbl/groups/views/group_delete_view.py create mode 100644 pgtbl/groups/views/group_list_view.py create mode 100644 pgtbl/groups/views/group_provide_view.py create mode 100644 pgtbl/groups/views/group_update_view.py create mode 100644 pgtbl/groups/views/student_insert_view.py create mode 100644 pgtbl/groups/views/student_list_available_view.py create mode 100644 pgtbl/groups/views/student_remove_view.py diff --git a/pgtbl/groups/forms/__init__.py b/pgtbl/groups/forms/__init__.py new file mode 100644 index 0000000..b692466 --- /dev/null +++ b/pgtbl/groups/forms/__init__.py @@ -0,0 +1 @@ +from .student_group_form import StudentGroupForm diff --git a/pgtbl/groups/forms.py b/pgtbl/groups/forms/student_group_form.py similarity index 86% rename from pgtbl/groups/forms.py rename to pgtbl/groups/forms/student_group_form.py index 70c5d0e..1231f17 100644 --- a/pgtbl/groups/forms.py +++ b/pgtbl/groups/forms/student_group_form.py @@ -1,5 +1,5 @@ from django import forms -from .models import Group +from groups.models import Group class StudentGroupForm(forms.ModelForm): diff --git a/pgtbl/groups/models/__init__.py b/pgtbl/groups/models/__init__.py new file mode 100644 index 0000000..4700ca8 --- /dev/null +++ b/pgtbl/groups/models/__init__.py @@ -0,0 +1 @@ +from .group import Group diff --git a/pgtbl/groups/models.py b/pgtbl/groups/models/group.py similarity index 99% rename from pgtbl/groups/models.py rename to pgtbl/groups/models/group.py index c44e491..922c2af 100644 --- a/pgtbl/groups/models.py +++ b/pgtbl/groups/models/group.py @@ -2,7 +2,6 @@ from django.contrib.auth import get_user_model from django.db import models -# App imports from disciplines.models import Discipline User = get_user_model() diff --git a/pgtbl/groups/tests/__init__.py b/pgtbl/groups/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/groups/tests/test_create_groups.py b/pgtbl/groups/tests/test_group_create.py similarity index 99% rename from pgtbl/groups/tests/test_create_groups.py rename to pgtbl/groups/tests/test_group_create.py index 46540b2..9d4f297 100644 --- a/pgtbl/groups/tests/test_create_groups.py +++ b/pgtbl/groups/tests/test_group_create.py @@ -8,7 +8,7 @@ User = get_user_model() -class CreateGroupTestCase(TestCase): +class GroupCreateTestCase(TestCase): """ Test to create a new group by teacher. """ diff --git a/pgtbl/groups/tests/test_delete_groups.py b/pgtbl/groups/tests/test_group_delete.py similarity index 99% rename from pgtbl/groups/tests/test_delete_groups.py rename to pgtbl/groups/tests/test_group_delete.py index 7f803e9..56d84ac 100644 --- a/pgtbl/groups/tests/test_delete_groups.py +++ b/pgtbl/groups/tests/test_group_delete.py @@ -9,7 +9,7 @@ User = get_user_model() -class DeleteGroupTestCase(TestCase): +class GroupDeleteTestCase(TestCase): """ Test to delete a new group by teacher. """ diff --git a/pgtbl/groups/tests/test_list_groups.py b/pgtbl/groups/tests/test_group_list.py similarity index 99% rename from pgtbl/groups/tests/test_list_groups.py rename to pgtbl/groups/tests/test_group_list.py index d5fde01..b543360 100644 --- a/pgtbl/groups/tests/test_list_groups.py +++ b/pgtbl/groups/tests/test_group_list.py @@ -9,7 +9,7 @@ User = get_user_model() -class ListGroupTestCase(TestCase): +class GroupListTestCase(TestCase): """ Test to list all groups. """ diff --git a/pgtbl/groups/tests/test_update_groups.py b/pgtbl/groups/tests/test_group_update.py similarity index 99% rename from pgtbl/groups/tests/test_update_groups.py rename to pgtbl/groups/tests/test_group_update.py index d1c8a2b..3a30722 100644 --- a/pgtbl/groups/tests/test_update_groups.py +++ b/pgtbl/groups/tests/test_group_update.py @@ -9,7 +9,7 @@ User = get_user_model() -class UpdateGroupTestCase(TestCase): +class GroupUpdateTestCase(TestCase): """ Test to update a new group by teacher. """ diff --git a/pgtbl/groups/urls.py b/pgtbl/groups/urls.py index 61040e3..0b278fa 100644 --- a/pgtbl/groups/urls.py +++ b/pgtbl/groups/urls.py @@ -7,49 +7,49 @@ # / url( r'^$', - views.ListGroupView.as_view(), + views.GroupListView.as_view(), name='list' ), # add/ url( r'^add/$', - views.CreateGroupView.as_view(), + views.GroupCreateView.as_view(), name='create' ), # /edit/ url( r'^(?P[0-9]+)/edit/$', - views.UpdateGroupView.as_view(), + views.GroupUpdateView.as_view(), name='update' ), # /delete/ url( r'^(?P[0-9]+)/delete/$', - views.DeleteGroupView.as_view(), + views.GroupDeleteView.as_view(), name='delete' ), # provide/ url( r'^provide/$', - views.ProvideGroupView.as_view(), + views.GroupProvideView.as_view(), name='provide' ), # /students/ url( r'^(?P[0-9]+)/students/$', - views.ListAvailableStudentsView.as_view(), + views.StudentListAvailableView.as_view(), name='students' ), # /students//add/ url( r'^(?P[0-9]+)/students/(?P[0-9]+)/add/$', - views.InsertStudentView.as_view(), + views.StudentInsertView.as_view(), name='add-student' ), # /students//remove/ url( r'^(?P[0-9]+)/students/(?P[0-9]+)/remove/$', - views.RemoveStudentView.as_view(), + views.StudentRemoveView.as_view(), name='remove-student' ), ] diff --git a/pgtbl/groups/views.py b/pgtbl/groups/views.py deleted file mode 100644 index 43d8897..0000000 --- a/pgtbl/groups/views.py +++ /dev/null @@ -1,681 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import redirect, get_object_or_404 -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib.auth import get_user_model -from django.contrib import messages -from django.views.generic import ( - CreateView, ListView, UpdateView, DeleteView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from core.generics import ObjectRedirectView -from .models import Group -from .forms import StudentGroupForm - -# Get the custom user from settings -User = get_user_model() - - -class ListGroupView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all groups of discipline. - """ - - template_name = 'groups/list.html' - paginate_by = 5 - context_object_name = 'groups' - - # Permissions - permissions_required = [ - 'show_discipline_groups_permission' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'disciplines:details', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Take the discipline that the group belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert a form inside group list. - """ - - context = super(ListGroupView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['form'] = StudentGroupForm() - return context - - def get_queryset(self): - """ - Get the group queryset from model database. - """ - - discipline = self.get_discipline() - - groups = Group.objects.filter(discipline=discipline) - - return groups - - -class CreateGroupView(LoginRequiredMixin, - PermissionMixin, - CreateView): - """ - View to create a new group to discipline. - """ - - model = Group - template_name = 'groups/list.html' - form_class = StudentGroupForm - - # Permissions - permissions_required = [ - 'change_own_group' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'disciplines:details', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Take the discipline that the group belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Receive the form already validated to create a group. - """ - - form.instance.discipline = self.get_discipline() - - form.save() - - messages.success(self.request, _('Group created successfully.')) - - return super(CreateGroupView, self).form_valid(form) - - def form_invalid(self, form): - """ - Redirect to group list with error. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the fields correctly.") - ) - - return redirect(self.get_success_url()) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class UpdateGroupView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a specific group. - """ - - model = Group - template_name = 'groups/form.html' - context_object_name = 'group' - form_class = StudentGroupForm - - # Permissions - permissions_required = [ - 'change_own_group' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'disciplines:details', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Take the discipline that the group belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert a discipline inside group template. - """ - - context = super(UpdateGroupView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - return context - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('Group updated successfully.')) - - return super(UpdateGroupView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class DeleteGroupView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific group. - """ - - model = Group - - # Permissions - permissions_required = [ - 'change_own_group' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'disciplines:details', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Take the discipline that the group belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - messages.success(self.request, _("Group deleted successfully.")) - - return success_url - - -class ProvideGroupView(LoginRequiredMixin, - PermissionMixin, - ObjectRedirectView): - """ - Make groups available for students. - """ - - template_name = 'groups/list.html' - permissions_required = ['change_own_group'] - - def get_object(self): - """ - Get discipline by url slug. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'disciplines:details', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_success_url(self): - """ - Create a success url to redirect. - """ - - discipline = self.get_object() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - if discipline.was_group_provided: - messages.success(self.request, _("Groups available.")) - else: - messages.success(self.request, _("Groups unavailable.")) - - return success_url - - def action(self, request, *args, **kwargs): - """ - Change groups permission to available or unavailable. - """ - - discipline = self.get_object() - - if discipline.was_group_provided: - discipline.was_group_provided = False - else: - discipline.was_group_provided = True - - discipline.save() - - return redirect(self.get_success_url()) - - -class ListAvailableStudentsView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Show a list of students available to insert into groups. - """ - - template_name = 'groups/students.html' - paginate_by = 12 - context_object_name = 'students' - permissions_required = ['change_own_group'] - - def get_discipline(self): - """ - Get the specific discipline by url. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_group(self): - """ - Get the specific group by url - """ - - group = get_object_or_404( - Group, - pk=self.kwargs.get('pk', '') - ) - - return group - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'groups:list', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_queryset(self): - """ - List all available students to insert into discipline. - """ - - self.discipline = self.get_discipline() - students = self.discipline.students.all() - - students_available = [] - - for student in students: - available = self.is_available(student) - - if available is True: - students_available.append(student) - - return students_available - - def is_available(self, student): - """ - Scroll through the discipline groups and return True if it is not - in any group. - """ - - available = False - - for group in self.discipline.groups.all(): - if student in group.students.all(): - available = False - break - else: - available = True - - return available - - def get_context_data(self, **kwargs): - """ - Insert discipline and group instance into student list. - """ - - context = super(ListAvailableStudentsView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['group'] = self.get_group() - return context - - -class InsertStudentView(LoginRequiredMixin, - PermissionMixin, - ObjectRedirectView): - """ - Insert a student inside group. - """ - - template_name = 'groups/students.html' - permissions_required = ['change_own_group'] - - def get_discipline(self): - """ - Get the specific discipline by url. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_group(self): - """ - Get the specific group by url - """ - - group = get_object_or_404( - Group, - pk=self.kwargs.get('group_id', '') - ) - - return group - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'groups:list', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_success_url(self): - """ - Create a success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - def action(self, request, *args, **kwargs): - """ - Insert a student into the group action. - and redirect to success url - """ - - student = get_object_or_404( - User, - pk=self.kwargs.get('student_id', '') - ) - - self.insert(student) - - return redirect(self.get_success_url()) - - def insert(self, student): - """ - Insert student into group. - """ - - group = self.get_group() - - if group.students.count() >= group.students_limit: - - messages.error( - self.request, - _("Crowded group.") - ) - - else: - - group.students.add(student) - - messages.success( - self.request, - _("{0} was inserted in the group: {1}" - .format(student.get_short_name(), group.title)) - ) - - -class RemoveStudentView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - Remove student from groups. - """ - - template_name = 'groups/students.html' - permissions_required = ['change_own_group'] - - def get_discipline(self): - """ - Get the specific discipline by url. - """ - - discipline = get_object_or_404( - Discipline, - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_group(self): - """ - Get the specific group by url - """ - - group = get_object_or_404( - Group, - pk=self.kwargs.get('group_id', '') - ) - - return group - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'groups:list', - kwargs={'slug': self.kwargs.get('slug', '')} - ) - - return failure_redirect_path - - def get_success_url(self): - """ - Create a success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'groups:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - def delete(self, request, *args, **kwargs): - """ - Redirect to success url after remove the specific student - from group. - """ - - user = get_object_or_404( - User, - pk=self.kwargs.get('student_id', '') - ) - - self.remove_from_group(user) - - return redirect(self.get_success_url()) - - def remove_from_group(self, student): - """ - Remove specific student from group. - """ - - group = self.get_group() - - group.students.remove(student) - - messages.success( - self.request, - _("The student {0} is removed from {1}" - .format(student.get_short_name(), group.title)) - ) diff --git a/pgtbl/groups/views/__init__.py b/pgtbl/groups/views/__init__.py new file mode 100644 index 0000000..2f80f85 --- /dev/null +++ b/pgtbl/groups/views/__init__.py @@ -0,0 +1,8 @@ +from .group_create_view import GroupCreateView +from .group_delete_view import GroupDeleteView +from .group_list_view import GroupListView +from .group_provide_view import GroupProvideView +from .group_update_view import GroupUpdateView +from .student_insert_view import StudentInsertView +from .student_remove_view import StudentRemoveView +from .student_list_available_view import StudentListAvailableView diff --git a/pgtbl/groups/views/group_create_view.py b/pgtbl/groups/views/group_create_view.py new file mode 100644 index 0000000..a84b0b6 --- /dev/null +++ b/pgtbl/groups/views/group_create_view.py @@ -0,0 +1,95 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import CreateView +from django.shortcuts import redirect +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.models import Group +from groups.forms import StudentGroupForm + + +class GroupCreateView(LoginRequiredMixin, + PermissionMixin, + CreateView): + """ + View to create a new group to discipline. + """ + + model = Group + template_name = 'groups/list.html' + form_class = StudentGroupForm + + # Permissions + permissions_required = [ + 'change_own_group' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'disciplines:details', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Take the discipline that the group belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Receive the form already validated to create a group. + """ + + form.instance.discipline = self.get_discipline() + + form.save() + + messages.success(self.request, _('Group created successfully.')) + + return super(GroupCreateView, self).form_valid(form) + + def form_invalid(self, form): + """ + Redirect to group list with error. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the fields correctly.") + ) + + return redirect(self.get_success_url()) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/groups/views/group_delete_view.py b/pgtbl/groups/views/group_delete_view.py new file mode 100644 index 0000000..ae25f54 --- /dev/null +++ b/pgtbl/groups/views/group_delete_view.py @@ -0,0 +1,68 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import DeleteView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.models import Group + + +class GroupDeleteView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific group. + """ + + model = Group + + # Permissions + permissions_required = [ + 'change_own_group' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'disciplines:details', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Take the discipline that the group belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + messages.success(self.request, _("Group deleted successfully.")) + + return success_url diff --git a/pgtbl/groups/views/group_list_view.py b/pgtbl/groups/views/group_list_view.py new file mode 100644 index 0000000..9f9de01 --- /dev/null +++ b/pgtbl/groups/views/group_list_view.py @@ -0,0 +1,76 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import ListView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.models import Group +from groups.forms import StudentGroupForm + + +class GroupListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all groups of discipline. + """ + + template_name = 'groups/list.html' + paginate_by = 5 + context_object_name = 'groups' + + # Permissions + permissions_required = [ + 'show_discipline_groups_permission' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'disciplines:details', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Take the discipline that the group belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert a form inside group list. + """ + + context = super(GroupListView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['form'] = StudentGroupForm() + return context + + def get_queryset(self): + """ + Get the group queryset from model database. + """ + + discipline = self.get_discipline() + + groups = Group.objects.filter(discipline=discipline) + + return groups diff --git a/pgtbl/groups/views/group_provide_view.py b/pgtbl/groups/views/group_provide_view.py new file mode 100644 index 0000000..142406a --- /dev/null +++ b/pgtbl/groups/views/group_provide_view.py @@ -0,0 +1,84 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import redirect, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from core.generics import ObjectRedirectView + + +class GroupProvideView(LoginRequiredMixin, + PermissionMixin, + ObjectRedirectView): + """ + Make groups available for students. + """ + + template_name = 'groups/list.html' + permissions_required = ['change_own_group'] + + def get_object(self): + """ + Get discipline by url slug. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'disciplines:details', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_success_url(self): + """ + Create a success url to redirect. + """ + + discipline = self.get_object() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + if discipline.was_group_provided: + messages.success(self.request, _("Groups available.")) + else: + messages.success(self.request, _("Groups unavailable.")) + + return success_url + + def action(self, request, *args, **kwargs): + """ + Change groups permission to available or unavailable. + """ + + discipline = self.get_object() + + if discipline.was_group_provided: + discipline.was_group_provided = False + else: + discipline.was_group_provided = True + + discipline.save() + + return redirect(self.get_success_url()) diff --git a/pgtbl/groups/views/group_update_view.py b/pgtbl/groups/views/group_update_view.py new file mode 100644 index 0000000..37ea278 --- /dev/null +++ b/pgtbl/groups/views/group_update_view.py @@ -0,0 +1,88 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import UpdateView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.forms import StudentGroupForm +from groups.models import Group + + +class GroupUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a specific group. + """ + + model = Group + template_name = 'groups/form.html' + context_object_name = 'group' + form_class = StudentGroupForm + + # Permissions + permissions_required = [ + 'change_own_group' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'disciplines:details', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Take the discipline that the group belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert a discipline inside group template. + """ + + context = super(GroupUpdateView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + return context + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('Group updated successfully.')) + + return super(GroupUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/groups/views/student_insert_view.py b/pgtbl/groups/views/student_insert_view.py new file mode 100644 index 0000000..9116327 --- /dev/null +++ b/pgtbl/groups/views/student_insert_view.py @@ -0,0 +1,119 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import redirect, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from core.generics import ObjectRedirectView +from groups.models import Group + +# Get the custom user from settings +User = get_user_model() + + +class StudentInsertView(LoginRequiredMixin, + PermissionMixin, + ObjectRedirectView): + """ + Insert a student inside group. + """ + + template_name = 'groups/students.html' + permissions_required = ['change_own_group'] + + def get_discipline(self): + """ + Get the specific discipline by url. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_group(self): + """ + Get the specific group by url + """ + + group = get_object_or_404( + Group, + pk=self.kwargs.get('group_id', '') + ) + + return group + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'groups:list', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_success_url(self): + """ + Create a success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + return success_url + + def action(self, request, *args, **kwargs): + """ + Insert a student into the group action. + and redirect to success url + """ + + student = get_object_or_404( + User, + pk=self.kwargs.get('student_id', '') + ) + + self.insert(student) + + return redirect(self.get_success_url()) + + def insert(self, student): + """ + Insert student into group. + """ + + group = self.get_group() + + if group.students.count() >= group.students_limit: + + messages.error( + self.request, + _("Crowded group.") + ) + + else: + + group.students.add(student) + + messages.success( + self.request, + _("{0} was inserted in the group: {1}" + .format(student.get_short_name(), group.title)) + ) diff --git a/pgtbl/groups/views/student_list_available_view.py b/pgtbl/groups/views/student_list_available_view.py new file mode 100644 index 0000000..9281b8b --- /dev/null +++ b/pgtbl/groups/views/student_list_available_view.py @@ -0,0 +1,110 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.shortcuts import get_object_or_404 +from django.views.generic import ListView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.models import Group + + +class StudentListAvailableView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Show a list of students available to insert into groups. + """ + + template_name = 'groups/students.html' + paginate_by = 12 + context_object_name = 'students' + permissions_required = ['change_own_group'] + + def get_discipline(self): + """ + Get the specific discipline by url. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_group(self): + """ + Get the specific group by url + """ + + group = get_object_or_404( + Group, + pk=self.kwargs.get('pk', '') + ) + + return group + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'groups:list', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_queryset(self): + """ + List all available students to insert into discipline. + """ + + self.discipline = self.get_discipline() + students = self.discipline.students.all() + + students_available = [] + + for student in students: + available = self.is_available(student) + + if available is True: + students_available.append(student) + + return students_available + + def is_available(self, student): + """ + Scroll through the discipline groups and return True if it is not + in any group. + """ + + available = False + + for group in self.discipline.groups.all(): + if student in group.students.all(): + available = False + break + else: + available = True + + return available + + def get_context_data(self, **kwargs): + """ + Insert discipline and group instance into student list. + """ + + context = super(StudentListAvailableView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['group'] = self.get_group() + + return context diff --git a/pgtbl/groups/views/student_remove_view.py b/pgtbl/groups/views/student_remove_view.py new file mode 100644 index 0000000..dd15d3e --- /dev/null +++ b/pgtbl/groups/views/student_remove_view.py @@ -0,0 +1,110 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import redirect, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.views.generic import DeleteView +from django.contrib import messages + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from groups.models import Group + +# Get the custom user from settings +User = get_user_model() + + +class StudentRemoveView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + Remove student from groups. + """ + + template_name = 'groups/students.html' + permissions_required = ['change_own_group'] + + def get_discipline(self): + """ + Get the specific discipline by url. + """ + + discipline = get_object_or_404( + Discipline, + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_group(self): + """ + Get the specific group by url + """ + + group = get_object_or_404( + Group, + pk=self.kwargs.get('group_id', '') + ) + + return group + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'groups:list', + kwargs={'slug': self.kwargs.get('slug', '')} + ) + + return failure_redirect_path + + def get_success_url(self): + """ + Create a success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'groups:list', + kwargs={'slug': discipline.slug} + ) + + return success_url + + def delete(self, request, *args, **kwargs): + """ + Redirect to success url after remove the specific student + from group. + """ + + user = get_object_or_404( + User, + pk=self.kwargs.get('student_id', '') + ) + + self.remove_from_group(user) + + return redirect(self.get_success_url()) + + def remove_from_group(self, student): + """ + Remove specific student from group. + """ + + group = self.get_group() + + group.students.remove(student) + + messages.success( + self.request, + _("The student {0} is removed from {1}" + .format(student.get_short_name(), group.title)) + ) From e7524b373aff3da7eef0b137c3bb3de0341ba2a1 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 23:30:27 -0300 Subject: [PATCH 13/56] Refactoring files forms --- pgtbl/files/forms.py | 22 ---------------------- pgtbl/files/forms/__init__.py | 2 ++ pgtbl/files/forms/discipline_file_form.py | 12 ++++++++++++ pgtbl/files/forms/session_file_form.py | 12 ++++++++++++ pgtbl/files/views_discipline.py | 10 +++++----- pgtbl/files/views_sessions.py | 4 ++-- 6 files changed, 33 insertions(+), 29 deletions(-) delete mode 100644 pgtbl/files/forms.py create mode 100644 pgtbl/files/forms/__init__.py create mode 100644 pgtbl/files/forms/discipline_file_form.py create mode 100644 pgtbl/files/forms/session_file_form.py diff --git a/pgtbl/files/forms.py b/pgtbl/files/forms.py deleted file mode 100644 index 94dcc6e..0000000 --- a/pgtbl/files/forms.py +++ /dev/null @@ -1,22 +0,0 @@ -from .models import DisciplineFile, SessionFile -from django import forms - - -class FileForm(forms.ModelForm): - """ - Form to create a new file. - """ - - class Meta: - model = DisciplineFile - fields = ['title', 'extension', 'description', 'archive'] - - -class SessionFileForm(forms.ModelForm): - """ - Form to create a new file to tbl session. - """ - - class Meta: - model = SessionFile - fields = ['title', 'extension', 'description', 'archive'] diff --git a/pgtbl/files/forms/__init__.py b/pgtbl/files/forms/__init__.py new file mode 100644 index 0000000..6188edb --- /dev/null +++ b/pgtbl/files/forms/__init__.py @@ -0,0 +1,2 @@ +from .discipline_file_form import DisciplineFileForm +from .session_file_form import SessionFileForm diff --git a/pgtbl/files/forms/discipline_file_form.py b/pgtbl/files/forms/discipline_file_form.py new file mode 100644 index 0000000..e980e5b --- /dev/null +++ b/pgtbl/files/forms/discipline_file_form.py @@ -0,0 +1,12 @@ +from files.models import DisciplineFile +from django import forms + + +class DisciplineFileForm(forms.ModelForm): + """ + Form to create a new file. + """ + + class Meta: + model = DisciplineFile + fields = ['title', 'extension', 'description', 'archive'] diff --git a/pgtbl/files/forms/session_file_form.py b/pgtbl/files/forms/session_file_form.py new file mode 100644 index 0000000..33b6273 --- /dev/null +++ b/pgtbl/files/forms/session_file_form.py @@ -0,0 +1,12 @@ +from files.models import SessionFile +from django import forms + + +class SessionFileForm(forms.ModelForm): + """ + Form to create a new file to tbl session. + """ + + class Meta: + model = SessionFile + fields = ['title', 'extension', 'description', 'archive'] diff --git a/pgtbl/files/views_discipline.py b/pgtbl/files/views_discipline.py index 046b2c1..2ce1a15 100644 --- a/pgtbl/files/views_discipline.py +++ b/pgtbl/files/views_discipline.py @@ -10,8 +10,8 @@ # App imports from core.permissions import PermissionMixin from disciplines.models import Discipline -from .models import DisciplineFile -from .forms import FileForm +from files.models import DisciplineFile +from files.forms import DisciplineFileForm class ListDisciplineFileView(LoginRequiredMixin, @@ -47,7 +47,7 @@ def get_context_data(self, **kwargs): context = super(ListDisciplineFileView, self).get_context_data(**kwargs) context['discipline'] = self.get_discipline() - context['form'] = FileForm() + context['form'] = DisciplineFileForm() return context def get_queryset(self): @@ -71,7 +71,7 @@ class CreateDisciplineFileView(LoginRequiredMixin, model = DisciplineFile template_name = 'files/list.html' - form_class = FileForm + form_class = DisciplineFileForm permissions_required = [ 'monitor_can_change' @@ -137,7 +137,7 @@ class EditDisciplineFileView(LoginRequiredMixin, model = DisciplineFile template_name = 'files/form.html' context_object_name = 'file' - form_class = FileForm + form_class = DisciplineFileForm permissions_required = [ 'monitor_can_change' diff --git a/pgtbl/files/views_sessions.py b/pgtbl/files/views_sessions.py index 4b6c3e2..56237e3 100644 --- a/pgtbl/files/views_sessions.py +++ b/pgtbl/files/views_sessions.py @@ -12,8 +12,8 @@ from disciplines.models import Discipline from TBLSessions.models import TBLSession from TBLSessions.utils import get_datetimes -from .models import SessionFile -from .forms import SessionFileForm +from files.models import SessionFile +from files.forms import SessionFileForm class ListSessionFileView(LoginRequiredMixin, From dcb7149c0907d6217796e2f4332a64fc286aff59 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 23:35:43 -0300 Subject: [PATCH 14/56] Refactoring file models --- pgtbl/files/models/__init__.py | 2 ++ pgtbl/files/models/discipline_file.py | 16 ++++++++++++ pgtbl/files/{models.py => models/file.py} | 30 ----------------------- pgtbl/files/models/session_file.py | 16 ++++++++++++ 4 files changed, 34 insertions(+), 30 deletions(-) create mode 100644 pgtbl/files/models/__init__.py create mode 100644 pgtbl/files/models/discipline_file.py rename pgtbl/files/{models.py => models/file.py} (73%) create mode 100644 pgtbl/files/models/session_file.py diff --git a/pgtbl/files/models/__init__.py b/pgtbl/files/models/__init__.py new file mode 100644 index 0000000..4eac785 --- /dev/null +++ b/pgtbl/files/models/__init__.py @@ -0,0 +1,2 @@ +from .discipline_file import DisciplineFile +from .session_file import SessionFile diff --git a/pgtbl/files/models/discipline_file.py b/pgtbl/files/models/discipline_file.py new file mode 100644 index 0000000..7f3e4ac --- /dev/null +++ b/pgtbl/files/models/discipline_file.py @@ -0,0 +1,16 @@ +from django.db import models +from disciplines.models import Discipline +from .file import File + + +class DisciplineFile(File): + """ + Insert files into discipline. + """ + + discipline = models.ForeignKey( + Discipline, + on_delete=models.CASCADE, + verbose_name='Discipline', + related_name='files' + ) diff --git a/pgtbl/files/models.py b/pgtbl/files/models/file.py similarity index 73% rename from pgtbl/files/models.py rename to pgtbl/files/models/file.py index c1311e5..9be5ff5 100644 --- a/pgtbl/files/models.py +++ b/pgtbl/files/models/file.py @@ -1,10 +1,6 @@ from django.utils.translation import ugettext_lazy as _ from django.db import models -# App imports -from disciplines.models import Discipline -from TBLSessions.models import TBLSession - class File(models.Model): """ @@ -78,29 +74,3 @@ class Meta: verbose_name = _("File") verbose_name_plural = _("Files") ordering = ['title', 'created_at'] - - -class DisciplineFile(File): - """ - Insert files into discipline. - """ - - discipline = models.ForeignKey( - Discipline, - on_delete=models.CASCADE, - verbose_name='Discipline', - related_name='files' - ) - - -class SessionFile(File): - """ - File to insert into tbl sessions. - """ - - session = models.ForeignKey( - TBLSession, - on_delete=models.CASCADE, - verbose_name='Session', - related_name='files' - ) diff --git a/pgtbl/files/models/session_file.py b/pgtbl/files/models/session_file.py new file mode 100644 index 0000000..c98b54f --- /dev/null +++ b/pgtbl/files/models/session_file.py @@ -0,0 +1,16 @@ +from django.db import models +from TBLSessions.models import TBLSession +from .file import File + + +class SessionFile(File): + """ + File to insert into tbl sessions. + """ + + session = models.ForeignKey( + TBLSession, + on_delete=models.CASCADE, + verbose_name='Session', + related_name='files' + ) From 9007f1a542d020c4d86e268856723129f193157a Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Fri, 13 Jul 2018 23:55:40 -0300 Subject: [PATCH 15/56] Refactoring file views --- pgtbl/files/urls.py | 31 +- pgtbl/files/views/__init__.py | 8 + .../views/discipline_file/create_view.py | 76 ++++ .../views/discipline_file/delete_view.py | 51 +++ .../files/views/discipline_file/list_view.py | 55 +++ .../views/discipline_file/update_view.py | 70 ++++ pgtbl/files/views/session_file/create_view.py | 93 +++++ pgtbl/files/views/session_file/delete_view.py | 80 +++++ pgtbl/files/views/session_file/list_view.py | 79 +++++ pgtbl/files/views/session_file/update_view.py | 107 ++++++ pgtbl/files/views_discipline.py | 228 ------------ pgtbl/files/views_sessions.py | 330 ------------------ 12 files changed, 634 insertions(+), 574 deletions(-) create mode 100644 pgtbl/files/views/__init__.py create mode 100644 pgtbl/files/views/discipline_file/create_view.py create mode 100644 pgtbl/files/views/discipline_file/delete_view.py create mode 100644 pgtbl/files/views/discipline_file/list_view.py create mode 100644 pgtbl/files/views/discipline_file/update_view.py create mode 100644 pgtbl/files/views/session_file/create_view.py create mode 100644 pgtbl/files/views/session_file/delete_view.py create mode 100644 pgtbl/files/views/session_file/list_view.py create mode 100644 pgtbl/files/views/session_file/update_view.py delete mode 100644 pgtbl/files/views_discipline.py delete mode 100644 pgtbl/files/views_sessions.py diff --git a/pgtbl/files/urls.py b/pgtbl/files/urls.py index 99e24a3..3ea69ac 100644 --- a/pgtbl/files/urls.py +++ b/pgtbl/files/urls.py @@ -1,6 +1,5 @@ from django.conf.urls import url, include -from . import views_discipline -from . import views_sessions +from . import views app_name = 'files' @@ -8,25 +7,25 @@ # / url( r'^$', - views_discipline.ListDisciplineFileView.as_view(), + views.DisciplineFileListView.as_view(), name='list' ), # add/ url( - r'^add/$', - views_discipline.CreateDisciplineFileView.as_view(), + r'^create/$', + views.DisciplineFileCreateView.as_view(), name='create' ), # /edit/ url( - r'^(?P[0-9]+)/edit/$', - views_discipline.EditDisciplineFileView.as_view(), + r'^(?P[0-9]+)/update/$', + views.DisciplineFileUpdateView.as_view(), name='update' ), # /delete/ url( r'^(?P[0-9]+)/delete/$', - views_discipline.DeleteDisciplineFileView.as_view(), + views.DisciplineFileDeleteView.as_view(), name='delete' ), ] @@ -35,25 +34,25 @@ # / url( r'^$', - views_sessions.ListSessionFileView.as_view(), + views.SessionFileListView.as_view(), name='session-list' ), - # add/ + # create/ url( - r'^add/$', - views_sessions.CreateSessionFileView.as_view(), + r'^create/$', + views.SessionFileCreateView.as_view(), name='session-create' ), - # /edit/ + # /update/ url( - r'^(?P[0-9]+)/edit/$', - views_sessions.EditSessionFileView.as_view(), + r'^(?P[0-9]+)/update/$', + views.SessionFileUpdateView.as_view(), name='session-update' ), # /delete/ url( r'^(?P[0-9]+)/delete/$', - views_sessions.DeleteSessionFileView.as_view(), + views.SessionFileDeleteView.as_view(), name='session-delete' ), ] diff --git a/pgtbl/files/views/__init__.py b/pgtbl/files/views/__init__.py new file mode 100644 index 0000000..23c682b --- /dev/null +++ b/pgtbl/files/views/__init__.py @@ -0,0 +1,8 @@ +from .discipline_file.create_view import DisciplineFileCreateView +from .discipline_file.delete_view import DisciplineFileDeleteView +from .discipline_file.list_view import DisciplineFileListView +from .discipline_file.update_view import DisciplineFileUpdateView +from .session_file.create_view import SessionFileCreateView +from .session_file.delete_view import SessionFileDeleteView +from .session_file.list_view import SessionFileListView +from .session_file.update_view import SessionFileUpdateView diff --git a/pgtbl/files/views/discipline_file/create_view.py b/pgtbl/files/views/discipline_file/create_view.py new file mode 100644 index 0000000..e35b944 --- /dev/null +++ b/pgtbl/files/views/discipline_file/create_view.py @@ -0,0 +1,76 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.shortcuts import redirect +from django.contrib import messages +from django.views.generic import CreateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from files.models import DisciplineFile +from files.forms import DisciplineFileForm + + +class DisciplineFileCreateView(LoginRequiredMixin, + PermissionMixin, + CreateView): + """ + View to insert a new file into the discipline. + """ + + model = DisciplineFile + template_name = 'files/list.html' + form_class = DisciplineFileForm + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Receive the form already validated to create a file. + """ + + form.instance.discipline = self.get_discipline() + form.save() + + messages.success(self.request, _('File created successfully.')) + + return super(DisciplineFileCreateView, self).form_valid(form) + + def form_invalid(self, form): + """ + Redirect to form with form error. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the fields correctly.") + ) + + return redirect(self.get_success_url()) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'files:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/files/views/discipline_file/delete_view.py b/pgtbl/files/views/discipline_file/delete_view.py new file mode 100644 index 0000000..1451083 --- /dev/null +++ b/pgtbl/files/views/discipline_file/delete_view.py @@ -0,0 +1,51 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import DeleteView + +# App imports +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from files.models import DisciplineFile + + +class DisciplineFileDeleteView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific file. + """ + + model = DisciplineFile + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'files:list', + kwargs={'slug': discipline.slug} + ) + + messages.success(self.request, _("File deleted successfully.")) + + return success_url diff --git a/pgtbl/files/views/discipline_file/list_view.py b/pgtbl/files/views/discipline_file/list_view.py new file mode 100644 index 0000000..d95c09a --- /dev/null +++ b/pgtbl/files/views/discipline_file/list_view.py @@ -0,0 +1,55 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from files.models import DisciplineFile +from files.forms import DisciplineFileForm + + +class DisciplineFileListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all file of discipline. + """ + + template_name = 'files/list.html' + paginate_by = 10 + context_object_name = 'files' + + permissions_required = [ + 'show_files_permission' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert discipline and form into file context data. + """ + + context = super(DisciplineFileListView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['form'] = DisciplineFileForm() + return context + + def get_queryset(self): + """ + Get the files queryset from model database. + """ + + discipline = self.get_discipline() + + files = DisciplineFile.objects.filter(discipline=discipline) + + return files diff --git a/pgtbl/files/views/discipline_file/update_view.py b/pgtbl/files/views/discipline_file/update_view.py new file mode 100644 index 0000000..ca94cdf --- /dev/null +++ b/pgtbl/files/views/discipline_file/update_view.py @@ -0,0 +1,70 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from files.models import DisciplineFile +from files.forms import DisciplineFileForm + + +class DisciplineFileUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a specific file. + """ + + model = DisciplineFile + template_name = 'files/form.html' + context_object_name = 'file' + form_class = DisciplineFileForm + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert a discipline inside file form. + """ + + context = super(DisciplineFileUpdateView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + return context + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('File updated successfully.')) + + return super(DisciplineFileUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'files:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/files/views/session_file/create_view.py b/pgtbl/files/views/session_file/create_view.py new file mode 100644 index 0000000..b88d9f1 --- /dev/null +++ b/pgtbl/files/views/session_file/create_view.py @@ -0,0 +1,93 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.shortcuts import redirect +from django.contrib import messages +from django.views.generic import CreateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from files.models import SessionFile +from files.forms import SessionFileForm + + +class SessionFileCreateView(LoginRequiredMixin, + PermissionMixin, + CreateView): + """ + View to insert a new file into the tbl session. + """ + + model = SessionFile + template_name = 'files/session-list.html' + form_class = SessionFileForm + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the session that the file belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def form_valid(self, form): + """ + Receive the form already validated to create a file. + """ + + form.instance.discipline = self.get_discipline() + form.instance.session = self.get_session() + form.save() + + messages.success(self.request, _('File created successfully.')) + + return super(SessionFileCreateView, self).form_valid(form) + + def form_invalid(self, form): + """ + Redirect to form with form error. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the fields correctly.") + ) + + return redirect(self.get_success_url()) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'files:session-list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + return success_url diff --git a/pgtbl/files/views/session_file/delete_view.py b/pgtbl/files/views/session_file/delete_view.py new file mode 100644 index 0000000..1e84f8e --- /dev/null +++ b/pgtbl/files/views/session_file/delete_view.py @@ -0,0 +1,80 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import DeleteView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from files.models import SessionFile + + +class SessionFileDeleteView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific tbl session file. + """ + + model = SessionFile + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the session that the file belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Get the specific file from tbl session of discipline. + """ + + session = self.get_session() + + archive = SessionFile.objects.get( + session=session, + pk=self.kwargs.get('file_id', '') + ) + + return archive + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'files:session-list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + messages.success(self.request, _("File deleted successfully.")) + + return success_url diff --git a/pgtbl/files/views/session_file/list_view.py b/pgtbl/files/views/session_file/list_view.py new file mode 100644 index 0000000..e7cd39a --- /dev/null +++ b/pgtbl/files/views/session_file/list_view.py @@ -0,0 +1,79 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from files.models import SessionFile +from files.forms import SessionFileForm + + +class SessionFileListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all tbl session file of discipline. + """ + + template_name = 'files/session_list.html' + paginate_by = 10 + context_object_name = 'files' + + # Modificar + permissions_required = [ + 'show_files_permission', + 'show_tbl_file_session' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the session that the file belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline, session and form into file context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(SessionFileListView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['form'] = SessionFileForm() + + return context + + def get_queryset(self): + """ + Get the files queryset from model database. + """ + + session = self.get_session() + + # Modificar + files = SessionFile.objects.filter( + session=session + ) + + return files diff --git a/pgtbl/files/views/session_file/update_view.py b/pgtbl/files/views/session_file/update_view.py new file mode 100644 index 0000000..ab1b52e --- /dev/null +++ b/pgtbl/files/views/session_file/update_view.py @@ -0,0 +1,107 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from files.models import SessionFile +from files.forms import SessionFileForm + + +class SessionFileUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a specific session file. + """ + + model = SessionFile + template_name = 'files/session_form.html' + context_object_name = 'file' + form_class = SessionFileForm + + permissions_required = [ + 'monitor_can_change' + ] + + def get_discipline(self): + """ + Take the discipline that the file belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the session that the file belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Get the specific file from tbl session of discipline. + """ + + session = self.get_session() + + archive = SessionFile.objects.get( + session=session, + pk=self.kwargs.get('file_id', '') + ) + + return archive + + def get_context_data(self, **kwargs): + """ + Insert a discipline and session inside file form template. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(SessionFileUpdateView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + + return context + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('File updated successfully.')) + + return super(SessionFileUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'files:session-list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + return success_url diff --git a/pgtbl/files/views_discipline.py b/pgtbl/files/views_discipline.py deleted file mode 100644 index 2ce1a15..0000000 --- a/pgtbl/files/views_discipline.py +++ /dev/null @@ -1,228 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.shortcuts import redirect -from django.contrib import messages -from django.views.generic import ( - CreateView, ListView, UpdateView, DeleteView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from files.models import DisciplineFile -from files.forms import DisciplineFileForm - - -class ListDisciplineFileView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all file of discipline. - """ - - template_name = 'files/list.html' - paginate_by = 10 - context_object_name = 'files' - - permissions_required = [ - 'show_files_permission' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert discipline and form into file context data. - """ - - context = super(ListDisciplineFileView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['form'] = DisciplineFileForm() - return context - - def get_queryset(self): - """ - Get the files queryset from model database. - """ - - discipline = self.get_discipline() - - files = DisciplineFile.objects.filter(discipline=discipline) - - return files - - -class CreateDisciplineFileView(LoginRequiredMixin, - PermissionMixin, - CreateView): - """ - View to insert a new file into the discipline. - """ - - model = DisciplineFile - template_name = 'files/list.html' - form_class = DisciplineFileForm - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Receive the form already validated to create a file. - """ - - form.instance.discipline = self.get_discipline() - form.save() - - messages.success(self.request, _('File created successfully.')) - - return super(CreateDisciplineFileView, self).form_valid(form) - - def form_invalid(self, form): - """ - Redirect to form with form error. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the fields correctly.") - ) - - return redirect(self.get_success_url()) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'files:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class EditDisciplineFileView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a specific file. - """ - - model = DisciplineFile - template_name = 'files/form.html' - context_object_name = 'file' - form_class = DisciplineFileForm - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert a discipline inside file form. - """ - - context = super(EditDisciplineFileView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - return context - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('File updated successfully.')) - - return super(EditDisciplineFileView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'files:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class DeleteDisciplineFileView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific file. - """ - - model = DisciplineFile - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'files:list', - kwargs={'slug': discipline.slug} - ) - - messages.success(self.request, _("File deleted successfully.")) - - return success_url diff --git a/pgtbl/files/views_sessions.py b/pgtbl/files/views_sessions.py deleted file mode 100644 index 56237e3..0000000 --- a/pgtbl/files/views_sessions.py +++ /dev/null @@ -1,330 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.shortcuts import redirect -from django.contrib import messages -from django.views.generic import ( - CreateView, ListView, UpdateView, DeleteView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from files.models import SessionFile -from files.forms import SessionFileForm - - -class ListSessionFileView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all tbl session file of discipline. - """ - - template_name = 'files/session_list.html' - paginate_by = 10 - context_object_name = 'files' - - # Modificar - permissions_required = [ - 'show_files_permission', - 'show_tbl_file_session' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the session that the file belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline, session and form into file context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(ListSessionFileView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['form'] = SessionFileForm() - return context - - def get_queryset(self): - """ - Get the files queryset from model database. - """ - - session = self.get_session() - - # Modificar - files = SessionFile.objects.filter( - session=session - ) - - return files - - -class CreateSessionFileView(LoginRequiredMixin, - PermissionMixin, - CreateView): - """ - View to insert a new file into the tbl session. - """ - - model = SessionFile - template_name = 'files/session-list.html' - form_class = SessionFileForm - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the session that the file belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def form_valid(self, form): - """ - Receive the form already validated to create a file. - """ - - form.instance.discipline = self.get_discipline() - form.instance.session = self.get_session() - form.save() - - messages.success(self.request, _('File created successfully.')) - - return super(CreateSessionFileView, self).form_valid(form) - - def form_invalid(self, form): - """ - Redirect to form with form error. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the fields correctly.") - ) - - return redirect(self.get_success_url()) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'files:session-list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - return success_url - - -class EditSessionFileView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a specific session file. - """ - - model = SessionFile - template_name = 'files/session_form.html' - context_object_name = 'file' - form_class = SessionFileForm - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the session that the file belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Get the specific file from tbl session of discipline. - """ - - session = self.get_session() - - archive = SessionFile.objects.get( - session=session, - pk=self.kwargs.get('file_id', '') - ) - - return archive - - def get_context_data(self, **kwargs): - """ - Insert a discipline and session inside file form template. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(EditSessionFileView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - return context - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('File updated successfully.')) - - return super(EditSessionFileView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'files:session-list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - return success_url - - -class DeleteSessionFileView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific tbl session file. - """ - - model = SessionFile - - permissions_required = [ - 'monitor_can_change' - ] - - def get_discipline(self): - """ - Take the discipline that the file belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the session that the file belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Get the specific file from tbl session of discipline. - """ - - session = self.get_session() - - archive = SessionFile.objects.get( - session=session, - pk=self.kwargs.get('file_id', '') - ) - - return archive - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'files:session-list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - messages.success(self.request, _("File deleted successfully.")) - - return success_url From b1ed2729440d1343127ce6e5680245a1ab0e2c1b Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 00:12:50 -0300 Subject: [PATCH 16/56] Change session file to module file --- .../templates/TBLSessions/sidebar.html | 2 +- pgtbl/files/forms/__init__.py | 2 +- ...ssion_file_form.py => module_file_form.py} | 6 ++--- pgtbl/files/models/__init__.py | 2 +- .../{session_file.py => module_file.py} | 2 +- .../templates/files/session_add_file.html | 2 +- .../files/templates/files/session_delete.html | 2 +- pgtbl/files/templates/files/session_form.html | 4 ++-- pgtbl/files/templates/files/session_list.html | 4 ++-- pgtbl/files/urls.py | 20 ++++++++--------- pgtbl/files/views/__init__.py | 8 +++---- .../create_view.py | 18 +++++++-------- .../delete_view.py | 14 ++++++------ .../list_view.py | 16 +++++++------- .../update_view.py | 22 +++++++++---------- 15 files changed, 62 insertions(+), 62 deletions(-) rename pgtbl/files/forms/{session_file_form.py => module_file_form.py} (62%) rename pgtbl/files/models/{session_file.py => module_file.py} (92%) rename pgtbl/files/views/{session_file => module_file}/create_view.py (84%) rename pgtbl/files/views/{session_file => module_file}/delete_view.py (85%) rename pgtbl/files/views/{session_file => module_file}/list_view.py (81%) rename pgtbl/files/views/{session_file => module_file}/update_view.py (82%) diff --git a/pgtbl/TBLSessions/templates/TBLSessions/sidebar.html b/pgtbl/TBLSessions/templates/TBLSessions/sidebar.html index 3494890..822cf76 100644 --- a/pgtbl/TBLSessions/templates/TBLSessions/sidebar.html +++ b/pgtbl/TBLSessions/templates/TBLSessions/sidebar.html @@ -13,7 +13,7 @@ -

@@ -107,7 +107,7 @@

data-target="#add-modal"> - {% include 'files/session_add_file.html' %} + {% include 'files/module/add_file.html' %} {% endif %} {% include 'core/pagination.html' %} diff --git a/pgtbl/files/views/discipline_file/create_view.py b/pgtbl/files/views/discipline_file/create_view.py index e35b944..a5c72a8 100644 --- a/pgtbl/files/views/discipline_file/create_view.py +++ b/pgtbl/files/views/discipline_file/create_view.py @@ -19,7 +19,7 @@ class DisciplineFileCreateView(LoginRequiredMixin, """ model = DisciplineFile - template_name = 'files/list.html' + template_name = 'files/discipline/list.html' form_class = DisciplineFileForm permissions_required = [ diff --git a/pgtbl/files/views/discipline_file/list_view.py b/pgtbl/files/views/discipline_file/list_view.py index d95c09a..ac67bea 100644 --- a/pgtbl/files/views/discipline_file/list_view.py +++ b/pgtbl/files/views/discipline_file/list_view.py @@ -14,7 +14,7 @@ class DisciplineFileListView(LoginRequiredMixin, View to see all file of discipline. """ - template_name = 'files/list.html' + template_name = 'files/discipline/list.html' paginate_by = 10 context_object_name = 'files' diff --git a/pgtbl/files/views/discipline_file/update_view.py b/pgtbl/files/views/discipline_file/update_view.py index ca94cdf..9c0d58c 100644 --- a/pgtbl/files/views/discipline_file/update_view.py +++ b/pgtbl/files/views/discipline_file/update_view.py @@ -18,7 +18,7 @@ class DisciplineFileUpdateView(LoginRequiredMixin, """ model = DisciplineFile - template_name = 'files/form.html' + template_name = 'files/discipline/form.html' context_object_name = 'file' form_class = DisciplineFileForm diff --git a/pgtbl/files/views/module_file/create_view.py b/pgtbl/files/views/module_file/create_view.py index 0829e50..01ed8d0 100644 --- a/pgtbl/files/views/module_file/create_view.py +++ b/pgtbl/files/views/module_file/create_view.py @@ -20,7 +20,7 @@ class ModuleFileCreateView(LoginRequiredMixin, """ model = ModuleFile - template_name = 'files/session-list.html' + template_name = 'files/module/list.html' form_class = ModuleFileForm permissions_required = [ diff --git a/pgtbl/files/views/module_file/list_view.py b/pgtbl/files/views/module_file/list_view.py index 0b72137..0372dd1 100644 --- a/pgtbl/files/views/module_file/list_view.py +++ b/pgtbl/files/views/module_file/list_view.py @@ -16,7 +16,7 @@ class ModuleFileListView(LoginRequiredMixin, View to see all tbl session file of discipline. """ - template_name = 'files/session_list.html' + template_name = 'files/module/list.html' paginate_by = 10 context_object_name = 'files' diff --git a/pgtbl/files/views/module_file/update_view.py b/pgtbl/files/views/module_file/update_view.py index b397177..35f2973 100644 --- a/pgtbl/files/views/module_file/update_view.py +++ b/pgtbl/files/views/module_file/update_view.py @@ -20,7 +20,7 @@ class ModuleFileUpdateView(LoginRequiredMixin, """ model = ModuleFile - template_name = 'files/session_form.html' + template_name = 'files/module/form.html' context_object_name = 'file' form_class = ModuleFileForm From b3b645e6d3e44d00c2adfbb03cf3acbff3f7dba4 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 00:37:35 -0300 Subject: [PATCH 18/56] Fix file test organization --- pgtbl/files/tests/__init__.py | 0 pgtbl/files/tests/discipline/__init__.py | 0 .../test_discipline_file_create.py} | 59 +---------------- .../test_discipline_file_delete.py} | 51 +-------------- .../discipline/test_discipline_file_list.py | 49 +++++++++++++++ .../test_discipline_file_update.py} | 59 +---------------- pgtbl/files/tests/modules/__init__.py | 0 .../tests/modules/test_module_files_create.py | 63 +++++++++++++++++++ .../tests/modules/test_module_files_delete.py | 56 +++++++++++++++++ .../test_module_files_list.py} | 47 +------------- .../tests/modules/test_module_files_update.py | 63 +++++++++++++++++++ 11 files changed, 240 insertions(+), 207 deletions(-) create mode 100644 pgtbl/files/tests/__init__.py create mode 100644 pgtbl/files/tests/discipline/__init__.py rename pgtbl/files/tests/{test_create_files.py => discipline/test_discipline_file_create.py} (52%) rename pgtbl/files/tests/{test_delete_files.py => discipline/test_discipline_file_delete.py} (53%) create mode 100644 pgtbl/files/tests/discipline/test_discipline_file_list.py rename pgtbl/files/tests/{test_update_files.py => discipline/test_discipline_file_update.py} (52%) create mode 100644 pgtbl/files/tests/modules/__init__.py create mode 100644 pgtbl/files/tests/modules/test_module_files_create.py create mode 100644 pgtbl/files/tests/modules/test_module_files_delete.py rename pgtbl/files/tests/{test_list_files.py => modules/test_module_files_list.py} (53%) create mode 100644 pgtbl/files/tests/modules/test_module_files_update.py diff --git a/pgtbl/files/tests/__init__.py b/pgtbl/files/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/files/tests/discipline/__init__.py b/pgtbl/files/tests/discipline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/files/tests/test_create_files.py b/pgtbl/files/tests/discipline/test_discipline_file_create.py similarity index 52% rename from pgtbl/files/tests/test_create_files.py rename to pgtbl/files/tests/discipline/test_discipline_file_create.py index c76456b..f9da66e 100644 --- a/pgtbl/files/tests/test_create_files.py +++ b/pgtbl/files/tests/discipline/test_discipline_file_create.py @@ -3,12 +3,12 @@ from django.test import TestCase, Client from core.test_utils import check_messages from model_mommy import mommy -from files.models import File +from files.models import DisciplineFile User = get_user_model() -class CreateFileTestCase(TestCase): +class DisciplineFileCreateTestCase(TestCase): """ Test to create a new discipline file. """ @@ -61,58 +61,3 @@ def test_create_file_by_student_fail(self): """ pass - - -class CreateSessionFileTestCase(TestCase): - """ - Test to create a new session file. - """ - - def setUp(self): - """ - This method will run before any test case. - """ - - pass - - def tearDown(self): - """ - This method will run after any test. - """ - - pass - - def test_redirect_to_login(self): - """ - User can not create a new file without logged in. - """ - - pass - - def test_create_file_by_teacher(self): - """ - Test to create a new file by teacher. - """ - - pass - - def test_create_file_by_monitors(self): - """ - Test to create a new file by monitors. - """ - - pass - - def test_create_file_fail(self): - """ - User can not create a file with invalid fields. - """ - - pass - - def test_create_file_by_student_fail(self): - """ - Student can not create a file. - """ - - pass diff --git a/pgtbl/files/tests/test_delete_files.py b/pgtbl/files/tests/discipline/test_discipline_file_delete.py similarity index 53% rename from pgtbl/files/tests/test_delete_files.py rename to pgtbl/files/tests/discipline/test_discipline_file_delete.py index f43e7e0..4e646e8 100644 --- a/pgtbl/files/tests/test_delete_files.py +++ b/pgtbl/files/tests/discipline/test_discipline_file_delete.py @@ -3,12 +3,12 @@ from django.test import TestCase, Client from core.test_utils import check_messages from model_mommy import mommy -from files.models import File +from files.models import DisciplineFile User = get_user_model() -class DeleteFileTestCase(TestCase): +class DisciplineFileDeleteTestCase(TestCase): """ Test to delete a discipline file. """ @@ -54,50 +54,3 @@ def test_delete_file_by_student_fail(self): """ pass - -class DeleteSessionFileTestCase(TestCase): - """ - Test to delete a session file. - """ - - def setUp(self): - """ - This method will run before any test case. - """ - - pass - - def tearDown(self): - """ - This method will run after any test. - """ - - pass - - def test_redirect_to_login(self): - """ - User can not delete a file without logged in. - """ - - pass - - def test_delete_file_by_teacher(self): - """ - Test to delete a file by teacher. - """ - - pass - - def test_delete_file_by_monitors(self): - """ - Test to delete a file by monitors. - """ - - pass - - def test_delete_file_by_student_fail(self): - """ - Student can not delete a file. - """ - - pass diff --git a/pgtbl/files/tests/discipline/test_discipline_file_list.py b/pgtbl/files/tests/discipline/test_discipline_file_list.py new file mode 100644 index 0000000..e3a3d41 --- /dev/null +++ b/pgtbl/files/tests/discipline/test_discipline_file_list.py @@ -0,0 +1,49 @@ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.test import TestCase, Client +from core.test_utils import check_messages +from model_mommy import mommy +from files.models import DisciplineFile + +User = get_user_model() + + +class DisciplineFileListTestCase(TestCase): + """ + Test to list discipline files. + """ + + def setUp(self): + """ + This method will run before any test case. + """ + + pass + + def tearDown(self): + """ + This method will run after any test. + """ + + pass + + def test_redirect_to_login(self): + """ + User can not see the file list without logged in. + """ + + pass + + def test_file_pagination(self): + """ + Test to show files by pagination. + """ + + pass + + def test_users_can_see_the_files(self): + """ + User like students, monitors and teacher can see the list of files. + """ + + pass diff --git a/pgtbl/files/tests/test_update_files.py b/pgtbl/files/tests/discipline/test_discipline_file_update.py similarity index 52% rename from pgtbl/files/tests/test_update_files.py rename to pgtbl/files/tests/discipline/test_discipline_file_update.py index 7a8d083..e61175f 100644 --- a/pgtbl/files/tests/test_update_files.py +++ b/pgtbl/files/tests/discipline/test_discipline_file_update.py @@ -3,12 +3,12 @@ from django.test import TestCase, Client from core.test_utils import check_messages from model_mommy import mommy -from files.models import File +from files.models import DisciplineFile User = get_user_model() -class UpdateFileTestCase(TestCase): +class DisciplineFileTestUpdateCase(TestCase): """ Test to update a discipline file. """ @@ -61,58 +61,3 @@ def test_update_file_by_student_fail(self): """ pass - - -class UpdateSessionFileTestCase(TestCase): - """ - Test to update a session file. - """ - - def setUp(self): - """ - This method will run before any test case. - """ - - pass - - def tearDown(self): - """ - This method will run after any test. - """ - - pass - - def test_redirect_to_login(self): - """ - User can not update a file without logged in. - """ - - pass - - def test_update_file_by_teacher(self): - """ - Test to update a file by teacher. - """ - - pass - - def test_update_file_by_monitors(self): - """ - Test to update a file by monitors. - """ - - pass - - def test_update_file_fail(self): - """ - User can not update a file with invalid fields. - """ - - pass - - def test_update_file_by_student_fail(self): - """ - Student can not update a file. - """ - - pass diff --git a/pgtbl/files/tests/modules/__init__.py b/pgtbl/files/tests/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/files/tests/modules/test_module_files_create.py b/pgtbl/files/tests/modules/test_module_files_create.py new file mode 100644 index 0000000..4197e53 --- /dev/null +++ b/pgtbl/files/tests/modules/test_module_files_create.py @@ -0,0 +1,63 @@ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.test import TestCase, Client +from core.test_utils import check_messages +from model_mommy import mommy +from files.models import ModuleFile + +User = get_user_model() + + +class ModuleFileCreateTestCase(TestCase): + """ + Test to create a new module file. + """ + + def setUp(self): + """ + This method will run before any test case. + """ + + pass + + def tearDown(self): + """ + This method will run after any test. + """ + + pass + + def test_redirect_to_login(self): + """ + User can not create a new file without logged in. + """ + + pass + + def test_create_file_by_teacher(self): + """ + Test to create a new file by teacher. + """ + + pass + + def test_create_file_by_monitors(self): + """ + Test to create a new file by monitors. + """ + + pass + + def test_create_file_fail(self): + """ + User can not create a file with invalid fields. + """ + + pass + + def test_create_file_by_student_fail(self): + """ + Student can not create a file. + """ + + pass diff --git a/pgtbl/files/tests/modules/test_module_files_delete.py b/pgtbl/files/tests/modules/test_module_files_delete.py new file mode 100644 index 0000000..0d99eaa --- /dev/null +++ b/pgtbl/files/tests/modules/test_module_files_delete.py @@ -0,0 +1,56 @@ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.test import TestCase, Client +from core.test_utils import check_messages +from model_mommy import mommy +from files.models import ModuleFile + +User = get_user_model() + + +class ModuleFileDeleteTestCase(TestCase): + """ + Test to delete a module file. + """ + + def setUp(self): + """ + This method will run before any test case. + """ + + pass + + def tearDown(self): + """ + This method will run after any test. + """ + + pass + + def test_redirect_to_login(self): + """ + User can not delete a file without logged in. + """ + + pass + + def test_delete_file_by_teacher(self): + """ + Test to delete a file by teacher. + """ + + pass + + def test_delete_file_by_monitors(self): + """ + Test to delete a file by monitors. + """ + + pass + + def test_delete_file_by_student_fail(self): + """ + Student can not delete a file. + """ + + pass diff --git a/pgtbl/files/tests/test_list_files.py b/pgtbl/files/tests/modules/test_module_files_list.py similarity index 53% rename from pgtbl/files/tests/test_list_files.py rename to pgtbl/files/tests/modules/test_module_files_list.py index b8d5abf..17f7cb8 100644 --- a/pgtbl/files/tests/test_list_files.py +++ b/pgtbl/files/tests/modules/test_module_files_list.py @@ -3,55 +3,14 @@ from django.test import TestCase, Client from core.test_utils import check_messages from model_mommy import mommy -from files.models import File +from files.models import ModuleFile User = get_user_model() -class ListFileTestCase(TestCase): +class ModuleFileListTestCase(TestCase): """ - Test to list discipline files. - """ - - def setUp(self): - """ - This method will run before any test case. - """ - - pass - - def tearDown(self): - """ - This method will run after any test. - """ - - pass - - def test_redirect_to_login(self): - """ - User can not see the file list without logged in. - """ - - pass - - def test_file_pagination(self): - """ - Test to show files by pagination. - """ - - pass - - def test_users_can_see_the_files(self): - """ - User like students, monitors and teacher can see the list of files. - """ - - pass - - -class ListSessionFileTestCase(TestCase): - """ - Test to list session files. + Test to list module files. """ def setUp(self): diff --git a/pgtbl/files/tests/modules/test_module_files_update.py b/pgtbl/files/tests/modules/test_module_files_update.py new file mode 100644 index 0000000..1e44d05 --- /dev/null +++ b/pgtbl/files/tests/modules/test_module_files_update.py @@ -0,0 +1,63 @@ +from django.core.urlresolvers import reverse_lazy +from django.contrib.auth import get_user_model +from django.test import TestCase, Client +from core.test_utils import check_messages +from model_mommy import mommy +from files.models import ModuleFile + +User = get_user_model() + + +class ModuleFileUpdateTestCase(TestCase): + """ + Test to update a moduel file. + """ + + def setUp(self): + """ + This method will run before any test case. + """ + + pass + + def tearDown(self): + """ + This method will run after any test. + """ + + pass + + def test_redirect_to_login(self): + """ + User can not update a file without logged in. + """ + + pass + + def test_update_file_by_teacher(self): + """ + Test to update a file by teacher. + """ + + pass + + def test_update_file_by_monitors(self): + """ + Test to update a file by monitors. + """ + + pass + + def test_update_file_fail(self): + """ + User can not update a file with invalid fields. + """ + + pass + + def test_update_file_by_student_fail(self): + """ + Student can not update a file. + """ + + pass From 5c3a43df8134a53e750236703bf84b62f0854ecf Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 00:43:35 -0300 Subject: [PATCH 19/56] Refactoring grades forms and models --- pgtbl/grades/forms/__init__.py | 1 + .../grades/{forms.py => forms/grade_form.py} | 2 +- pgtbl/grades/models/__init__.py | 2 + pgtbl/grades/models/final_grade.py | 72 +++++++++++++++++++ pgtbl/grades/{models.py => models/grade.py} | 71 ------------------ 5 files changed, 76 insertions(+), 72 deletions(-) create mode 100644 pgtbl/grades/forms/__init__.py rename pgtbl/grades/{forms.py => forms/grade_form.py} (87%) create mode 100644 pgtbl/grades/models/__init__.py create mode 100644 pgtbl/grades/models/final_grade.py rename pgtbl/grades/{models.py => models/grade.py} (63%) diff --git a/pgtbl/grades/forms/__init__.py b/pgtbl/grades/forms/__init__.py new file mode 100644 index 0000000..f3765bc --- /dev/null +++ b/pgtbl/grades/forms/__init__.py @@ -0,0 +1 @@ +from .grade_form import GradeForm diff --git a/pgtbl/grades/forms.py b/pgtbl/grades/forms/grade_form.py similarity index 87% rename from pgtbl/grades/forms.py rename to pgtbl/grades/forms/grade_form.py index ae99f03..4890d3e 100644 --- a/pgtbl/grades/forms.py +++ b/pgtbl/grades/forms/grade_form.py @@ -1,5 +1,5 @@ from django import forms -from .models import Grade +from grades.models import Grade class GradeForm(forms.ModelForm): diff --git a/pgtbl/grades/models/__init__.py b/pgtbl/grades/models/__init__.py new file mode 100644 index 0000000..5fcefa0 --- /dev/null +++ b/pgtbl/grades/models/__init__.py @@ -0,0 +1,2 @@ +from .grade import Grade +from .final_grade import FinalGrade diff --git a/pgtbl/grades/models/final_grade.py b/pgtbl/grades/models/final_grade.py new file mode 100644 index 0000000..7e30940 --- /dev/null +++ b/pgtbl/grades/models/final_grade.py @@ -0,0 +1,72 @@ +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.db import models +from disciplines.models import Discipline + + +class FinalGrade(models.Model): + """ + Store the student grade of discipline. + """ + + discipline = models.ForeignKey( + Discipline, + on_delete=models.CASCADE, + verbose_name='Disciplines', + related_name='grades' + ) + + student = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name='Students', + related_name='discipline_grades' + ) + + created_at = models.DateTimeField( + _('Created at'), + help_text=_("Date that the session is created."), + auto_now_add=True + ) + + updated_at = models.DateTimeField( + _('Updated at'), + help_text=_("Date that the session is updated."), + auto_now=True + ) + + def calcule_final_grade(self): + """ + Calcule the student final grade. + """ + + session_grades = 0.0 + + number_of_sessions = self.discipline.tbl_sessions.count() + + for session in self.discipline.tbl_sessions.all(): + for grade in session.grades.filter(student=self.student): + session_grades += grade.calcule_session_grade() + + grade = 0.0 + if number_of_sessions > 0: + grade = (session_grades / number_of_sessions) + + return grade + + def __str__(self): + """ + Returns the object as a string, the attribute that will represent + the object. + """ + + return '{0}: {1} - {2}'.format( + self.discipline.title, + self.student.get_short_name(), + self.calcule_final_grade() + ) + + class Meta: + verbose_name = _('Discipline grades') + verbose_name_plural = _('Discipline grades') + ordering = ['discipline', 'student', 'created_at'] diff --git a/pgtbl/grades/models.py b/pgtbl/grades/models/grade.py similarity index 63% rename from pgtbl/grades/models.py rename to pgtbl/grades/models/grade.py index d0cc768..16c25d1 100644 --- a/pgtbl/grades/models.py +++ b/pgtbl/grades/models/grade.py @@ -1,10 +1,7 @@ from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.db import models - -# App imports from TBLSessions.models import TBLSession -from disciplines.models import Discipline from groups.models import Group @@ -120,71 +117,3 @@ class Meta: verbose_name = _('TBL Session grades') verbose_name_plural = _('TBL Sessions grades') ordering = ['session', 'student', 'created_at'] - - -class FinalGrade(models.Model): - """ - Store the student grade of discipline. - """ - - discipline = models.ForeignKey( - Discipline, - on_delete=models.CASCADE, - verbose_name='Disciplines', - related_name='grades' - ) - - student = models.ForeignKey( - settings.AUTH_USER_MODEL, - on_delete=models.CASCADE, - verbose_name='Students', - related_name='discipline_grades' - ) - - created_at = models.DateTimeField( - _('Created at'), - help_text=_("Date that the session is created."), - auto_now_add=True - ) - - updated_at = models.DateTimeField( - _('Updated at'), - help_text=_("Date that the session is updated."), - auto_now=True - ) - - def calcule_final_grade(self): - """ - Calcule the student final grade. - """ - - session_grades = 0.0 - - number_of_sessions = self.discipline.tbl_sessions.count() - - for session in self.discipline.tbl_sessions.all(): - for grade in session.grades.filter(student=self.student): - session_grades += grade.calcule_session_grade() - - grade = 0.0 - if number_of_sessions > 0: - grade = (session_grades/number_of_sessions) - - return grade - - def __str__(self): - """ - Returns the object as a string, the attribute that will represent - the object. - """ - - return '{0}: {1} - {2}'.format( - self.discipline.title, - self.student.get_short_name(), - self.calcule_final_grade() - ) - - class Meta: - verbose_name = _('Discipline grades') - verbose_name_plural = _('Discipline grades') - ordering = ['discipline', 'student', 'created_at'] From d67ea349354286d5bed2af4756342f55781780b2 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 00:57:17 -0300 Subject: [PATCH 20/56] Refactoring grade views --- pgtbl/grades/tests/__init__.py | 0 pgtbl/grades/urls.py | 2 +- pgtbl/grades/views.py | 351 --------------------- pgtbl/grades/views/__init__.py | 5 + pgtbl/grades/views/grade_discipline_csv.py | 50 +++ pgtbl/grades/views/grade_list_view.py | 69 ++++ pgtbl/grades/views/grade_module_csv.py | 58 ++++ pgtbl/grades/views/grade_result_view.py | 56 ++++ pgtbl/grades/views/grade_update_view.py | 134 ++++++++ 9 files changed, 373 insertions(+), 352 deletions(-) create mode 100644 pgtbl/grades/tests/__init__.py delete mode 100644 pgtbl/grades/views.py create mode 100644 pgtbl/grades/views/__init__.py create mode 100644 pgtbl/grades/views/grade_discipline_csv.py create mode 100644 pgtbl/grades/views/grade_list_view.py create mode 100644 pgtbl/grades/views/grade_module_csv.py create mode 100644 pgtbl/grades/views/grade_result_view.py create mode 100644 pgtbl/grades/views/grade_update_view.py diff --git a/pgtbl/grades/tests/__init__.py b/pgtbl/grades/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/grades/urls.py b/pgtbl/grades/urls.py index 7362c5a..45fdb91 100644 --- a/pgtbl/grades/urls.py +++ b/pgtbl/grades/urls.py @@ -19,7 +19,7 @@ # /session-csv/ url( r'^session-csv/$', - views.get_session_grade_csv, + views.get_module_grade_csv, name='session-csv' ), ] diff --git a/pgtbl/grades/views.py b/pgtbl/grades/views.py deleted file mode 100644 index a03d1f4..0000000 --- a/pgtbl/grades/views.py +++ /dev/null @@ -1,351 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib import messages -from django.views.generic import ( - ListView, UpdateView -) - -# CSV -from django.http import HttpResponse -import csv - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from accounts.models import User -from .models import Grade, FinalGrade -from .forms import GradeForm - - -class GradeListView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all student grades of TBL sessions. - """ - - template_name = 'grades/list.html' - context_object_name = 'grades' - - permissions_required = ['show_session_grades'] - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Get the session by url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline and form into session context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(GradeListView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - return context - - def get_queryset(self): - """ - Get the tbl sessions queryset from model database. - """ - - discipline = self.get_discipline() - - grades = Grade.objects.filter( - session=self.get_session() - ) - - return grades - - -class GradeUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - Update student grade. - """ - - model = Grade - template_name = 'grades/form.html' - context_object_name = 'grade' - form_class = GradeForm - - permissions_required = ['only_teacher_can_change'] - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Get the session by url kwargs. - """ - - discipline = self.get_discipline() - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Get student grade. - """ - - user = User.objects.get( - pk=self.kwargs.get('student_pk', '') - ) - - grade = Grade.objects.get( - student=user - ) - - return grade - - def get_context_data(self, **kwargs): - """ - Insert a discipline inside grade edit template. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(GradeUpdateView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - return context - - def form_valid(self, form): - """ - Return the form with valided fields. - """ - - if form.instance.irat > 10 or form.instance.irat < 0: - return self.form_invalid(form) - - if form.instance.grat > 10 or form.instance.grat < 0: - return self.form_invalid(form) - - if form.instance.practical > 10 or form.instance.practical < 0: - return self.form_invalid(form) - - if form.instance.peer_review > 10 or form.instance.peer_review < 0: - return self.form_invalid(form) - - messages.success( - self.request, - _("Grades updated successfully.") - ) - - return super(GradeUpdateView, self).form_valid(form) - - def form_invalid(self, form): - """ - Return the form with specific field errors. - """ - - messages.error( - self.request, - _("Grade need to be a number between 0 and 10.") - ) - - return super(GradeUpdateView, self).form_invalid(form) - - def get_success_url(self): - """ - Get the success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'grades:list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.pk - } - ) - - return success_url - - -class GradeResultView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Show the list of students with their final grade. - """ - - template_name = 'grades/result.html' - context_object_name = 'grades' - - permissions_required = [] - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert discipline and form into session context data. - """ - - context = super(GradeResultView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - return context - - def get_queryset(self): - """ - Get the tbl sessions queryset from model database. - """ - - grades = [] - discipline = self.get_discipline() - - for student in discipline.students.all(): - grade, created = FinalGrade.objects.get_or_create( - discipline=discipline, - student=student - ) - grades.append(grade) - - return grades - - -def get_session_grade_csv(request, *args, **kwargs): - """ - Create a CSV from TBL session grades. - """ - - # Create the HttpResponse object with the approprieate CSV headers. - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="session-grades.csv"' - - # Create the CSV writer - writer = csv.writer(response) - - # Get important variables - discipline = Discipline.objects.get( - slug=kwargs.get('slug', '') - ) - - session = TBLSession.objects.get( - pk=kwargs.get('pk', '') - ) - - grades = Grade.objects.filter( - session=session - ) - - # Create CSV file rows - writer.writerow([ - 'Disciplina' - 'Grupos', - 'UsuƔrios', - 'iRAT', - 'gRAT', - 'Test prƔtico', - 'Peer Review', - 'Nota final' - ]) - - for grade in grades: - writer.writerow([ - '{0}'.format(discipline.title), - '{0}'.format(grade.group.title), - '{0}'.format(grade.student.username), - '{0}'.format(grade.irat), - '{0}'.format(grade.grat), - '{0}'.format(grade.practical), - '{0}'.format(grade.peer_review), - '{0:.1f}'.format(grade.calcule_session_grade()) - ]) - - return response - - -def get_final_grade_csv(request, *args, **kwargs): - """ - Create a CSV from students final grade. - """ - - # Create the HttpResponse object with the approprieate CSV headers. - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="final-grades.csv"' - - # Create the CSV writer - writer = csv.writer(response) - - # Get important variables - discipline = Discipline.objects.get( - slug=kwargs.get('slug', '') - ) - - grades = FinalGrade.objects.filter( - discipline=discipline - ) - - # Create CSV file rows - writer.writerow([ - 'Disciplina', - 'UsuƔrios', - 'Nota final', - 'Status' - ]) - - for grade in grades: - if grade.calcule_final_grade() > 5: - status = 'Aprovado' - else: - status = 'Reprovado' - - writer.writerow([ - '{0}'.format(discipline.title), - '{0}'.format(grade.student.username), - '{0:.1f}'.format(grade.calcule_final_grade()), - '{0}'.format(status) - ]) - - return response diff --git a/pgtbl/grades/views/__init__.py b/pgtbl/grades/views/__init__.py new file mode 100644 index 0000000..ebf2e91 --- /dev/null +++ b/pgtbl/grades/views/__init__.py @@ -0,0 +1,5 @@ +from .grade_discipline_csv import get_final_grade_csv +from .grade_module_csv import get_module_grade_csv +from .grade_list_view import GradeListView +from .grade_update_view import GradeUpdateView +from .grade_result_view import GradeResultView diff --git a/pgtbl/grades/views/grade_discipline_csv.py b/pgtbl/grades/views/grade_discipline_csv.py new file mode 100644 index 0000000..738757e --- /dev/null +++ b/pgtbl/grades/views/grade_discipline_csv.py @@ -0,0 +1,50 @@ +from django.http import HttpResponse +import csv + +from disciplines.models import Discipline +from grades.models import FinalGrade + + +def get_final_grade_csv(request, *args, **kwargs): + """ + Create a CSV from students final grade. + """ + + # Create the HttpResponse object with the approprieate CSV headers. + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="final-grades.csv"' + + # Create the CSV writer + writer = csv.writer(response) + + # Get important variables + discipline = Discipline.objects.get( + slug=kwargs.get('slug', '') + ) + + grades = FinalGrade.objects.filter( + discipline=discipline + ) + + # Create CSV file rows + writer.writerow([ + 'Disciplina', + 'UsuƔrios', + 'Nota final', + 'Status' + ]) + + for grade in grades: + if grade.calcule_final_grade() > 5: + status = 'Aprovado' + else: + status = 'Reprovado' + + writer.writerow([ + '{0}'.format(discipline.title), + '{0}'.format(grade.student.username), + '{0:.1f}'.format(grade.calcule_final_grade()), + '{0}'.format(status) + ]) + + return response diff --git a/pgtbl/grades/views/grade_list_view.py b/pgtbl/grades/views/grade_list_view.py new file mode 100644 index 0000000..2ebf6a9 --- /dev/null +++ b/pgtbl/grades/views/grade_list_view.py @@ -0,0 +1,69 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from grades.models import Grade + + +class GradeListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all student grades of TBL sessions. + """ + + template_name = 'grades/list.html' + context_object_name = 'grades' + + permissions_required = ['show_session_grades'] + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Get the session by url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline and form into session context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(GradeListView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + + return context + + def get_queryset(self): + """ + Get the tbl sessions queryset from model database. + """ + + grades = Grade.objects.filter( + session=self.get_session() + ) + + return grades diff --git a/pgtbl/grades/views/grade_module_csv.py b/pgtbl/grades/views/grade_module_csv.py new file mode 100644 index 0000000..2df349f --- /dev/null +++ b/pgtbl/grades/views/grade_module_csv.py @@ -0,0 +1,58 @@ +from django.http import HttpResponse +import csv + +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from grades.models import Grade + + +def get_module_grade_csv(request, *args, **kwargs): + """ + Create a CSV from TBL module grades. + """ + + # Create the HttpResponse object with the approprieate CSV headers. + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="session-grades.csv"' + + # Create the CSV writer + writer = csv.writer(response) + + # Get important variables + discipline = Discipline.objects.get( + slug=kwargs.get('slug', '') + ) + + session = TBLSession.objects.get( + pk=kwargs.get('pk', '') + ) + + grades = Grade.objects.filter( + session=session + ) + + # Create CSV file rows + writer.writerow([ + 'Disciplina' + 'Grupos', + 'UsuƔrios', + 'iRAT', + 'gRAT', + 'Test prƔtico', + 'Peer Review', + 'Nota final' + ]) + + for grade in grades: + writer.writerow([ + '{0}'.format(discipline.title), + '{0}'.format(grade.group.title), + '{0}'.format(grade.student.username), + '{0}'.format(grade.irat), + '{0}'.format(grade.grat), + '{0}'.format(grade.practical), + '{0}'.format(grade.peer_review), + '{0:.1f}'.format(grade.calcule_session_grade()) + ]) + + return response diff --git a/pgtbl/grades/views/grade_result_view.py b/pgtbl/grades/views/grade_result_view.py new file mode 100644 index 0000000..c73071b --- /dev/null +++ b/pgtbl/grades/views/grade_result_view.py @@ -0,0 +1,56 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from grades.models import FinalGrade + + +class GradeResultView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Show the list of students with their final grade. + """ + + template_name = 'grades/result.html' + context_object_name = 'grades' + + permissions_required = [] + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert discipline and form into session context data. + """ + + context = super(GradeResultView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + return context + + def get_queryset(self): + """ + Get the tbl sessions queryset from model database. + """ + + grades = [] + discipline = self.get_discipline() + + for student in discipline.students.all(): + grade, created = FinalGrade.objects.get_or_create( + discipline=discipline, + student=student + ) + grades.append(grade) + + return grades diff --git a/pgtbl/grades/views/grade_update_view.py b/pgtbl/grades/views/grade_update_view.py new file mode 100644 index 0000000..d71bd93 --- /dev/null +++ b/pgtbl/grades/views/grade_update_view.py @@ -0,0 +1,134 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from accounts.models import User +from grades.models import Grade +from grades.forms import GradeForm + + +class GradeUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + Update student grade. + """ + + model = Grade + template_name = 'grades/form.html' + context_object_name = 'grade' + form_class = GradeForm + + permissions_required = ['only_teacher_can_change'] + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Get the session by url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Get student grade. + """ + + user = User.objects.get( + pk=self.kwargs.get('student_pk', '') + ) + + grade = Grade.objects.get( + student=user + ) + + return grade + + def get_context_data(self, **kwargs): + """ + Insert a discipline inside grade edit template. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(GradeUpdateView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + + return context + + def form_valid(self, form): + """ + Return the form with valided fields. + """ + + if form.instance.irat > 10 or form.instance.irat < 0: + return self.form_invalid(form) + + if form.instance.grat > 10 or form.instance.grat < 0: + return self.form_invalid(form) + + if form.instance.practical > 10 or form.instance.practical < 0: + return self.form_invalid(form) + + if form.instance.peer_review > 10 or form.instance.peer_review < 0: + return self.form_invalid(form) + + messages.success( + self.request, + _("Grades updated successfully.") + ) + + return super(GradeUpdateView, self).form_valid(form) + + def form_invalid(self, form): + """ + Return the form with specific field errors. + """ + + messages.error( + self.request, + _("Grade need to be a number between 0 and 10.") + ) + + return super(GradeUpdateView, self).form_invalid(form) + + def get_success_url(self): + """ + Get the success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'grades:list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.pk + } + ) + + return success_url From d5ef193541de1223ae51bc7bf1a85bd510d37757 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 01:09:04 -0300 Subject: [PATCH 21/56] Refactoring TBLSession forms and models --- pgtbl/TBLSessions/forms/__init__.py | 2 ++ .../practical_test_form.py} | 19 +---------------- pgtbl/TBLSessions/forms/tbl_session_form.py | 21 +++++++++++++++++++ pgtbl/TBLSessions/models/__init__.py | 1 + .../{models.py => models/tbl_session.py} | 0 5 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 pgtbl/TBLSessions/forms/__init__.py rename pgtbl/TBLSessions/{forms.py => forms/practical_test_form.py} (56%) create mode 100644 pgtbl/TBLSessions/forms/tbl_session_form.py create mode 100644 pgtbl/TBLSessions/models/__init__.py rename pgtbl/TBLSessions/{models.py => models/tbl_session.py} (100%) diff --git a/pgtbl/TBLSessions/forms/__init__.py b/pgtbl/TBLSessions/forms/__init__.py new file mode 100644 index 0000000..1c551cf --- /dev/null +++ b/pgtbl/TBLSessions/forms/__init__.py @@ -0,0 +1,2 @@ +from .tbl_session_form import TBLSessionForm +from .practical_test_form import PracticalTestForm diff --git a/pgtbl/TBLSessions/forms.py b/pgtbl/TBLSessions/forms/practical_test_form.py similarity index 56% rename from pgtbl/TBLSessions/forms.py rename to pgtbl/TBLSessions/forms/practical_test_form.py index 0ead4fb..b0878b2 100644 --- a/pgtbl/TBLSessions/forms.py +++ b/pgtbl/TBLSessions/forms/practical_test_form.py @@ -1,25 +1,8 @@ from django import forms from pagedown.widgets import PagedownWidget -from .models import TBLSession +from TBLSessions.models import TBLSession -class TBLSessionForm(forms.ModelForm): - """ - Form to create a new tbl session. - """ - - class Meta: - model = TBLSession - fields = ['title', 'description', 'is_closed'] - - # Widgets about some fields - widgets = { - 'description': PagedownWidget( - css=("core/css/markdown.css"), - show_preview=False - ) - } - class PracticalTestForm(forms.ModelForm): """ Form to update the practical test. diff --git a/pgtbl/TBLSessions/forms/tbl_session_form.py b/pgtbl/TBLSessions/forms/tbl_session_form.py new file mode 100644 index 0000000..096ef72 --- /dev/null +++ b/pgtbl/TBLSessions/forms/tbl_session_form.py @@ -0,0 +1,21 @@ +from django import forms +from pagedown.widgets import PagedownWidget +from TBLSessions.models import TBLSession + + +class TBLSessionForm(forms.ModelForm): + """ + Form to create a new tbl session. + """ + + class Meta: + model = TBLSession + fields = ['title', 'description', 'is_closed'] + + # Widgets about some fields + widgets = { + 'description': PagedownWidget( + css=("core/css/markdown.css"), + show_preview=False + ) + } diff --git a/pgtbl/TBLSessions/models/__init__.py b/pgtbl/TBLSessions/models/__init__.py new file mode 100644 index 0000000..d8194e8 --- /dev/null +++ b/pgtbl/TBLSessions/models/__init__.py @@ -0,0 +1 @@ +from .tbl_session import TBLSession diff --git a/pgtbl/TBLSessions/models.py b/pgtbl/TBLSessions/models/tbl_session.py similarity index 100% rename from pgtbl/TBLSessions/models.py rename to pgtbl/TBLSessions/models/tbl_session.py From 788f527c187eee671885c57ae3d432b99c4bf26c Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 01:26:49 -0300 Subject: [PATCH 22/56] Refactoring TBLSession views --- pgtbl/TBLSessions/urls.py | 20 +- pgtbl/TBLSessions/views/__init__.py | 7 + .../views/practical_test_detail_view.py | 87 ++++++ .../practical_test_update_view.py} | 86 +----- .../views/tbl_session_create_view.py | 76 +++++ .../views/tbl_session_delete_view.py | 50 +++ .../views/tbl_session_detail_view.py | 63 ++++ .../views/tbl_session_list_view.py | 56 ++++ .../views/tbl_session_update_view.py | 70 +++++ pgtbl/TBLSessions/views_session.py | 285 ------------------ 10 files changed, 424 insertions(+), 376 deletions(-) create mode 100644 pgtbl/TBLSessions/views/__init__.py create mode 100644 pgtbl/TBLSessions/views/practical_test_detail_view.py rename pgtbl/TBLSessions/{views_practical.py => views/practical_test_update_view.py} (54%) create mode 100644 pgtbl/TBLSessions/views/tbl_session_create_view.py create mode 100644 pgtbl/TBLSessions/views/tbl_session_delete_view.py create mode 100644 pgtbl/TBLSessions/views/tbl_session_detail_view.py create mode 100644 pgtbl/TBLSessions/views/tbl_session_list_view.py create mode 100644 pgtbl/TBLSessions/views/tbl_session_update_view.py delete mode 100644 pgtbl/TBLSessions/views_session.py diff --git a/pgtbl/TBLSessions/urls.py b/pgtbl/TBLSessions/urls.py index e4410f3..bd44432 100644 --- a/pgtbl/TBLSessions/urls.py +++ b/pgtbl/TBLSessions/urls.py @@ -1,5 +1,5 @@ from django.conf.urls import url, include -from . import views_session, views_practical +from . import views app_name = 'TBLSessions' @@ -7,31 +7,31 @@ # / url( r'^$', - views_session.ListTBLSessionView.as_view(), + views.TBLSessionListView.as_view(), name='list' ), # add/ url( - r'^add/$', - views_session.CreateSessionView.as_view(), + r'^create/$', + views.TBLSessionCreateView.as_view(), name='create' ), # /edit/ url( - r'^(?P[0-9]+)/edit/$', - views_session.EditSessionView.as_view(), + r'^(?P[0-9]+)/update/$', + views.TBLSessionUpdateView.as_view(), name='update' ), # /delete/ url( r'^(?P[0-9]+)/delete/$', - views_session.DeleteSessionView.as_view(), + views.TBLSessionDeleteView.as_view(), name='delete' ), # /details/ url( r'^(?P[0-9]+)/details/$', - views_session.ShowSessionView.as_view(), + views.TBLSessionDetailView.as_view(), name='details' ), ] @@ -40,13 +40,13 @@ # practical-test/ url( r'^practical-test/$', - views_practical.PracticalTestDetailView.as_view(), + views.PracticalTestDetailView.as_view(), name='practical-details' ), # practical-test/edit/ url( r'^practical-test/edit/$', - views_practical.PracticalTestUpdateView.as_view(), + views.PracticalTestUpdateView.as_view(), name='practical-update' ), ] diff --git a/pgtbl/TBLSessions/views/__init__.py b/pgtbl/TBLSessions/views/__init__.py new file mode 100644 index 0000000..6873f34 --- /dev/null +++ b/pgtbl/TBLSessions/views/__init__.py @@ -0,0 +1,7 @@ +from .practical_test_detail_view import PracticalTestDetailView +from .practical_test_update_view import PracticalTestUpdateView +from .tbl_session_create_view import TBLSessionCreateView +from .tbl_session_delete_view import TBLSessionDeleteView +from .tbl_session_detail_view import TBLSessionDetailView +from .tbl_session_update_view import TBLSessionUpdateView +from .tbl_session_list_view import TBLSessionListView diff --git a/pgtbl/TBLSessions/views/practical_test_detail_view.py b/pgtbl/TBLSessions/views/practical_test_detail_view.py new file mode 100644 index 0000000..447f08c --- /dev/null +++ b/pgtbl/TBLSessions/views/practical_test_detail_view.py @@ -0,0 +1,87 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.db.models import Q +from django.views.generic import DetailView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes + + +class PracticalTestDetailView(LoginRequiredMixin, + PermissionMixin, + DetailView): + """ + View to show the practical test. + """ + + template_name = 'TBLSessions/practical_test.html' + context_object_name = 'session' + + permissions_required = [ + 'show_tbl_session', + 'show_practical_test', + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_object(self): + """ + Get the session discipline. + """ + + discipline = self.get_discipline() + + session = TBLSession.objects.get( + Q(discipline=discipline), + Q(pk=self.kwargs.get('pk', '')) + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline into tbl session context. + """ + + session = self.get_object() + irat_datetime, grat_datetime = get_datetimes(session) + + context = super(PracticalTestDetailView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + + return context diff --git a/pgtbl/TBLSessions/views_practical.py b/pgtbl/TBLSessions/views/practical_test_update_view.py similarity index 54% rename from pgtbl/TBLSessions/views_practical.py rename to pgtbl/TBLSessions/views/practical_test_update_view.py index 35a0619..ceea904 100644 --- a/pgtbl/TBLSessions/views_practical.py +++ b/pgtbl/TBLSessions/views/practical_test_update_view.py @@ -3,91 +3,14 @@ from django.core.urlresolvers import reverse_lazy from django.contrib import messages from django.db.models import Q -from django.views.generic import ( - UpdateView, DetailView -) +from django.views.generic import UpdateView # App imports from core.permissions import PermissionMixin from disciplines.models import Discipline -from .models import TBLSession -from .utils import get_datetimes -from .forms import PracticalTestForm - - -class PracticalTestDetailView(LoginRequiredMixin, - PermissionMixin, - DetailView): - """ - View to show the practical test. - """ - - template_name = 'TBLSessions/practical_test.html' - context_object_name = 'session' - - permissions_required = [ - 'show_tbl_session', - 'show_practical_test', - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_object(self): - """ - Get the session discipline. - """ - - discipline = self.get_discipline() - - session = TBLSession.objects.get( - Q(discipline=discipline), - Q(pk=self.kwargs.get('pk', '')) - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline into tbl session context. - """ - - session = self.get_object() - irat_datetime, grat_datetime = get_datetimes(session) - - context = super(PracticalTestDetailView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - return context +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from TBLSessions.forms import PracticalTestForm class PracticalTestUpdateView(LoginRequiredMixin, @@ -144,6 +67,7 @@ def get_context_data(self, **kwargs): context['discipline'] = self.get_discipline() context['irat_datetime'] = irat_datetime context['grat_datetime'] = grat_datetime + return context def form_valid(self, form): diff --git a/pgtbl/TBLSessions/views/tbl_session_create_view.py b/pgtbl/TBLSessions/views/tbl_session_create_view.py new file mode 100644 index 0000000..822008a --- /dev/null +++ b/pgtbl/TBLSessions/views/tbl_session_create_view.py @@ -0,0 +1,76 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.shortcuts import redirect +from django.contrib import messages +from django.views.generic import CreateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.forms import TBLSessionForm + + +class TBLSessionCreateView(LoginRequiredMixin, + PermissionMixin, + CreateView): + """ + View to insert a new tbl session into the discipline. + """ + + model = TBLSession + template_name = 'TBLSessions/list.html' + form_class = TBLSessionForm + + permissions_required = [ + 'monitor_can_change_if_is_teacher' + ] + + def get_discipline(self): + """ + Take the discipline that the tbl session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Receive the form already validated to create a session. + """ + + form.instance.discipline = self.get_discipline() + form.save() + + messages.success(self.request, _('TBL session created successfully.')) + + return super(TBLSessionCreateView, self).form_valid(form) + + def form_invalid(self, form): + """ + Redirect to form with form errors. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the fields correctly.") + ) + + return redirect(self.get_success_url()) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'TBLSessions:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/TBLSessions/views/tbl_session_delete_view.py b/pgtbl/TBLSessions/views/tbl_session_delete_view.py new file mode 100644 index 0000000..abcdc5b --- /dev/null +++ b/pgtbl/TBLSessions/views/tbl_session_delete_view.py @@ -0,0 +1,50 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import DeleteView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession + + +class TBLSessionDeleteView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific tbl session. + """ + + model = TBLSession + + permissions_required = [ + 'monitor_can_change_if_is_teacher' + ] + + def get_discipline(self): + """ + Take the discipline that the tbl session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'TBLSessions:list', + kwargs={'slug': discipline.slug} + ) + + messages.success(self.request, _("TBL session deleted successfully.")) + + return success_url diff --git a/pgtbl/TBLSessions/views/tbl_session_detail_view.py b/pgtbl/TBLSessions/views/tbl_session_detail_view.py new file mode 100644 index 0000000..d4b6a6a --- /dev/null +++ b/pgtbl/TBLSessions/views/tbl_session_detail_view.py @@ -0,0 +1,63 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.db.models import Q +from django.views.generic import DetailView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes + + +class TBLSessionDetailView(LoginRequiredMixin, + PermissionMixin, + DetailView): + """ + View to show a specific tbl session. + """ + + template_name = 'TBLSessions/details.html' + context_object_name = 'session' + permissions_required = [ + 'show_sessions_permission', + 'show_tbl_session' + ] + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_object(self): + """ + Get the session discipline. + """ + + discipline = self.get_discipline() + + session = TBLSession.objects.get( + Q(discipline=discipline), + Q(pk=self.kwargs.get('pk', '')) + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline into tbl session context. + """ + + session = self.get_object() + irat_datetime, grat_datetime = get_datetimes(session) + + context = super(TBLSessionDetailView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + + return context diff --git a/pgtbl/TBLSessions/views/tbl_session_list_view.py b/pgtbl/TBLSessions/views/tbl_session_list_view.py new file mode 100644 index 0000000..d7b9c9b --- /dev/null +++ b/pgtbl/TBLSessions/views/tbl_session_list_view.py @@ -0,0 +1,56 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.forms import TBLSessionForm + + +class TBLSessionListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all discipline tbl sessions. + """ + + template_name = 'TBLSessions/list.html' + paginate_by = 5 + context_object_name = 'sessions' + + permissions_required = [ + 'show_sessions_permission' + ] + + def get_discipline(self): + """ + Take the discipline that the session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert discipline and form into session context data. + """ + + context = super(TBLSessionListView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + context['form'] = TBLSessionForm() + + return context + + def get_queryset(self): + """ + Get the tbl sessions queryset from model database. + """ + + discipline = self.get_discipline() + + sessions = TBLSession.objects.filter(discipline=discipline) + + return sessions diff --git a/pgtbl/TBLSessions/views/tbl_session_update_view.py b/pgtbl/TBLSessions/views/tbl_session_update_view.py new file mode 100644 index 0000000..951de64 --- /dev/null +++ b/pgtbl/TBLSessions/views/tbl_session_update_view.py @@ -0,0 +1,70 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.forms import TBLSessionForm + + +class TBLSessionUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a specific tbl session. + """ + + model = TBLSession + template_name = 'TBLSessions/form.html' + context_object_name = 'session' + form_class = TBLSessionForm + + permissions_required = [ + 'monitor_can_change_if_is_teacher' + ] + + def get_discipline(self): + """ + Take the discipline that the tbl session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_context_data(self, **kwargs): + """ + Insert a discipline inside tbl session form template. + """ + + context = super(TBLSessionUpdateView, self).get_context_data(**kwargs) + context['discipline'] = self.get_discipline() + return context + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('TBL session updated successfully.')) + + return super(TBLSessionUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + + success_url = reverse_lazy( + 'TBLSessions:list', + kwargs={'slug': discipline.slug} + ) + + return success_url diff --git a/pgtbl/TBLSessions/views_session.py b/pgtbl/TBLSessions/views_session.py deleted file mode 100644 index 4db3e1e..0000000 --- a/pgtbl/TBLSessions/views_session.py +++ /dev/null @@ -1,285 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.shortcuts import redirect -from django.contrib import messages -from django.db.models import Q -from django.views.generic import ( - ListView, CreateView, UpdateView, DeleteView, - DetailView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from .models import TBLSession -from .utils import get_datetimes -from .forms import TBLSessionForm - - -class ListTBLSessionView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all discipline tbl sessions. - """ - - template_name = 'TBLSessions/list.html' - paginate_by = 5 - context_object_name = 'sessions' - - permissions_required = [ - 'show_sessions_permission' - ] - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert discipline and form into session context data. - """ - - context = super(ListTBLSessionView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['form'] = TBLSessionForm() - return context - - def get_queryset(self): - """ - Get the tbl sessions queryset from model database. - """ - - discipline = self.get_discipline() - - sessions = TBLSession.objects.filter(discipline=discipline) - - return sessions - - -class CreateSessionView(LoginRequiredMixin, - PermissionMixin, - CreateView): - """ - View to insert a new tbl session into the discipline. - """ - - model = TBLSession - template_name = 'TBLSessions/list.html' - form_class = TBLSessionForm - - permissions_required = [ - 'monitor_can_change_if_is_teacher' - ] - - def get_discipline(self): - """ - Take the discipline that the tbl session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Receive the form already validated to create a session. - """ - - form.instance.discipline = self.get_discipline() - form.save() - - messages.success(self.request, _('TBL session created successfully.')) - - return super(CreateSessionView, self).form_valid(form) - - def form_invalid(self, form): - """ - Redirect to form with form errors. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the fields correctly.") - ) - - return redirect(self.get_success_url()) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'TBLSessions:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class EditSessionView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a specific tbl session. - """ - - model = TBLSession - template_name = 'TBLSessions/form.html' - context_object_name = 'session' - form_class = TBLSessionForm - - permissions_required = [ - 'monitor_can_change_if_is_teacher' - ] - - def get_discipline(self): - """ - Take the discipline that the tbl session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_context_data(self, **kwargs): - """ - Insert a discipline inside tbl session form template. - """ - - context = super(EditSessionView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - return context - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('TBL session updated successfully.')) - - return super(EditSessionView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'TBLSessions:list', - kwargs={'slug': discipline.slug} - ) - - return success_url - - -class DeleteSessionView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific tbl session. - """ - - model = TBLSession - - permissions_required = [ - 'monitor_can_change_if_is_teacher' - ] - - def get_discipline(self): - """ - Take the discipline that the tbl session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - - success_url = reverse_lazy( - 'TBLSessions:list', - kwargs={'slug': discipline.slug} - ) - - messages.success(self.request, _("TBL session deleted successfully.")) - - return success_url - - -class ShowSessionView(LoginRequiredMixin, - PermissionMixin, - DetailView): - """ - View to show a specific tbl session. - """ - - template_name = 'TBLSessions/details.html' - context_object_name = 'session' - permissions_required = [ - 'show_sessions_permission', - 'show_tbl_session' - ] - - def get_discipline(self): - """ - Take the discipline that the session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_object(self): - """ - Get the session discipline. - """ - - discipline = self.get_discipline() - - session = TBLSession.objects.get( - Q(discipline=discipline), - Q(pk=self.kwargs.get('pk', '')) - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline into tbl session context. - """ - - session = self.get_object() - irat_datetime, grat_datetime = get_datetimes(session) - - context = super(ShowSessionView, self).get_context_data(**kwargs) - context['discipline'] = self.get_discipline() - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - return context From 8445d6e2e4fd55ed64e8a61882eb20ceea301755 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 01:35:55 -0300 Subject: [PATCH 23/56] Refactoring TBLSessions template --- .../css/practical.css => practical_test/css/detail.css} | 0 .../practical_update.css => practical_test/css/update.css} | 0 .../practical_test.html => practical_test/detail.html} | 4 ++-- .../practical_info.html => practical_test/info.html} | 0 .../practical_update.html => practical_test/update.html} | 4 ++-- pgtbl/TBLSessions/tests/__init__.py | 0 pgtbl/TBLSessions/tests/test_practical_detail.py | 2 +- ...{test_create_tbl_session.py => test_tbl_session_create.py} | 2 +- ...{test_delete_tbl_session.py => test_tbl_session_delete.py} | 2 +- .../{test_list_tbl_session.py => test_tbl_session_list.py} | 2 +- ...{test_update_tbl_session.py => test_tbl_session_update.py} | 2 +- pgtbl/TBLSessions/views/practical_test_detail_view.py | 2 +- pgtbl/TBLSessions/views/practical_test_update_view.py | 2 +- 13 files changed, 11 insertions(+), 11 deletions(-) rename pgtbl/TBLSessions/static/{TBLSessions/css/practical.css => practical_test/css/detail.css} (100%) rename pgtbl/TBLSessions/static/{TBLSessions/css/practical_update.css => practical_test/css/update.css} (100%) rename pgtbl/TBLSessions/templates/{TBLSessions/practical_test.html => practical_test/detail.html} (95%) rename pgtbl/TBLSessions/templates/{TBLSessions/practical_info.html => practical_test/info.html} (100%) rename pgtbl/TBLSessions/templates/{TBLSessions/practical_update.html => practical_test/update.html} (94%) create mode 100644 pgtbl/TBLSessions/tests/__init__.py rename pgtbl/TBLSessions/tests/{test_create_tbl_session.py => test_tbl_session_create.py} (97%) rename pgtbl/TBLSessions/tests/{test_delete_tbl_session.py => test_tbl_session_delete.py} (96%) rename pgtbl/TBLSessions/tests/{test_list_tbl_session.py => test_tbl_session_list.py} (96%) rename pgtbl/TBLSessions/tests/{test_update_tbl_session.py => test_tbl_session_update.py} (97%) diff --git a/pgtbl/TBLSessions/static/TBLSessions/css/practical.css b/pgtbl/TBLSessions/static/practical_test/css/detail.css similarity index 100% rename from pgtbl/TBLSessions/static/TBLSessions/css/practical.css rename to pgtbl/TBLSessions/static/practical_test/css/detail.css diff --git a/pgtbl/TBLSessions/static/TBLSessions/css/practical_update.css b/pgtbl/TBLSessions/static/practical_test/css/update.css similarity index 100% rename from pgtbl/TBLSessions/static/TBLSessions/css/practical_update.css rename to pgtbl/TBLSessions/static/practical_test/css/update.css diff --git a/pgtbl/TBLSessions/templates/TBLSessions/practical_test.html b/pgtbl/TBLSessions/templates/practical_test/detail.html similarity index 95% rename from pgtbl/TBLSessions/templates/TBLSessions/practical_test.html rename to pgtbl/TBLSessions/templates/practical_test/detail.html index 8e0de40..8d56077 100644 --- a/pgtbl/TBLSessions/templates/TBLSessions/practical_test.html +++ b/pgtbl/TBLSessions/templates/practical_test/detail.html @@ -4,7 +4,7 @@ {% block css %} - + {% endblock %} {% block breadcrumb %} @@ -65,7 +65,7 @@

data-target="#myModal"> - {% include 'TBLSessions/practical_info.html' %} + {% include 'practical_test/info.html' %} diff --git a/pgtbl/TBLSessions/templates/TBLSessions/practical_info.html b/pgtbl/TBLSessions/templates/practical_test/info.html similarity index 100% rename from pgtbl/TBLSessions/templates/TBLSessions/practical_info.html rename to pgtbl/TBLSessions/templates/practical_test/info.html diff --git a/pgtbl/TBLSessions/templates/TBLSessions/practical_update.html b/pgtbl/TBLSessions/templates/practical_test/update.html similarity index 94% rename from pgtbl/TBLSessions/templates/TBLSessions/practical_update.html rename to pgtbl/TBLSessions/templates/practical_test/update.html index b52d137..bfd40e5 100644 --- a/pgtbl/TBLSessions/templates/TBLSessions/practical_update.html +++ b/pgtbl/TBLSessions/templates/practical_test/update.html @@ -1,11 +1,11 @@ -{% extends 'TBLSessions/practical_test.html' %} +{% extends 'practical_test/detail.html' %} {% load static %} {% load widget_tweaks %} {% load i18n %} {% block css %} - + {{form.media}} {% endblock %} diff --git a/pgtbl/TBLSessions/tests/__init__.py b/pgtbl/TBLSessions/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/TBLSessions/tests/test_practical_detail.py b/pgtbl/TBLSessions/tests/test_practical_detail.py index 3e04ddc..5515f21 100644 --- a/pgtbl/TBLSessions/tests/test_practical_detail.py +++ b/pgtbl/TBLSessions/tests/test_practical_detail.py @@ -8,7 +8,7 @@ User = get_user_model() -class ShowPracticalTestCase(TestCase): +class DetailPracticalTestCase(TestCase): """ Test to show the practical test. """ diff --git a/pgtbl/TBLSessions/tests/test_create_tbl_session.py b/pgtbl/TBLSessions/tests/test_tbl_session_create.py similarity index 97% rename from pgtbl/TBLSessions/tests/test_create_tbl_session.py rename to pgtbl/TBLSessions/tests/test_tbl_session_create.py index 2676232..e0dd595 100644 --- a/pgtbl/TBLSessions/tests/test_create_tbl_session.py +++ b/pgtbl/TBLSessions/tests/test_tbl_session_create.py @@ -8,7 +8,7 @@ User = get_user_model() -class CreateTBLSessionTestCase(TestCase): +class TBLSessionCreateTestCase(TestCase): """ Test to create a new TBL session. """ diff --git a/pgtbl/TBLSessions/tests/test_delete_tbl_session.py b/pgtbl/TBLSessions/tests/test_tbl_session_delete.py similarity index 96% rename from pgtbl/TBLSessions/tests/test_delete_tbl_session.py rename to pgtbl/TBLSessions/tests/test_tbl_session_delete.py index e010114..7d83ec5 100644 --- a/pgtbl/TBLSessions/tests/test_delete_tbl_session.py +++ b/pgtbl/TBLSessions/tests/test_tbl_session_delete.py @@ -8,7 +8,7 @@ User = get_user_model() -class DeleteTBLSessionTestCase(TestCase): +class TBLSessionDeleteTestCase(TestCase): """ Test to delete a new tbl session. """ diff --git a/pgtbl/TBLSessions/tests/test_list_tbl_session.py b/pgtbl/TBLSessions/tests/test_tbl_session_list.py similarity index 96% rename from pgtbl/TBLSessions/tests/test_list_tbl_session.py rename to pgtbl/TBLSessions/tests/test_tbl_session_list.py index 6420024..676dc9e 100644 --- a/pgtbl/TBLSessions/tests/test_list_tbl_session.py +++ b/pgtbl/TBLSessions/tests/test_tbl_session_list.py @@ -8,7 +8,7 @@ User = get_user_model() -class ListTBLSessionTestCase(TestCase): +class TBLSessionListTestCase(TestCase): """ Test to list tbl sessions. """ diff --git a/pgtbl/TBLSessions/tests/test_update_tbl_session.py b/pgtbl/TBLSessions/tests/test_tbl_session_update.py similarity index 97% rename from pgtbl/TBLSessions/tests/test_update_tbl_session.py rename to pgtbl/TBLSessions/tests/test_tbl_session_update.py index 09226bb..9e572b6 100644 --- a/pgtbl/TBLSessions/tests/test_update_tbl_session.py +++ b/pgtbl/TBLSessions/tests/test_tbl_session_update.py @@ -8,7 +8,7 @@ User = get_user_model() -class UpdateTBLSessionTestCase(TestCase): +class TBLSessionUpdateTestCase(TestCase): """ Test to update a TBL session. """ diff --git a/pgtbl/TBLSessions/views/practical_test_detail_view.py b/pgtbl/TBLSessions/views/practical_test_detail_view.py index 447f08c..cdcc3c0 100644 --- a/pgtbl/TBLSessions/views/practical_test_detail_view.py +++ b/pgtbl/TBLSessions/views/practical_test_detail_view.py @@ -18,7 +18,7 @@ class PracticalTestDetailView(LoginRequiredMixin, View to show the practical test. """ - template_name = 'TBLSessions/practical_test.html' + template_name = 'practical_test/detail.html' context_object_name = 'session' permissions_required = [ diff --git a/pgtbl/TBLSessions/views/practical_test_update_view.py b/pgtbl/TBLSessions/views/practical_test_update_view.py index ceea904..0333a7b 100644 --- a/pgtbl/TBLSessions/views/practical_test_update_view.py +++ b/pgtbl/TBLSessions/views/practical_test_update_view.py @@ -21,7 +21,7 @@ class PracticalTestUpdateView(LoginRequiredMixin, """ model = TBLSession - template_name = 'TBLSessions/practical_update.html' + template_name = 'practical_test/update.html' context_object_name = 'session' form_class = PracticalTestForm From 6aaccc9f0d8b1efc17916ed11c165bbb308a77ca Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 01:46:26 -0300 Subject: [PATCH 24/56] Refactoring questions forms --- pgtbl/questions/forms.py | 120 ---------------------- pgtbl/questions/forms/__init__.py | 4 + pgtbl/questions/forms/alternative_form.py | 23 +++++ pgtbl/questions/forms/grat_form.py | 44 ++++++++ pgtbl/questions/forms/irat_form.py | 29 ++++++ pgtbl/questions/forms/question_form.py | 31 ++++++ 6 files changed, 131 insertions(+), 120 deletions(-) delete mode 100644 pgtbl/questions/forms.py create mode 100644 pgtbl/questions/forms/__init__.py create mode 100644 pgtbl/questions/forms/alternative_form.py create mode 100644 pgtbl/questions/forms/grat_form.py create mode 100644 pgtbl/questions/forms/irat_form.py create mode 100644 pgtbl/questions/forms/question_form.py diff --git a/pgtbl/questions/forms.py b/pgtbl/questions/forms.py deleted file mode 100644 index d23358a..0000000 --- a/pgtbl/questions/forms.py +++ /dev/null @@ -1,120 +0,0 @@ -from django.utils.translation import ugettext_lazy as _ -from django import forms -from TBLSessions.models import TBLSession -from .models import Question, Alternative - - -class QuestionForm(forms.ModelForm): - """ - Form to create and update questions. - """ - - class Meta: - model = Question - fields = ['title', 'level', 'topic', 'is_exercise'] - - -class AlternativeForm(forms.ModelForm): - """ - Form to create an alternative with inline formset. - """ - - class Meta: - model = Alternative - fields = ['title', 'is_correct'] - - -# Djanho allows edit a collection of form in the same page. -# extra: controls the number of forms that will apper -AlternativeFormSet = forms.inlineformset_factory( - Question, - Alternative, - form=AlternativeForm, - extra=4, - max_num=4 -) - - -class AnswerQuestionForm(forms.Form): - """ - Form to insert scores from each alternative. - """ - - score = forms.IntegerField( - initial=0, - max_value=4, - min_value=0 - ) - -# # Insert a form to each alternative of question (4 forms) -AnswerQuestionFormSet = forms.formset_factory( - AnswerQuestionForm, - extra=4 -) - - -class IRATForm(forms.ModelForm): - """ - Form to update iRAT duration and weight. - """ - - class Meta: - model = TBLSession - fields = ['irat_duration', 'irat_weight'] - - -class IRATDateForm(forms.ModelForm): - """ - Form to update datetime of iRAT test. - """ - - irat_datetime = forms.DateTimeField( - label=_("Date and time to provide the iRAT test"), - required=False, - input_formats=['%Y-%m-%dT%H:%M'] # '2016-04-06T17:18 - ) - - class Meta: - model = TBLSession - fields = ['irat_datetime'] - -# gRAT -class AnswerGRATQuestionForm(forms.Form): - """ - Form to insert scores from each alternative. - """ - - SCORES = ( - (4, _('4 Points')), - (2, _('2 Points')), - (1, _('1 Point ')), - (0, _('0 Points')) - ) - - score = forms.ChoiceField(choices=SCORES) - - -class GRATForm(forms.ModelForm): - """ - Form to update gRAT duration and weight. - """ - - class Meta: - model = TBLSession - fields = ['grat_duration', 'grat_weight'] - - -class GRATDateForm(forms.ModelForm): - """ - Form to update datetime of gRAT test. - """ - - grat_datetime = forms.DateTimeField( - label=_("Date and time to provide the gRAT test"), - required=False, - input_formats=['%Y-%m-%dT%H:%M'] # '2016-04-06T17:18 - ) - - class Meta: - model = TBLSession - fields = ['grat_datetime'] diff --git a/pgtbl/questions/forms/__init__.py b/pgtbl/questions/forms/__init__.py new file mode 100644 index 0000000..19bf115 --- /dev/null +++ b/pgtbl/questions/forms/__init__.py @@ -0,0 +1,4 @@ +from .alternative_form import AlternativeForm, AlternativeFormSet +from .question_form import QuestionForm, AnswerQuestionForm +from .irat_form import IRATForm, IRATDateForm +from .grat_form import GRATForm, GRATDateForm, AnswerGRATQuestionForm diff --git a/pgtbl/questions/forms/alternative_form.py b/pgtbl/questions/forms/alternative_form.py new file mode 100644 index 0000000..d9a92cd --- /dev/null +++ b/pgtbl/questions/forms/alternative_form.py @@ -0,0 +1,23 @@ +from django import forms +from questions.models import Question, Alternative + + +class AlternativeForm(forms.ModelForm): + """ + Form to create an alternative with inline formset. + """ + + class Meta: + model = Alternative + fields = ['title', 'is_correct'] + + +# Djanho allows edit a collection of form in the same page. +# extra: controls the number of forms that will apper +AlternativeFormSet = forms.inlineformset_factory( + Question, + Alternative, + form=AlternativeForm, + extra=4, + max_num=4 +) diff --git a/pgtbl/questions/forms/grat_form.py b/pgtbl/questions/forms/grat_form.py new file mode 100644 index 0000000..9e2cecd --- /dev/null +++ b/pgtbl/questions/forms/grat_form.py @@ -0,0 +1,44 @@ +from django.utils.translation import ugettext_lazy as _ +from django import forms +from TBLSessions.models import TBLSession + + +class GRATForm(forms.ModelForm): + """ + Form to update gRAT duration and weight. + """ + + class Meta: + model = TBLSession + fields = ['grat_duration', 'grat_weight'] + + +class GRATDateForm(forms.ModelForm): + """ + Form to update datetime of gRAT test. + """ + + grat_datetime = forms.DateTimeField( + label=_("Date and time to provide the gRAT test"), + required=False, + input_formats=['%Y-%m-%dT%H:%M'] # '2016-04-06T17:18 + ) + + class Meta: + model = TBLSession + fields = ['grat_datetime'] + + +class AnswerGRATQuestionForm(forms.Form): + """ + Form to insert scores from each alternative. + """ + + SCORES = ( + (4, _('4 Points')), + (2, _('2 Points')), + (1, _('1 Point ')), + (0, _('0 Points')) + ) + + score = forms.ChoiceField(choices=SCORES) diff --git a/pgtbl/questions/forms/irat_form.py b/pgtbl/questions/forms/irat_form.py new file mode 100644 index 0000000..81c543d --- /dev/null +++ b/pgtbl/questions/forms/irat_form.py @@ -0,0 +1,29 @@ +from django.utils.translation import ugettext_lazy as _ +from django import forms +from TBLSessions.models import TBLSession + + +class IRATForm(forms.ModelForm): + """ + Form to update iRAT duration and weight. + """ + + class Meta: + model = TBLSession + fields = ['irat_duration', 'irat_weight'] + + +class IRATDateForm(forms.ModelForm): + """ + Form to update datetime of iRAT test. + """ + + irat_datetime = forms.DateTimeField( + label=_("Date and time to provide the iRAT test"), + required=False, + input_formats=['%Y-%m-%dT%H:%M'] # '2016-04-06T17:18 + ) + + class Meta: + model = TBLSession + fields = ['irat_datetime'] diff --git a/pgtbl/questions/forms/question_form.py b/pgtbl/questions/forms/question_form.py new file mode 100644 index 0000000..4b375d8 --- /dev/null +++ b/pgtbl/questions/forms/question_form.py @@ -0,0 +1,31 @@ +from django import forms +from questions.models import Question + + +class QuestionForm(forms.ModelForm): + """ + Form to create and update questions. + """ + + class Meta: + model = Question + fields = ['title', 'level', 'topic', 'is_exercise'] + + +class AnswerQuestionForm(forms.Form): + """ + Form to insert scores from each alternative. + """ + + score = forms.IntegerField( + initial=0, + max_value=4, + min_value=0 + ) + + +# Insert a form to each alternative of question (4 forms) +AnswerQuestionFormSet = forms.formset_factory( + AnswerQuestionForm, + extra=4 +) From 50c8a658648413f03972cc35669ab05c7df3ec59 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 02:11:24 -0300 Subject: [PATCH 25/56] Refactoring question models --- pgtbl/questions/models.py | 246 ------------------ pgtbl/questions/models/__init__.py | 5 + pgtbl/questions/models/alternative.py | 51 ++++ pgtbl/questions/models/exercise_submission.py | 51 ++++ pgtbl/questions/models/grat_submission.py | 59 +++++ pgtbl/questions/models/irat_submission.py | 51 ++++ pgtbl/questions/models/question.py | 71 +++++ pgtbl/questions/models/submission.py | 29 +++ 8 files changed, 317 insertions(+), 246 deletions(-) delete mode 100644 pgtbl/questions/models.py create mode 100644 pgtbl/questions/models/__init__.py create mode 100644 pgtbl/questions/models/alternative.py create mode 100644 pgtbl/questions/models/exercise_submission.py create mode 100644 pgtbl/questions/models/grat_submission.py create mode 100644 pgtbl/questions/models/irat_submission.py create mode 100644 pgtbl/questions/models/question.py create mode 100644 pgtbl/questions/models/submission.py diff --git a/pgtbl/questions/models.py b/pgtbl/questions/models.py deleted file mode 100644 index d3f81a9..0000000 --- a/pgtbl/questions/models.py +++ /dev/null @@ -1,246 +0,0 @@ -from django.utils.translation import ugettext_lazy as _ -from django.conf import settings -from django.db import models - -from TBLSessions.models import TBLSession -from groups.models import Group - - -class Question(models.Model): - """ - Create questions to insert into list of exercises and evaluations. - """ - - title = models.CharField( - _('Title'), - max_length=1000, - help_text=_('Question title.') - ) - - session = models.ForeignKey( - TBLSession, - on_delete=models.CASCADE, - related_name='questions' - ) - - LEVELS = [ - (_('Basic'), _('Basic')), - (_('Intermediary'), _('Intermediary')), - (_('Advanced'), _('Advanced')), - ] - - level = models.CharField( - _('Level'), - max_length=15, - choices=LEVELS, - default='basic', - help_text=_('Difficulty level') - ) - - topic = models.CharField( - _('Topic'), - max_length=100, - help_text=_('Question topic.') - ) - - is_exercise = models.BooleanField( - _('Is it an exercise?'), - default=True, - help_text=_('Exercise are questions that appear in the exercise list.') - ) - - created_at = models.DateTimeField( - _('Created at'), - help_text=_("Date that the question is created."), - auto_now_add=True - ) - - updated_at = models.DateTimeField( - _('Updated at'), - help_text=_("Date that the question is updated."), - auto_now=True - ) - - def __str__(self): - """ - Question string. - """ - - return self.title - - class Meta: - verbose_name = _('Question') - verbose_name_plural = _('Questions') - ordering = ['title', 'created_at'] - - -class Alternative(models.Model): - """ - Question alternatives. - """ - - title = models.CharField( - _('Title'), - max_length=1000, - help_text=_('Alternative title.') - ) - - is_correct = models.BooleanField( - _('Is correct?'), - default=False, - help_text=_('Is correct alternative to answer the question.') - ) - - question = models.ForeignKey( - Question, - on_delete=models.CASCADE, - related_name='alternatives' - ) - - created_at = models.DateTimeField( - _('Created at'), - help_text=_("Date that the alternative of question is created."), - auto_now_add=True - ) - - updated_at = models.DateTimeField( - _('Updated at'), - help_text=_("Date that the alternative of question is updated."), - auto_now=True - ) - - def __str__(self): - """ - Alternative of question string. - """ - - return self.title - - class Meta: - verbose_name = _('Alternative') - verbose_name_plural = _('Alternatives') - ordering = ['title', 'created_at'] - - -class Submission(models.Model): - """ - Store all submissions for a given question. - """ - - session = models.ForeignKey( - TBLSession, - on_delete=models.CASCADE, - verbose_name=_("TBL sessions"), - related_name="exercise_submissions" - ) - - question = models.ForeignKey( - Question, - on_delete=models.CASCADE, - verbose_name=_("Questions"), - related_name="exercise_submissions" - ) - - user = models.ForeignKey( - settings.AUTH_USER_MODEL, - on_delete=models.CASCADE, - verbose_name=_('Users'), - related_name="exercise_submissions" - ) - - correct_alternative = models.CharField( - _('Correct Alternative'), - max_length=1000, - help_text=_('Correct alternative title.') - ) - - score = models.PositiveIntegerField( - _("Score"), - default=0, - help_text=_("Question score answered."), - ) - - created_at = models.DateTimeField( - _('Created at'), - help_text=_("Date that the submission of question is created."), - auto_now_add=True - ) - - -class ExerciseSubmission(Submission): - """ - Store all submissions for a given exercise question. - """ - - def __str__(self): - """ - Alternative of question string. - """ - - obj = "{0}: {1} - {2}".format( - self.user.get_short_name(), - self.question, - self.score - ) - - return obj - - class Meta: - verbose_name = _('Exercise Submission') - verbose_name_plural = _('Exercise Submissions') - ordering = ['user', 'question', 'created_at'] - - -class IRATSubmission(Submission): - """ - Store all submissions for a given iRAT question. - """ - - def __str__(self): - """ - Alternative of question string. - """ - - obj = "{0}: {1} - {2}".format( - self.user.get_short_name(), - self.question, - self.score - ) - - return obj - - class Meta: - verbose_name = _('iRAT Submission') - verbose_name_plural = _('iRAT Submissions') - ordering = ['user', 'question', 'created_at'] - - -class GRATSubmission(Submission): - """ - Store all submissions for a given gRAT question. - """ - - group = models.ForeignKey( - Group, - on_delete=models.CASCADE, - verbose_name=_('Groups'), - related_name="submissions" - ) - - def __str__(self): - """ - Alternative of question string. - """ - - obj = "{0}: {1} - {2}".format( - self.group.title, - self.question, - self.score - ) - - return obj - - class Meta: - verbose_name = _('gRAT Submission') - verbose_name_plural = _('gRAT Submissions') - ordering = ['group', 'question', 'created_at'] diff --git a/pgtbl/questions/models/__init__.py b/pgtbl/questions/models/__init__.py new file mode 100644 index 0000000..90b1d90 --- /dev/null +++ b/pgtbl/questions/models/__init__.py @@ -0,0 +1,5 @@ +from .alternative import Alternative +from .question import Question +from .exercise_submission import ExerciseSubmission +from .irat_submission import IRATSubmission +from .grat_submission import GRATSubmission diff --git a/pgtbl/questions/models/alternative.py b/pgtbl/questions/models/alternative.py new file mode 100644 index 0000000..7bb9b51 --- /dev/null +++ b/pgtbl/questions/models/alternative.py @@ -0,0 +1,51 @@ +from django.utils.translation import ugettext_lazy as _ +from django.db import models +from .question import Question + + +class Alternative(models.Model): + """ + Question alternatives. + """ + + title = models.CharField( + _('Title'), + max_length=1000, + help_text=_('Alternative title.') + ) + + is_correct = models.BooleanField( + _('Is correct?'), + default=False, + help_text=_('Is correct alternative to answer the question.') + ) + + question = models.ForeignKey( + Question, + on_delete=models.CASCADE, + related_name='alternatives' + ) + + created_at = models.DateTimeField( + _('Created at'), + help_text=_("Date that the alternative of question is created."), + auto_now_add=True + ) + + updated_at = models.DateTimeField( + _('Updated at'), + help_text=_("Date that the alternative of question is updated."), + auto_now=True + ) + + def __str__(self): + """ + Alternative of question string. + """ + + return self.title + + class Meta: + verbose_name = _('Alternative') + verbose_name_plural = _('Alternatives') + ordering = ['title', 'created_at'] diff --git a/pgtbl/questions/models/exercise_submission.py b/pgtbl/questions/models/exercise_submission.py new file mode 100644 index 0000000..5874d3f --- /dev/null +++ b/pgtbl/questions/models/exercise_submission.py @@ -0,0 +1,51 @@ +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.db import models +from TBLSessions.models import TBLSession +from .question import Question +from .submission import Submission + + +class ExerciseSubmission(Submission): + """ + Store all submissions for a given exercise question. + """ + + session = models.ForeignKey( + TBLSession, + on_delete=models.CASCADE, + verbose_name=_("TBL sessions"), + related_name="exercise_submissions" + ) + + question = models.ForeignKey( + Question, + on_delete=models.CASCADE, + verbose_name=_("Questions"), + related_name="exercise_submissions" + ) + + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name=_('Users'), + related_name="exercise_submissions" + ) + + def __str__(self): + """ + Alternative of question string. + """ + + obj = "{0}: {1} - {2}".format( + self.user.get_short_name(), + self.question, + self.score + ) + + return obj + + class Meta: + verbose_name = _('Exercise Submission') + verbose_name_plural = _('Exercise Submissions') + ordering = ['user', 'question', 'created_at'] diff --git a/pgtbl/questions/models/grat_submission.py b/pgtbl/questions/models/grat_submission.py new file mode 100644 index 0000000..f9f4e49 --- /dev/null +++ b/pgtbl/questions/models/grat_submission.py @@ -0,0 +1,59 @@ +from django.utils.translation import ugettext_lazy as _ +from django.db import models +from django.conf import settings +from groups.models import Group +from TBLSessions.models import TBLSession +from .question import Question +from .submission import Submission + + +class GRATSubmission(Submission): + """ + Store all submissions for a given gRAT question. + """ + + session = models.ForeignKey( + TBLSession, + on_delete=models.CASCADE, + verbose_name=_("TBL sessions"), + related_name="grat_submissions" + ) + + question = models.ForeignKey( + Question, + on_delete=models.CASCADE, + verbose_name=_("Questions"), + related_name="grat_submissions" + ) + + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name=_('Users'), + related_name="grat_submissions" + ) + + group = models.ForeignKey( + Group, + on_delete=models.CASCADE, + verbose_name=_('Groups'), + related_name="submissions" + ) + + def __str__(self): + """ + Alternative of question string. + """ + + obj = "{0}: {1} - {2}".format( + self.group.title, + self.question, + self.score + ) + + return obj + + class Meta: + verbose_name = _('gRAT Submission') + verbose_name_plural = _('gRAT Submissions') + ordering = ['group', 'question', 'created_at'] diff --git a/pgtbl/questions/models/irat_submission.py b/pgtbl/questions/models/irat_submission.py new file mode 100644 index 0000000..9947f43 --- /dev/null +++ b/pgtbl/questions/models/irat_submission.py @@ -0,0 +1,51 @@ +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.db import models +from TBLSessions.models import TBLSession +from .question import Question +from .submission import Submission + + +class IRATSubmission(Submission): + """ + Store all submissions for a given iRAT question. + """ + + session = models.ForeignKey( + TBLSession, + on_delete=models.CASCADE, + verbose_name=_("TBL sessions"), + related_name="irat_submissions" + ) + + question = models.ForeignKey( + Question, + on_delete=models.CASCADE, + verbose_name=_("Questions"), + related_name="irat_submissions" + ) + + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + verbose_name=_('Users'), + related_name="irat_submissions" + ) + + def __str__(self): + """ + Alternative of question string. + """ + + obj = "{0}: {1} - {2}".format( + self.user.get_short_name(), + self.question, + self.score + ) + + return obj + + class Meta: + verbose_name = _('iRAT Submission') + verbose_name_plural = _('iRAT Submissions') + ordering = ['user', 'question', 'created_at'] diff --git a/pgtbl/questions/models/question.py b/pgtbl/questions/models/question.py new file mode 100644 index 0000000..cd2c329 --- /dev/null +++ b/pgtbl/questions/models/question.py @@ -0,0 +1,71 @@ +from django.utils.translation import ugettext_lazy as _ +from django.db import models +from TBLSessions.models import TBLSession + + +class Question(models.Model): + """ + Create questions to insert into list of exercises and evaluations. + """ + + title = models.CharField( + _('Title'), + max_length=1000, + help_text=_('Question title.') + ) + + session = models.ForeignKey( + TBLSession, + on_delete=models.CASCADE, + related_name='questions' + ) + + LEVELS = [ + (_('Basic'), _('Basic')), + (_('Intermediary'), _('Intermediary')), + (_('Advanced'), _('Advanced')), + ] + + level = models.CharField( + _('Level'), + max_length=15, + choices=LEVELS, + default='basic', + help_text=_('Difficulty level') + ) + + topic = models.CharField( + _('Topic'), + max_length=100, + help_text=_('Question topic.') + ) + + is_exercise = models.BooleanField( + _('Is it an exercise?'), + default=True, + help_text=_('Exercise are questions that appear in the exercise list.') + ) + + created_at = models.DateTimeField( + _('Created at'), + help_text=_("Date that the question is created."), + auto_now_add=True + ) + + updated_at = models.DateTimeField( + _('Updated at'), + help_text=_("Date that the question is updated."), + auto_now=True + ) + + def __str__(self): + """ + Question string. + """ + + return self.title + + class Meta: + verbose_name = _('Question') + verbose_name_plural = _('Questions') + ordering = ['title', 'created_at'] diff --git a/pgtbl/questions/models/submission.py b/pgtbl/questions/models/submission.py new file mode 100644 index 0000000..4dbebcc --- /dev/null +++ b/pgtbl/questions/models/submission.py @@ -0,0 +1,29 @@ +from django.utils.translation import ugettext_lazy as _ +from django.db import models + + +class Submission(models.Model): + """ + Store all submissions for a given question. + """ + + correct_alternative = models.CharField( + _('Correct Alternative'), + max_length=1000, + help_text=_('Correct alternative title.') + ) + + score = models.PositiveIntegerField( + _("Score"), + default=0, + help_text=_("Question score answered."), + ) + + created_at = models.DateTimeField( + _('Created at'), + help_text=_("Date that the submission of question is created."), + auto_now_add=True + ) + + class Meta: + abstract = True From cf35f97166110966eaaaedf68b5732ada92233f2 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 03:07:48 -0300 Subject: [PATCH 26/56] Refactoring questions views --- pgtbl/questions/urls.py | 38 +- pgtbl/questions/views/__init__.py | 18 + .../views/exercise/answer_question_view.py | 201 ++++++ pgtbl/questions/views/exercise/csv.py | 77 +++ .../views/exercise/exercise_result_view.py | 113 ++++ .../views/exercise/reset_exercise_view.py | 89 +++ .../views/grat/grat_answer_question_view.py | 238 +++++++ .../views/grat/grat_date_update_view.py | 95 +++ .../questions/views/grat/grat_result_view.py | 140 ++++ .../questions/views/grat/grat_update_view.py | 61 ++ pgtbl/questions/views/grat/grat_view.py | 108 ++++ .../views/irat/irat_answer_question_view.py | 219 +++++++ .../views/irat/irat_date_update_view.py | 82 +++ .../questions/views/irat/irat_result_view.py | 170 +++++ .../questions/views/irat/irat_update_view.py | 60 ++ pgtbl/questions/views/irat/irat_view.py | 107 ++++ .../views/question/create_question_view.py | 177 +++++ .../views/question/delete_question_view.py | 88 +++ .../views/question/exercise_list_view.py | 81 +++ .../views/question/update_question_view.py | 197 ++++++ pgtbl/questions/views_exercise.py | 466 -------------- pgtbl/questions/views_grat.py | 603 ------------------ pgtbl/questions/views_irat.py | 597 ----------------- pgtbl/questions/views_question.py | 516 --------------- 24 files changed, 2340 insertions(+), 2201 deletions(-) create mode 100644 pgtbl/questions/views/__init__.py create mode 100644 pgtbl/questions/views/exercise/answer_question_view.py create mode 100644 pgtbl/questions/views/exercise/csv.py create mode 100644 pgtbl/questions/views/exercise/exercise_result_view.py create mode 100644 pgtbl/questions/views/exercise/reset_exercise_view.py create mode 100644 pgtbl/questions/views/grat/grat_answer_question_view.py create mode 100644 pgtbl/questions/views/grat/grat_date_update_view.py create mode 100644 pgtbl/questions/views/grat/grat_result_view.py create mode 100644 pgtbl/questions/views/grat/grat_update_view.py create mode 100644 pgtbl/questions/views/grat/grat_view.py create mode 100644 pgtbl/questions/views/irat/irat_answer_question_view.py create mode 100644 pgtbl/questions/views/irat/irat_date_update_view.py create mode 100644 pgtbl/questions/views/irat/irat_result_view.py create mode 100644 pgtbl/questions/views/irat/irat_update_view.py create mode 100644 pgtbl/questions/views/irat/irat_view.py create mode 100644 pgtbl/questions/views/question/create_question_view.py create mode 100644 pgtbl/questions/views/question/delete_question_view.py create mode 100644 pgtbl/questions/views/question/exercise_list_view.py create mode 100644 pgtbl/questions/views/question/update_question_view.py delete mode 100644 pgtbl/questions/views_exercise.py delete mode 100644 pgtbl/questions/views_grat.py delete mode 100644 pgtbl/questions/views_irat.py delete mode 100644 pgtbl/questions/views_question.py diff --git a/pgtbl/questions/urls.py b/pgtbl/questions/urls.py index 17769bd..e77973d 100644 --- a/pgtbl/questions/urls.py +++ b/pgtbl/questions/urls.py @@ -1,5 +1,5 @@ from django.conf.urls import url, include -from . import views_question, views_exercise, views_irat, views_grat +from . import views app_name = 'questions' @@ -7,25 +7,25 @@ # / url( r'^$', - views_question.ExerciseListView.as_view(), + views.ExerciseListView.as_view(), name='list' ), # /add-question/ url( r'^add-question/$', - views_question.CreateQuestionView.as_view(), + views.CreateQuestionView.as_view(), name='create-question' ), # /question.id/edit/ url( r'^(?P[0-9]+)/edit/$', - views_question.UpdateQuestionView.as_view(), + views.UpdateQuestionView.as_view(), name='update-question' ), # /question.id/delete/ url( r'^(?P[0-9]+)/delete/$', - views_question.DeleteQuestionView.as_view(), + views.DeleteQuestionView.as_view(), name='delete-question' ), ] @@ -34,25 +34,25 @@ # /result/ url( r'^result/$', - views_exercise.ExerciseResultView.as_view(), + views.ExerciseResultView.as_view(), name='exercise-result' ), # /result/csv/ url( r'^result/csv/$', - views_exercise.get_csv, + views.get_csv, name='exercise-result-csv' ), # /result/reset/ url( r'^result/reset/$', - views_exercise.ResetExerciseView.as_view(), + views.ResetExerciseView.as_view(), name='exercise-reset' ), # /question//answer-page// url( r'^question/(?P[0-9]+)/answer-page/(?P[0-9]+)/$', - views_exercise.AnswerQuestionView.as_view(), + views.AnswerQuestionView.as_view(), name='exercise-answer-question' ) ] @@ -61,31 +61,31 @@ # / url( r'^$', - views_irat.IRATView.as_view(), + views.IRATView.as_view(), name='irat-list' ), # /edit-date/ url( r'^edit-date/$', - views_irat.IRATDateUpdateView.as_view(), + views.IRATDateUpdateView.as_view(), name='irat-date' ), # /edit-irat/ url( r'^edit-irat/$', - views_irat.IRATUpdateView.as_view(), + views.IRATUpdateView.as_view(), name='irat-update' ), # /result/ url( r'^result/$', - views_irat.IRATResultView.as_view(), + views.IRATResultView.as_view(), name='irat-result' ), # /question//answer-page// url( r'^question/(?P[0-9]+)/answer-page/(?P[0-9]+)/$', - views_irat.AnswerIRATQuestionView.as_view(), + views.IRATAnswerQuestionView.as_view(), name='irat-answer-question' ), ] @@ -94,31 +94,31 @@ # / url( r'^$', - views_grat.GRATView.as_view(), + views.GRATView.as_view(), name='grat-list' ), # /edit-date/ url( r'^edit-date/$', - views_grat.GRATDateUpdateView.as_view(), + views.GRATDateUpdateView.as_view(), name='grat-date' ), # /edit-irat/ url( r'^edit-irat/$', - views_grat.GRATUpdateView.as_view(), + views.GRATUpdateView.as_view(), name='grat-update' ), # /result/ url( r'^result/$', - views_grat.GRATResultView.as_view(), + views.GRATResultView.as_view(), name='grat-result' ), # /question//answer-page// url( r'^question/(?P[0-9]+)/answer-page/(?P[0-9]+)/$', - views_grat.AnswerGRATQuestionView.as_view(), + views.GRATAnswerQuestionView.as_view(), name='grat-answer-question' ), ] diff --git a/pgtbl/questions/views/__init__.py b/pgtbl/questions/views/__init__.py new file mode 100644 index 0000000..e4a9fe3 --- /dev/null +++ b/pgtbl/questions/views/__init__.py @@ -0,0 +1,18 @@ +from .exercise.answer_question_view import AnswerQuestionView +from .exercise.csv import get_csv +from .exercise.exercise_result_view import ExerciseResultView +from .exercise.reset_exercise_view import ResetExerciseView +from .grat.grat_answer_question_view import GRATAnswerQuestionView +from .grat.grat_date_update_view import GRATDateUpdateView +from .grat.grat_result_view import GRATResultView +from .grat.grat_update_view import GRATUpdateView +from .grat.grat_view import GRATView +from .irat.irat_answer_question_view import IRATAnswerQuestionView +from .irat.irat_date_update_view import IRATDateUpdateView +from .irat.irat_result_view import IRATResultView +from .irat.irat_update_view import IRATUpdateView +from .irat.irat_view import IRATView +from .question.create_question_view import CreateQuestionView +from .question.delete_question_view import DeleteQuestionView +from .question.exercise_list_view import ExerciseListView +from .question.update_question_view import UpdateQuestionView diff --git a/pgtbl/questions/views/exercise/answer_question_view.py b/pgtbl/questions/views/exercise/answer_question_view.py new file mode 100644 index 0000000..2deff48 --- /dev/null +++ b/pgtbl/questions/views/exercise/answer_question_view.py @@ -0,0 +1,201 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import FormView + +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.models import Question, ExerciseSubmission +from questions.forms import AnswerQuestionForm + + +class AnswerQuestionView(LoginRequiredMixin, FormView): + """ + Answer the respective question. + """ + + template_name = 'questions/list.html' + form_class = AnswerQuestionForm + + # Permissions + permissions_required = [ + 'show_questions_permission' + ] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Get question by url kwargs. + """ + + question = get_object_or_404( + Question, + pk=self.kwargs.get('question_id', '') + ) + + return question + + def get_page(self): + """ + Get the page that the questions is inserted. + """ + + page = self.kwargs.get('question_page', '') + + return page + + def get_success_url(self): + """ + After answer the question go to next page. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'questions:list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + success_url += "?page={0}".format(self.get_page()) + + return success_url + + def post(self, request, *args, **kwargs): + """ + Form to insert scores and answer question. + """ + + question = self.get_object() + + form1 = AnswerQuestionForm(request.POST, prefix="alternative01") + form2 = AnswerQuestionForm(request.POST, prefix="alternative02") + form3 = AnswerQuestionForm(request.POST, prefix="alternative03") + form4 = AnswerQuestionForm(request.POST, prefix="alternative04") + + success = False + + if form1.is_valid() and \ + form2.is_valid() and \ + form3.is_valid() and \ + form4.is_valid(): + + score = self.get_question_score( + question=question, + forms=[form1, form2, form3, form4] + ) + + scores = self.get_form_scores( + forms=[form1, form2, form3, form4] + ) + + success = self.validate_answer(scores, question) + + correct_alternative = None + for alternative in question.alternatives.all(): + if alternative.is_correct: + correct_alternative = alternative + + if success: + messages.success( + self.request, + _("Question answered successfully.") + ) + + ExerciseSubmission.objects.create( + session=self.get_session(), + user=self.request.user, + question=question, + correct_alternative=correct_alternative.title, + score=score + ) + + return redirect(self.get_success_url()) + + def get_question_score(self, question, forms): + """ + Get the score from correct alternative. + """ + + form1, form2, form3, form4 = forms + score = 0 + + if question.alternatives.all()[0].is_correct: + score = int(form1['score'].value()) + elif question.alternatives.all()[1].is_correct: + score = int(form2['score'].value()) + elif question.alternatives.all()[2].is_correct: + score = int(form3['score'].value()) + else: + score = int(form4['score'].value()) + + return score + + def get_form_scores(self, forms): + """ + Get the total scores from forms. + """ + + scores = 0 + + for form in forms: + scores += int(form['score'].value()) + + return scores + + def validate_answer(self, scores, question): + """ + Validate the submission. + """ + + if 0 <= scores <= 4: + + submissions = ExerciseSubmission.objects.filter( + session=self.get_session(), + question=question, + user=self.request.user + ) + + if submissions.count() == 0: + return True + + messages.error( + self.request, + _("You can only submit the question once.") + ) + + return False + + messages.error( + self.request, + _("You only have 4 points to distribute to the \ + 4 alternatives.") + ) + + return False diff --git a/pgtbl/questions/views/exercise/csv.py b/pgtbl/questions/views/exercise/csv.py new file mode 100644 index 0000000..ec23aaf --- /dev/null +++ b/pgtbl/questions/views/exercise/csv.py @@ -0,0 +1,77 @@ +from django.http import HttpResponse +import csv + +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.models import Question, ExerciseSubmission + + +def get_csv(request, *args, **kwargs): + """ + Create a CSV about exercise list result. + """ + + # Create the HttpResponse object with the approprieate CSV headers. + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="exercise-result.csv"' + + # Create the CSV writer + writer = csv.writer(response) + + # Get important variables + discipline = Discipline.objects.get( + slug=kwargs.get('slug', '') + ) + + session = TBLSession.objects.get( + pk=kwargs.get('pk', '') + ) + + questions = Question.objects.filter( + session=session, + is_exercise=True + ) + + submissions = ExerciseSubmission.objects.filter( + session=session, + user=request.user + ) + + score = 0 + total = 4 * questions.count() + + for submission in submissions: + score += submission.score + + grade = (score / total) * 10 + + # Create CSV file rows + writer.writerow([ + 'ID: {0}'.format(request.user.id), + 'Nome: {0}'.format(request.user.get_short_name()), + 'Username: {0}'.format(request.user.username), + 'Tipo de avaliaĆ§Ć£o: ExercĆ­cios', + ]) + writer.writerow([ + 'Disciplina: {0}'.format(discipline.title), + 'Professor: {0}'.format(discipline.teacher), + 'SessĆ£o do TBL: {0}'.format(session.title), + 'Nota no exercicio: {0:.2f}'.format(grade) + ]) + + counter = 0 + for submission in submissions: + counter += 1 + writer.writerow([ + '[{0}]'.format(counter), + 'TĆ­tulo: {0}'.format(submission.question.title), + 'PontuaĆ§Ć£o: {0}/{1}'.format(submission.score, 4) + ]) + + writer.writerow([ + '', + '', + 'PontuaĆ§Ć£o total: {0}/{1}'.format(score, total) + ]) + + return response diff --git a/pgtbl/questions/views/exercise/exercise_result_view.py b/pgtbl/questions/views/exercise/exercise_result_view.py new file mode 100644 index 0000000..0d5951d --- /dev/null +++ b/pgtbl/questions/views/exercise/exercise_result_view.py @@ -0,0 +1,113 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question, ExerciseSubmission + + +class ExerciseResultView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Show the result of exercise list. + """ + + template_name = 'questions/result.html' + context_object_name = 'submissions' + + # Permissions + permissions_required = [ + 'show_questions_permission', + ] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_questions(self): + """ + Get all exercise list questions. + """ + + questions = Question.objects.filter( + session=self.get_session(), + is_exercise=True + ) + + return questions + + def get_context_data(self, **kwargs): + """ + Insert discipline, session into exercise result context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(ExerciseResultView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['result'] = self.result() + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + submissions = ExerciseSubmission.objects.filter( + session=self.get_session(), + user=self.request.user + ) + + return submissions + + def result(self): + """ + Get the total scores about exercise list. + """ + + questions = self.get_questions() + submissions = self.get_queryset() + + score = 0 + grade = 0 + + total = 4 * questions.count() + + for submission in submissions: + score += submission.score + + if total > 0: + grade = (score / total) * 10 + + result = { + 'score': score, + 'total': total, + 'grade': "{0:.2f}".format(grade) + } + + return result diff --git a/pgtbl/questions/views/exercise/reset_exercise_view.py b/pgtbl/questions/views/exercise/reset_exercise_view.py new file mode 100644 index 0000000..ee71328 --- /dev/null +++ b/pgtbl/questions/views/exercise/reset_exercise_view.py @@ -0,0 +1,89 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import RedirectView +from django.contrib import messages +from django.shortcuts import redirect + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.models import ExerciseSubmission + + +class ResetExerciseView(LoginRequiredMixin, + PermissionMixin, + RedirectView): + """ + Reset the exercise. + """ + + permissions_required = [ + 'show_questions_permission' + ] + + def get_discipline(self): + """ + Get discipline by url slug + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + submissions = ExerciseSubmission.objects.filter( + session=self.get_session(), + user=self.request.user + ) + + return submissions + + def get_success_url(self): + """ + Get the success url to redirect to. + """ + + success_url = reverse_lazy( + 'questions:list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return success_url + + def get(self, request, *args, **kwargs): + """ + Reset exercise list. + """ + + submissions = self.get_queryset() + + for submission in submissions: + submission.delete() + + messages.success( + self.request, + _("Exercise list reseted successfully.") + ) + + return redirect(self.get_success_url()) diff --git a/pgtbl/questions/views/grat/grat_answer_question_view.py b/pgtbl/questions/views/grat/grat_answer_question_view.py new file mode 100644 index 0000000..27888b0 --- /dev/null +++ b/pgtbl/questions/views/grat/grat_answer_question_view.py @@ -0,0 +1,238 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import FormView + +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from groups.models import Group +from questions.models import Question, GRATSubmission +from questions.forms import AnswerGRATQuestionForm + + +class GRATAnswerQuestionView(LoginRequiredMixin, FormView): + """ + Answer the respective gRAT question. + """ + + template_name = 'questions/grat.html' + form_class = AnswerGRATQuestionForm + + # Permissions + permissions_required = [ + 'show_questions_permission', + 'grat_permissions' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_student_group(self): + """ + Get current student group. + """ + + groups = Group.objects.filter( + discipline=self.get_discipline() + ) + + for group in groups: + if self.request.user in group.students.all(): + return group + + def get_object(self): + """ + Get question by url kwargs. + """ + + question = get_object_or_404( + Question, + pk=self.kwargs.get('question_id', '') + ) + + return question + + def get_page(self): + """ + Get the page that the questions is inserted. + """ + + page = self.kwargs.get('question_page', '') + + return page + + def get_success_url(self): + """ + After answer the question the same page. + """ + + success_url = reverse_lazy( + 'questions:grat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + success_url += "?page={0}".format(self.get_page()) + + return success_url + + def post(self, request, *args, **kwargs): + """ + Form to insert scores and answer question. + """ + + question = self.get_object() + + form1 = AnswerGRATQuestionForm(request.POST, prefix="alternative01") + form2 = AnswerGRATQuestionForm(request.POST, prefix="alternative02") + form3 = AnswerGRATQuestionForm(request.POST, prefix="alternative03") + form4 = AnswerGRATQuestionForm(request.POST, prefix="alternative04") + + success = False + + if form1.is_valid() and \ + form2.is_valid() and \ + form3.is_valid() and \ + form4.is_valid(): + + score = self.get_question_score( + question=question, + forms=[form1, form2, form3, form4] + ) + + success = self.validate_answer( + question=question, + forms=[form1, form2, form3, form4] + ) + + correct_alternative = None + for alternative in question.alternatives.all(): + if alternative.is_correct: + correct_alternative = alternative + + if success: + messages.success( + self.request, + _("Question answered successfully.") + ) + + GRATSubmission.objects.create( + session=self.get_session(), + group=self.get_student_group(), + user=self.request.user, + question=question, + correct_alternative=correct_alternative.title, + score=score + ) + + return redirect(self.get_success_url()) + + def get_question_score(self, question, forms): + """ + Get the score from correct alternative. + """ + + form1, form2, form3, form4 = forms + score = 0 + + if question.alternatives.all()[0].is_correct: + score = int(form1['score'].value()) + elif question.alternatives.all()[1].is_correct: + score = int(form2['score'].value()) + elif question.alternatives.all()[2].is_correct: + score = int(form3['score'].value()) + else: + score = int(form4['score'].value()) + + return score + + def validate_answer(self, question, forms): + """ + Validate the submission. + """ + + # Verify is student is in some group + if not self.get_student_group(): + messages.error( + self.request, + _("Student must be in a group to answer the test.") + ) + + return False + + # Verify repeated options + answers = [0, 1, 2, 4] + + for form in forms: + if int(form['score'].value()) in answers: + answers.remove(int(form['score'].value())) + + if len(answers) != 0: + + messages.error( + self.request, + _("You can't repeat the options.") + ) + + return False + + # Verify if has only one submission from the user group + submissions = GRATSubmission.objects.filter( + session=self.get_session(), + question=question, + group=self.get_student_group() + ) + + if submissions.count() != 0: + + messages.error( + self.request, + _("Your group has already answered this question.") + ) + + return False + + return True diff --git a/pgtbl/questions/views/grat/grat_date_update_view.py b/pgtbl/questions/views/grat/grat_date_update_view.py new file mode 100644 index 0000000..f389123 --- /dev/null +++ b/pgtbl/questions/views/grat/grat_date_update_view.py @@ -0,0 +1,95 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import UpdateView +from django.shortcuts import redirect +from django.contrib import messages +from django.utils import timezone + +# App imports +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.forms import GRATDateForm + +# Python imports +from datetime import timedelta + + +class GRATDateUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + Update the gRAT date. + """ + + model = TBLSession + template_name = 'questions/grat.html' + form_class = GRATDateForm + + # Permissions + permissions_required = ['crud_tests'] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + now = timezone.localtime(timezone.now()) + + if form.instance.grat_datetime is None: + + messages.error( + self.request, + _("gRAT date must to be filled in.") + ) + + return redirect(self.get_success_url()) + + if now > form.instance.grat_datetime: + + messages.error( + self.request, + _("gRAT date must to be later than today's date.") + ) + + return redirect(self.get_success_url()) + + if (form.instance.irat_datetime + timedelta(minutes=form.instance.irat_duration)) > form.instance.grat_datetime: + + messages.error( + self.request, + _("gRAT date must to be later than iRAT date with its duration.") + ) + + return redirect(self.get_success_url()) + + messages.success(self.request, _('gRAT date updated successfully.')) + + return super(GRATDateUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + success_url = reverse_lazy( + 'questions:grat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return success_url diff --git a/pgtbl/questions/views/grat/grat_result_view.py b/pgtbl/questions/views/grat/grat_result_view.py new file mode 100644 index 0000000..94d0540 --- /dev/null +++ b/pgtbl/questions/views/grat/grat_result_view.py @@ -0,0 +1,140 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from grades.models import Grade +from groups.models import Group +from questions.models import Question, GRATSubmission + + +class GRATResultView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Show the result of gRAT test. + """ + + template_name = 'questions/grat_result.html' + context_object_name = 'submissions' + + # Permissions + permissions_required = [ + 'show_questions_permission' + ] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_questions(self): + """ + Get all exercise list questions. + """ + + questions = Question.objects.filter( + session=self.get_session(), + is_exercise=False + ) + + return questions + + def get_student_group(self): + """ + Get current student group. + """ + + groups = Group.objects.filter( + discipline=self.get_discipline() + ) + + for group in groups: + if self.request.user in group.students.all(): + return group + + def get_context_data(self, **kwargs): + """ + Insert discipline, session into gRAT result context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(GRATResultView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['result'] = self.result() + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + submissions = GRATSubmission.objects.filter( + session=self.get_session(), + group=self.get_student_group() + ) + + return submissions + + def result(self): + """ + Get the total scores about gRAT test and distribute for all students + from group. + """ + + questions = self.get_questions() + submissions = self.get_queryset() + + # Calcule the grade + score = 0 + grade = 0 + + total = 4 * questions.count() + + for submission in submissions: + score += submission.score + + if total > 0: + grade = (score / total) * 10 + + grades = Grade.objects.filter( + session=self.get_session(), + group=self.get_student_group() + ) + + for student_grade in grades: + student_grade.grat = grade + student_grade.save() + + # Store the result and return it + result = { + 'score': score, + 'total': total, + 'grade': "{0:.2f}".format(grade) + } + + return result diff --git a/pgtbl/questions/views/grat/grat_update_view.py b/pgtbl/questions/views/grat/grat_update_view.py new file mode 100644 index 0000000..aa4c58b --- /dev/null +++ b/pgtbl/questions/views/grat/grat_update_view.py @@ -0,0 +1,61 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +# App imports +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.forms import GRATForm + + +class GRATUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + Update the gRAT duration and weight + """ + + model = TBLSession + template_name = 'questions/grat.html' + form_class = GRATForm + + # Permissions + permissions_required = ['crud_tests'] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('gRAT updated successfully.')) + + return super(GRATUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + success_url = reverse_lazy( + 'questions:grat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return success_url diff --git a/pgtbl/questions/views/grat/grat_view.py b/pgtbl/questions/views/grat/grat_view.py new file mode 100644 index 0000000..e9c5cfd --- /dev/null +++ b/pgtbl/questions/views/grat/grat_view.py @@ -0,0 +1,108 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.views.generic import ListView +from django.contrib import messages + +# App imports +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question +from questions.forms import AnswerGRATQuestionForm, GRATDateForm, GRATForm + + +class GRATView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + gRAT (Group Readiness Assurance Test) + """ + + template_name = 'questions/grat.html' + paginate_by = 1 + context_object_name = 'questions' + + # Permissions + permissions_required = [ + 'show_questions_permission', + 'grat_permissions' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline, session and form into gRAT context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(GRATView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['date_form'] = GRATDateForm() + context['grat_form'] = GRATForm() + context['form1'] = AnswerGRATQuestionForm(prefix="alternative01") + context['form2'] = AnswerGRATQuestionForm(prefix="alternative02") + context['form3'] = AnswerGRATQuestionForm(prefix="alternative03") + context['form4'] = AnswerGRATQuestionForm(prefix="alternative04") + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + session = self.get_session() + + questions = Question.objects.filter( + session=session, + is_exercise=False + ) + + return questions diff --git a/pgtbl/questions/views/irat/irat_answer_question_view.py b/pgtbl/questions/views/irat/irat_answer_question_view.py new file mode 100644 index 0000000..9d5967f --- /dev/null +++ b/pgtbl/questions/views/irat/irat_answer_question_view.py @@ -0,0 +1,219 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import FormView + +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.models import Question, IRATSubmission +from questions.forms import AnswerQuestionForm + + +class IRATAnswerQuestionView(LoginRequiredMixin, FormView): + """ + Answer the respective iRAT question. + """ + + template_name = 'questions/irat-list.html' + form_class = AnswerQuestionForm + + # Permissions + permissions_required = [ + 'show_questions_permission', + 'irat_permissions' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Get question by url kwargs. + """ + + question = get_object_or_404( + Question, + pk=self.kwargs.get('question_id', '') + ) + + return question + + def get_page(self): + """ + Get the page that the questions is inserted. + """ + + page = self.kwargs.get('question_page', '') + + return page + + def get_success_url(self): + """ + After answer the question the same page. + """ + + success_url = reverse_lazy( + 'questions:irat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + success_url += "?page={0}".format(self.get_page()) + + return success_url + + def post(self, request, *args, **kwargs): + """ + Form to insert scores and answer question. + """ + + question = self.get_object() + + form1 = AnswerQuestionForm(request.POST, prefix="alternative01") + form2 = AnswerQuestionForm(request.POST, prefix="alternative02") + form3 = AnswerQuestionForm(request.POST, prefix="alternative03") + form4 = AnswerQuestionForm(request.POST, prefix="alternative04") + + success = False + + if form1.is_valid() and \ + form2.is_valid() and \ + form3.is_valid() and \ + form4.is_valid(): + + score = self.get_question_score( + question=question, + forms=[form1, form2, form3, form4] + ) + + scores = self.get_form_scores( + forms=[form1, form2, form3, form4] + ) + + success = self.validate_answer(scores, question) + + correct_alternative = None + for alternative in question.alternatives.all(): + if alternative.is_correct: + correct_alternative = alternative + + if success: + messages.success( + self.request, + _("Question answered successfully.") + ) + + IRATSubmission.objects.create( + session=self.get_session(), + user=self.request.user, + question=question, + correct_alternative=correct_alternative.title, + score=score + ) + + return redirect(self.get_success_url()) + + def get_question_score(self, question, forms): + """ + Get the score from correct alternative. + """ + + form1, form2, form3, form4 = forms + score = 0 + + if question.alternatives.all()[0].is_correct: + score = int(form1['score'].value()) + elif question.alternatives.all()[1].is_correct: + score = int(form2['score'].value()) + elif question.alternatives.all()[2].is_correct: + score = int(form3['score'].value()) + else: + score = int(form4['score'].value()) + + return score + + def get_form_scores(self, forms): + """ + Get the total scores from forms. + """ + + scores = 0 + + for form in forms: + scores += int(form['score'].value()) + + return scores + + def validate_answer(self, scores, question): + """ + Validate the submission. + """ + + if 0 <= scores <= 4: + + submissions = IRATSubmission.objects.filter( + session=self.get_session(), + question=question, + user=self.request.user + ) + + if submissions.count() == 0: + return True + + messages.error( + self.request, + _("You can only submit the question once.") + ) + + return False + + messages.error( + self.request, + _("You only have 4 points to distribute to the \ + 4 alternatives.") + ) + + return False diff --git a/pgtbl/questions/views/irat/irat_date_update_view.py b/pgtbl/questions/views/irat/irat_date_update_view.py new file mode 100644 index 0000000..52e2fe3 --- /dev/null +++ b/pgtbl/questions/views/irat/irat_date_update_view.py @@ -0,0 +1,82 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import redirect +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.utils import timezone +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.forms import IRATDateForm + + +class IRATDateUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + Update the iRAT date. + """ + + model = TBLSession + template_name = 'questions/irat.html' + form_class = IRATDateForm + + # Permissions + permissions_required = ['crud_tests'] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + now = timezone.localtime(timezone.now()) + + if form.instance.irat_datetime is None: + + messages.error( + self.request, + _("iRAT date must to be filled in.") + ) + + return redirect(self.get_success_url()) + + if now > form.instance.irat_datetime: + + messages.error( + self.request, + _("iRAT date must to be later than today's date.") + ) + + return redirect(self.get_success_url()) + + messages.success(self.request, _('iRAT date updated successfully.')) + + return super(IRATDateUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + success_url = reverse_lazy( + 'questions:irat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return success_url diff --git a/pgtbl/questions/views/irat/irat_result_view.py b/pgtbl/questions/views/irat/irat_result_view.py new file mode 100644 index 0000000..dce3b16 --- /dev/null +++ b/pgtbl/questions/views/irat/irat_result_view.py @@ -0,0 +1,170 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from grades.models import Grade +from groups.models import Group +from questions.models import Question, IRATSubmission + + +class IRATResultView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + Show the result of iRAT test. + """ + + template_name = 'questions/irat_result.html' + context_object_name = 'submissions' + + # Permissions + permissions_required = [ + 'show_questions_permission', + 'show_test_result' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("The results only be available when gRAT is done.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_questions(self): + """ + Get all exercise list questions. + """ + + questions = Question.objects.filter( + session=self.get_session(), + is_exercise=False + ) + + return questions + + def get_student_group(self): + """ + Get current student group. + """ + + groups = Group.objects.filter( + discipline=self.get_discipline() + ) + + for group in groups: + if self.request.user in group.students.all(): + return group + + def get_context_data(self, **kwargs): + """ + Insert discipline, session into iRAT result context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(IRATResultView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['result'] = self.result() + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + submissions = IRATSubmission.objects.filter( + session=self.get_session(), + user=self.request.user + ) + + return submissions + + def result(self): + """ + Get the total scores about iRAT. + """ + + questions = self.get_questions() + submissions = self.get_queryset() + + # Calcule the grade + score = 0 + grade = 0 + + total = 4 * questions.count() + + for submission in submissions: + score += submission.score + + if total > 0: + grade = (score / total) * 10 + + # Create a grade for specific student + discipline = self.get_discipline() + + grades = Grade.objects.filter( + session=self.get_session(), + student=self.request.user + ) + + if grades.count() == 0 and self.request.user in discipline.students.all(): + Grade.objects.create( + session=self.get_session(), + student=self.request.user, + group=self.get_student_group(), + irat=grade + ) + + # Store the result and return it + result = { + 'score': score, + 'total': total, + 'grade': "{0:.2f}".format(grade) + } + + return result diff --git a/pgtbl/questions/views/irat/irat_update_view.py b/pgtbl/questions/views/irat/irat_update_view.py new file mode 100644 index 0000000..f5cd6b6 --- /dev/null +++ b/pgtbl/questions/views/irat/irat_update_view.py @@ -0,0 +1,60 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.forms import IRATForm + + +class IRATUpdateView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + Update the iRAT duration and weight + """ + + model = TBLSession + template_name = 'questions/irat.html' + form_class = IRATForm + + # Permissions + permissions_required = ['crud_tests'] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def form_valid(self, form): + """ + Return the form with fields valided. + """ + + messages.success(self.request, _('iRAT updated successfully.')) + + return super(IRATUpdateView, self).form_valid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + success_url = reverse_lazy( + 'questions:irat-list', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return success_url diff --git a/pgtbl/questions/views/irat/irat_view.py b/pgtbl/questions/views/irat/irat_view.py new file mode 100644 index 0000000..33bffce --- /dev/null +++ b/pgtbl/questions/views/irat/irat_view.py @@ -0,0 +1,107 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question +from questions.forms import AnswerQuestionForm, IRATDateForm, IRATForm + + +class IRATView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + iRAT (Individual Readiness Assurance Test) + """ + + template_name = 'questions/irat.html' + paginate_by = 1 + context_object_name = 'questions' + + # Permissions + permissions_required = [ + 'show_questions_permission', + 'irat_permissions' + ] + + def get_failure_redirect_path(self): + """ + Get the failure redirect path. + """ + + messages.error( + self.request, + _("You are not authorized to do this action.") + ) + + failure_redirect_path = reverse_lazy( + 'TBLSessions:details', + kwargs={ + 'slug': self.kwargs.get('slug', ''), + 'pk': self.kwargs.get('pk', '') + } + ) + + return failure_redirect_path + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline, session and form into exercise list context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(IRATView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['date_form'] = IRATDateForm() + context['irat_form'] = IRATForm() + context['form1'] = AnswerQuestionForm(prefix="alternative01") + context['form2'] = AnswerQuestionForm(prefix="alternative02") + context['form3'] = AnswerQuestionForm(prefix="alternative03") + context['form4'] = AnswerQuestionForm(prefix="alternative04") + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + session = self.get_session() + + questions = Question.objects.filter( + session=session, + is_exercise=False + ) + + return questions diff --git a/pgtbl/questions/views/question/create_question_view.py b/pgtbl/questions/views/question/create_question_view.py new file mode 100644 index 0000000..fb5f468 --- /dev/null +++ b/pgtbl/questions/views/question/create_question_view.py @@ -0,0 +1,177 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.db import transaction +from django.views.generic import CreateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question +from questions.forms import AlternativeFormSet + + +class CreateQuestionView(LoginRequiredMixin, + PermissionMixin, + CreateView): + """ + View to create a new question with alternatives. + """ + + model = Question + fields = ['title', 'level', 'topic', 'is_exercise'] + template_name = 'questions/add.html' + + permissions_required = [ + 'crud_question_permission' + ] + + def get_discipline(self): + """ + Take the discipline that the question belongs to. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the TBL session that the question belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline and session and alternatives formset into add + question template. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(CreateQuestionView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + + if self.request.POST: + context['alternatives'] = AlternativeFormSet(self.request.POST) + else: + context['alternatives'] = AlternativeFormSet() + + return context + + def form_valid(self, form): + """ + Receive the form already validated to create a new question with + for alternatives to fill. + """ + + form.instance.session = self.get_session() + + context = self.get_context_data() + alternatives = context['alternatives'] + + # Before a view is called, django initializes a transaction. If the + # response return with success, django commits the transaction. If + # there are any exceptions, django roll back the database. + # Atomic allows us to create a block of code within atomicity in the + # database is guaranteed. If the code block runs successfully, the + # modification are inserted into the database, if give an exception + # the modifications are discarted + with transaction.atomic(): + self.object = form.save(commit=False) + + if alternatives.is_valid(): + alternatives.instance = self.object + + success = self.validate_alternatives(alternatives) + + if not success: + return super(CreateQuestionView, self).form_invalid(form) + + form.save() + alternatives.save() + else: + return self.form_invalid(form) + + messages.success(self.request, _('Question created successfully.')) + + return super(CreateQuestionView, self).form_valid(form) + + def validate_alternatives(self, alternatives): + """ + Verify if only one alternative is correct and if it has 4 alternatives. + """ + + counter_true = 0 + counter_false = 0 + + for alternative_form in alternatives: + + if alternative_form.instance.title == '': + + messages.error( + self.request, + _('All the alternatives need to be filled.') + ) + + return False + + if alternative_form.instance.is_correct is True: + counter_true += 1 + else: + counter_false += 1 + + if counter_true > 1 or counter_false == 4: + + messages.error( + self.request, + _('The question only needs one correct alternative, \ + check if there is more than one or no longer insert one') + ) + + return False + + return True + + def form_invalid(self, form): + """ + Redirect to form with form errors. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the questions fields and \ + alternative fields correctly.") + ) + + return super(CreateQuestionView, self).form_invalid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + + success_url = reverse_lazy( + 'questions:list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + return success_url diff --git a/pgtbl/questions/views/question/delete_question_view.py b/pgtbl/questions/views/question/delete_question_view.py new file mode 100644 index 0000000..0b641af --- /dev/null +++ b/pgtbl/questions/views/question/delete_question_view.py @@ -0,0 +1,88 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.views.generic import DeleteView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from questions.models import Question + + +class DeleteQuestionView(LoginRequiredMixin, + PermissionMixin, + DeleteView): + """ + View to delete a specific question. + """ + + model = Question + + permissions_required = [ + 'crud_question_permission' + ] + + def get_discipline(self): + """ + Take the discipline that the tbl session belongs to + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the TBL session that the question belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Take the specific question to delete. + """ + + question = Question.objects.get( + session=self.get_session(), + pk=self.kwargs.get('question_id', '') + ) + + return question + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + question = self.get_object() + + if question.is_exercise: + success_url = reverse_lazy( + 'questions:list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + else: + success_url = reverse_lazy( + 'questions:irat-list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + messages.success(self.request, _("Question deleted successfully.")) + + return success_url diff --git a/pgtbl/questions/views/question/exercise_list_view.py b/pgtbl/questions/views/question/exercise_list_view.py new file mode 100644 index 0000000..17d32e6 --- /dev/null +++ b/pgtbl/questions/views/question/exercise_list_view.py @@ -0,0 +1,81 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic import ListView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question +from questions.forms import AnswerQuestionForm + + +class ExerciseListView(LoginRequiredMixin, + PermissionMixin, + ListView): + """ + View to see all the questions that the students will answer. + """ + + template_name = 'questions/list.html' + paginate_by = 1 + context_object_name = 'questions' + + # Permissions + permissions_required = [ + 'show_questions_permission' + ] + + def get_discipline(self): + """ + Get the discipline from url kwargs. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + get the session from url kwargs. + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_context_data(self, **kwargs): + """ + Insert discipline, session and form into exercise list context data. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(ExerciseListView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + context['form1'] = AnswerQuestionForm(prefix="alternative01") + context['form2'] = AnswerQuestionForm(prefix="alternative02") + context['form3'] = AnswerQuestionForm(prefix="alternative03") + context['form4'] = AnswerQuestionForm(prefix="alternative04") + + return context + + def get_queryset(self): + """ + Get the questions queryset from model database. + """ + + session = self.get_session() + + questions = Question.objects.filter( + session=session, + is_exercise=True + ) + + return questions diff --git a/pgtbl/questions/views/question/update_question_view.py b/pgtbl/questions/views/question/update_question_view.py new file mode 100644 index 0000000..259c44a --- /dev/null +++ b/pgtbl/questions/views/question/update_question_view.py @@ -0,0 +1,197 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse_lazy +from django.contrib import messages +from django.db import transaction +from django.views.generic import UpdateView + +from core.permissions import PermissionMixin +from disciplines.models import Discipline +from TBLSessions.models import TBLSession +from TBLSessions.utils import get_datetimes +from questions.models import Question +from questions.forms import AlternativeFormSet + + +class UpdateQuestionView(LoginRequiredMixin, + PermissionMixin, + UpdateView): + """ + View to update a new question with alternatives. + """ + + model = Question + fields = ['title', 'level', 'topic', 'is_exercise'] + template_name = 'questions/update.html' + + permissions_required = [ + 'crud_question_permission' + ] + + def get_discipline(self): + """ + Take the discipline that the question belongs to. + """ + + discipline = Discipline.objects.get( + slug=self.kwargs.get('slug', '') + ) + + return discipline + + def get_session(self): + """ + Take the TBL session that the question belongs to + """ + + session = TBLSession.objects.get( + pk=self.kwargs.get('pk', '') + ) + + return session + + def get_object(self): + """ + Take the specific question to update. + """ + + question = Question.objects.get( + session=self.get_session(), + pk=self.kwargs.get('question_id', '') + ) + + return question + + def get_context_data(self, **kwargs): + """ + Insert discipline and session and alternatives formset into add + question template. + """ + + irat_datetime, grat_datetime = get_datetimes(self.get_session()) + + context = super(UpdateQuestionView, self).get_context_data(**kwargs) + context['irat_datetime'] = irat_datetime + context['grat_datetime'] = grat_datetime + context['discipline'] = self.get_discipline() + context['session'] = self.get_session() + + if self.request.POST: + context['alternatives'] = AlternativeFormSet( + self.request.POST, + instance=self.object + ) + else: + context['alternatives'] = AlternativeFormSet( + instance=self.object + ) + + return context + + def form_valid(self, form): + """ + Receive the form already validated to update the question with + for alternatives. + """ + + form.instance.session = self.get_session() + + context = self.get_context_data() + alternatives = context['alternatives'] + + with transaction.atomic(): + self.object = form.save(commit=False) + + if alternatives.is_valid(): + alternatives.instance = self.object + + success = self.validate_alternatives(alternatives) + + if not success: + return super(UpdateQuestionView, self).form_invalid(form) + + form.save() + alternatives.save() + else: + return self.form_invalid(form) + + messages.success(self.request, _('Question updated successfully.')) + + return super(UpdateQuestionView, self).form_valid(form) + + def validate_alternatives(self, alternatives): + """ + Verify if only one alternative is correct and if it has 4 alternatives. + """ + + counter_true = 0 + counter_false = 0 + + for alternative_form in alternatives: + + if alternative_form.instance.title == '': + + messages.error( + self.request, + _('All the alternatives need to be filled.') + ) + + return False + + if alternative_form.instance.is_correct is True: + counter_true += 1 + else: + counter_false += 1 + + if counter_true > 1 or counter_false == 4: + + messages.error( + self.request, + _('The question only needs one correct alternative, \ + check if there is more than one or no longer insert one') + ) + + return False + + return True + + def form_invalid(self, form): + """ + Redirect to form with form errors. + """ + + messages.error( + self.request, + _("Invalid fields, please fill in the questions fields and \ + alternative fields correctly.") + ) + + return super(UpdateQuestionView, self).form_invalid(form) + + def get_success_url(self): + """ + Get success url to redirect. + """ + + discipline = self.get_discipline() + session = self.get_session() + question = self.get_object() + + if question.is_exercise: + success_url = reverse_lazy( + 'questions:list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + else: + success_url = reverse_lazy( + 'questions:irat-list', + kwargs={ + 'slug': discipline.slug, + 'pk': session.id + } + ) + + return success_url diff --git a/pgtbl/questions/views_exercise.py b/pgtbl/questions/views_exercise.py deleted file mode 100644 index 385b1ab..0000000 --- a/pgtbl/questions/views_exercise.py +++ /dev/null @@ -1,466 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import get_object_or_404, redirect -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib import messages -from django.views.generic import ( - ListView, FormView, RedirectView -) - -# CSV -from django.http import HttpResponse -import csv - - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from .models import Question, ExerciseSubmission -from .forms import AnswerQuestionForm - - -class AnswerQuestionView(FormView): - """ - Answer the respective question. - """ - - template_name = 'questions/list.html' - form_class = AnswerQuestionForm - - # Permissions - permissions_required = [ - 'show_questions_permission' - ] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Get question by url kwargs. - """ - - question = get_object_or_404( - Question, - pk=self.kwargs.get('question_id', '') - ) - - return question - - def get_page(self): - """ - Get the page that the questions is inserted. - """ - - page = self.kwargs.get('question_page', '') - - return page - - def get_success_url(self): - """ - After answer the question go to next page. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'questions:list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - success_url += "?page={0}".format(self.get_page()) - - return success_url - - def post(self, request, *args, **kwargs): - """ - Form to insert scores and answer question. - """ - - question = self.get_object() - - form1 = AnswerQuestionForm(request.POST, prefix="alternative01") - form2 = AnswerQuestionForm(request.POST, prefix="alternative02") - form3 = AnswerQuestionForm(request.POST, prefix="alternative03") - form4 = AnswerQuestionForm(request.POST, prefix="alternative04") - - success = False - - if form1.is_valid() and \ - form2.is_valid() and \ - form3.is_valid() and \ - form4.is_valid(): - - score = self.get_question_score( - question=question, - forms=[form1, form2, form3, form4] - ) - - scores = self.get_form_scores( - forms=[form1, form2, form3, form4] - ) - - success = self.validate_answer(scores, question) - - correct_alternative = None - for alternative in question.alternatives.all(): - if alternative.is_correct: - correct_alternative = alternative - - if success: - messages.success( - self.request, - _("Question answered successfully.") - ) - - ExerciseSubmission.objects.create( - session=self.get_session(), - user=self.request.user, - question=question, - correct_alternative=correct_alternative.title, - score=score - ) - - return redirect(self.get_success_url()) - - def get_question_score(self, question, forms): - """ - Get the score from correct alternative. - """ - - form1, form2, form3, form4 = forms - score = 0 - - if question.alternatives.all()[0].is_correct: - score = int(form1['score'].value()) - elif question.alternatives.all()[1].is_correct: - score = int(form2['score'].value()) - elif question.alternatives.all()[2].is_correct: - score = int(form3['score'].value()) - else: - score = int(form4['score'].value()) - - return score - - - def get_form_scores(self, forms): - """ - Get the total scores from forms. - """ - - scores = 0 - - for form in forms: - scores += int(form['score'].value()) - - return scores - - - def validate_answer(self, scores, question): - """ - Validate the submission. - """ - - if 0 <= scores <= 4: - - submissions = ExerciseSubmission.objects.filter( - session=self.get_session(), - question=question, - user=self.request.user - ) - - if submissions.count() == 0: - return True - - messages.error( - self.request, - _("You can only submit the question once.") - ) - - return False - - messages.error( - self.request, - _("You only have 4 points to distribute to the \ - 4 alternatives.") - ) - - return False - - -class ExerciseResultView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Show the result of exercise list. - """ - - template_name = 'questions/result.html' - context_object_name = 'submissions' - - # Permissions - permissions_required = [ - 'show_questions_permission', - ] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_questions(self): - """ - Get all exercise list questions. - """ - - questions = Question.objects.filter( - session=self.get_session(), - is_exercise=True - ) - - return questions - - def get_context_data(self, **kwargs): - """ - Insert discipline, session into exercise result context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(ExerciseResultView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['result'] = self.result() - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - submissions = ExerciseSubmission.objects.filter( - session=self.get_session(), - user=self.request.user - ) - - return submissions - - def result(self): - """ - Get the total scores about exercise list. - """ - - questions = self.get_questions() - submissions = self.get_queryset() - - score = 0 - grade = 0 - - total = 4*questions.count() - - for submission in submissions: - score += submission.score - - if total > 0: - grade = (score/total) * 10 - - result = { - 'score': score, - 'total': total, - 'grade': "{0:.2f}".format(grade) - } - - return result - - -class ResetExerciseView(LoginRequiredMixin, - PermissionMixin, - RedirectView): - """ - Reset the exercise. - """ - - permissions_required = [ - 'show_questions_permission' - ] - - def get_discipline(self): - """ - Get discipline by url slug - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - submissions = ExerciseSubmission.objects.filter( - session=self.get_session(), - user=self.request.user - ) - - return submissions - - def get_success_url(self): - """ - Get the success url to redirect to. - """ - - success_url = reverse_lazy( - 'questions:list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return success_url - - def get(self, request, *args, **kwargs): - """ - Reset exercise list. - """ - - submissions = self.get_queryset() - - for submission in submissions: - submission.delete() - - messages.success( - self.request, - _("Exercise list reseted successfully.") - ) - - return redirect(self.get_success_url()) - - -def get_csv(request, *args, **kwargs): - """ - Create a CSV about exercise list result. - """ - - # Create the HttpResponse object with the approprieate CSV headers. - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="exercise-result.csv"' - - # Create the CSV writer - writer = csv.writer(response) - - # Get important variables - discipline = Discipline.objects.get( - slug=kwargs.get('slug', '') - ) - - session = TBLSession.objects.get( - pk=kwargs.get('pk', '') - ) - - questions = Question.objects.filter( - session=session, - is_exercise=True - ) - - submissions = ExerciseSubmission.objects.filter( - session=session, - user=request.user - ) - - score = 0 - total = 4*questions.count() - - for submission in submissions: - score += submission.score - - grade = (score/total) * 10 - - # Create CSV file rows - writer.writerow([ - 'ID: {0}'.format(request.user.id), - 'Nome: {0}'.format(request.user.get_short_name()), - 'Username: {0}'.format(request.user.username), - 'Tipo de avaliaĆ§Ć£o: ExercĆ­cios', - ]) - writer.writerow([ - 'Disciplina: {0}'.format(discipline.title), - 'Professor: {0}'.format(discipline.teacher), - 'SessĆ£o do TBL: {0}'.format(session.title), - 'Nota no exercicio: {0:.2f}'.format(grade) - ]) - - counter = 0 - for submission in submissions: - counter += 1 - writer.writerow([ - '[{0}]'.format(counter), - 'TĆ­tulo: {0}'.format(submission.question.title), - 'PontuaĆ§Ć£o: {0}/{1}'.format(submission.score, 4) - ]) - - writer.writerow([ - '', - '', - 'PontuaĆ§Ć£o total: {0}/{1}'.format(score, total) - ]) - - return response diff --git a/pgtbl/questions/views_grat.py b/pgtbl/questions/views_grat.py deleted file mode 100644 index 5d8ea45..0000000 --- a/pgtbl/questions/views_grat.py +++ /dev/null @@ -1,603 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import get_object_or_404, redirect -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib import messages -from django.utils import timezone -from django.views.generic import ( - ListView, FormView, UpdateView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from grades.models import Grade -from groups.models import Group -from .models import Question, GRATSubmission -from .forms import AnswerGRATQuestionForm, GRATDateForm, GRATForm - -# Python imports -from datetime import timedelta - - -class GRATView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - gRAT (Group Readiness Assurance Test) - """ - - template_name = 'questions/grat.html' - paginate_by = 1 - context_object_name = 'questions' - - # Permissions - permissions_required = [ - 'show_questions_permission', - 'grat_permissions' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline, session and form into gRAT context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(GRATView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['date_form'] = GRATDateForm() - context['grat_form'] = GRATForm() - context['form1'] = AnswerGRATQuestionForm(prefix="alternative01") - context['form2'] = AnswerGRATQuestionForm(prefix="alternative02") - context['form3'] = AnswerGRATQuestionForm(prefix="alternative03") - context['form4'] = AnswerGRATQuestionForm(prefix="alternative04") - - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - session = self.get_session() - - questions = Question.objects.filter( - session=session, - is_exercise=False - ) - - return questions - - -class GRATUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - Update the gRAT duration and weight - """ - - model = TBLSession - template_name = 'questions/grat.html' - form_class = GRATForm - - # Permissions - permissions_required = ['crud_tests'] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('gRAT updated successfully.')) - - return super(GRATUpdateView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - success_url = reverse_lazy( - 'questions:grat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return success_url - - -class GRATDateUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - Update the gRAT date. - """ - - model = TBLSession - template_name = 'questions/grat.html' - form_class = GRATDateForm - - # Permissions - permissions_required = ['crud_tests'] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - now = timezone.localtime(timezone.now()) - - if form.instance.grat_datetime is None: - - messages.error( - self.request, - _("gRAT date must to be filled in.") - ) - - return redirect(self.get_success_url()) - - if now > form.instance.grat_datetime: - - messages.error( - self.request, - _("gRAT date must to be later than today's date.") - ) - - return redirect(self.get_success_url()) - - if (form.instance.irat_datetime + \ - timedelta(minutes=form.instance.irat_duration)) > \ - form.instance.grat_datetime: - - messages.error( - self.request, - _("gRAT date must to be later than iRAT date with its duration.") - ) - - return redirect(self.get_success_url()) - - messages.success(self.request, _('gRAT date updated successfully.')) - - return super(GRATDateUpdateView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - success_url = reverse_lazy( - 'questions:grat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return success_url - -class AnswerGRATQuestionView(FormView): - """ - Answer the respective gRAT question. - """ - - template_name = 'questions/grat.html' - form_class = AnswerGRATQuestionForm - - # Permissions - permissions_required = [ - 'show_questions_permission', - 'grat_permissions' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_student_group(self): - """ - Get current student group. - """ - - groups = Group.objects.filter( - discipline=self.get_discipline() - ) - - for group in groups: - if self.request.user in group.students.all(): - return group - - def get_object(self): - """ - Get question by url kwargs. - """ - - question = get_object_or_404( - Question, - pk=self.kwargs.get('question_id', '') - ) - - return question - - def get_page(self): - """ - Get the page that the questions is inserted. - """ - - page = self.kwargs.get('question_page', '') - - return page - - def get_success_url(self): - """ - After answer the question the same page. - """ - - success_url = reverse_lazy( - 'questions:grat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - success_url += "?page={0}".format(self.get_page()) - - return success_url - - def post(self, request, *args, **kwargs): - """ - Form to insert scores and answer question. - """ - - question = self.get_object() - - form1 = AnswerGRATQuestionForm(request.POST, prefix="alternative01") - form2 = AnswerGRATQuestionForm(request.POST, prefix="alternative02") - form3 = AnswerGRATQuestionForm(request.POST, prefix="alternative03") - form4 = AnswerGRATQuestionForm(request.POST, prefix="alternative04") - - success = False - - if form1.is_valid() and \ - form2.is_valid() and \ - form3.is_valid() and \ - form4.is_valid(): - - score = self.get_question_score( - question=question, - forms=[form1, form2, form3, form4] - ) - - success = self.validate_answer( - question=question, - forms=[form1, form2, form3, form4] - ) - - correct_alternative = None - for alternative in question.alternatives.all(): - if alternative.is_correct: - correct_alternative = alternative - - if success: - messages.success( - self.request, - _("Question answered successfully.") - ) - - GRATSubmission.objects.create( - session=self.get_session(), - group=self.get_student_group(), - user=self.request.user, - question=question, - correct_alternative=correct_alternative.title, - score=score - ) - - return redirect(self.get_success_url()) - - def get_question_score(self, question, forms): - """ - Get the score from correct alternative. - """ - - form1, form2, form3, form4 = forms - score = 0 - - if question.alternatives.all()[0].is_correct: - score = int(form1['score'].value()) - elif question.alternatives.all()[1].is_correct: - score = int(form2['score'].value()) - elif question.alternatives.all()[2].is_correct: - score = int(form3['score'].value()) - else: - score = int(form4['score'].value()) - - return score - - - def validate_answer(self, question, forms): - """ - Validate the submission. - """ - - # Verify is student is in some group - if not self.get_student_group(): - messages.error( - self.request, - _("Student must be in a group to answer the test.") - ) - - return False - - # Verify repeated options - answers = [0, 1, 2, 4] - - for form in forms: - if int(form['score'].value()) in answers: - answers.remove(int(form['score'].value())) - - if len(answers) != 0: - - messages.error( - self.request, - _("You can't repeat the options.") - ) - - return False - - # Verify if has only one submission from the user group - submissions = GRATSubmission.objects.filter( - session=self.get_session(), - question=question, - group=self.get_student_group() - ) - - if submissions.count() != 0: - - messages.error( - self.request, - _("Your group has already answered this question.") - ) - - return False - - return True - - -class GRATResultView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Show the result of gRAT test. - """ - - template_name = 'questions/grat_result.html' - context_object_name = 'submissions' - - # Permissions - permissions_required = [ - 'show_questions_permission' - ] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_questions(self): - """ - Get all exercise list questions. - """ - - questions = Question.objects.filter( - session=self.get_session(), - is_exercise=False - ) - - return questions - - def get_student_group(self): - """ - Get current student group. - """ - - groups = Group.objects.filter( - discipline=self.get_discipline() - ) - - for group in groups: - if self.request.user in group.students.all(): - return group - - def get_context_data(self, **kwargs): - """ - Insert discipline, session into gRAT result context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(GRATResultView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['result'] = self.result() - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - submissions = GRATSubmission.objects.filter( - session=self.get_session(), - group=self.get_student_group() - ) - - return submissions - - def result(self): - """ - Get the total scores about gRAT test and distribute for all students - from group. - """ - - questions = self.get_questions() - submissions = self.get_queryset() - - # Calcule the grade - score = 0 - grade = 0 - - total = 4*questions.count() - - for submission in submissions: - score += submission.score - - if total > 0: - grade = (score/total) * 10 - - grades = Grade.objects.filter( - session=self.get_session(), - group=self.get_student_group() - ) - - for student_grade in grades: - student_grade.grat = grade - student_grade.save() - - # Store the result and return it - result = { - 'score': score, - 'total': total, - 'grade': "{0:.2f}".format(grade) - } - - return result diff --git a/pgtbl/questions/views_irat.py b/pgtbl/questions/views_irat.py deleted file mode 100644 index 9f8315f..0000000 --- a/pgtbl/questions/views_irat.py +++ /dev/null @@ -1,597 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import get_object_or_404, redirect -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib import messages -from django.utils import timezone -from django.views.generic import ( - ListView, FormView, UpdateView -) - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from grades.models import Grade -from groups.models import Group -from .models import Question, IRATSubmission -from .forms import AnswerQuestionForm, IRATDateForm, IRATForm - - -class IRATView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - iRAT (Individual Readiness Assurance Test) - """ - - template_name = 'questions/irat.html' - paginate_by = 1 - context_object_name = 'questions' - - # Permissions - permissions_required = [ - 'show_questions_permission', - 'irat_permissions' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline, session and form into exercise list context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(IRATView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['date_form'] = IRATDateForm() - context['irat_form'] = IRATForm() - context['form1'] = AnswerQuestionForm(prefix="alternative01") - context['form2'] = AnswerQuestionForm(prefix="alternative02") - context['form3'] = AnswerQuestionForm(prefix="alternative03") - context['form4'] = AnswerQuestionForm(prefix="alternative04") - - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - session = self.get_session() - - questions = Question.objects.filter( - session=session, - is_exercise=False - ) - - return questions - - -class IRATUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - Update the iRAT duration and weight - """ - - model = TBLSession - template_name = 'questions/irat.html' - form_class = IRATForm - - # Permissions - permissions_required = ['crud_tests'] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - messages.success(self.request, _('iRAT updated successfully.')) - - return super(IRATUpdateView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - success_url = reverse_lazy( - 'questions:irat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return success_url - - -class IRATDateUpdateView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - Update the iRAT date. - """ - - model = TBLSession - template_name = 'questions/irat.html' - form_class = IRATDateForm - - # Permissions - permissions_required = ['crud_tests'] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def form_valid(self, form): - """ - Return the form with fields valided. - """ - - now = timezone.localtime(timezone.now()) - - if form.instance.irat_datetime is None: - - messages.error( - self.request, - _("iRAT date must to be filled in.") - ) - - return redirect(self.get_success_url()) - - if now > form.instance.irat_datetime: - - messages.error( - self.request, - _("iRAT date must to be later than today's date.") - ) - - return redirect(self.get_success_url()) - - messages.success(self.request, _('iRAT date updated successfully.')) - - return super(IRATDateUpdateView, self).form_valid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - success_url = reverse_lazy( - 'questions:irat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return success_url - -class AnswerIRATQuestionView(FormView): - """ - Answer the respective iRAT question. - """ - - template_name = 'questions/irat-list.html' - form_class = AnswerQuestionForm - - # Permissions - permissions_required = [ - 'show_questions_permission', - 'irat_permissions' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("You are not authorized to do this action.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Get question by url kwargs. - """ - - question = get_object_or_404( - Question, - pk=self.kwargs.get('question_id', '') - ) - - return question - - def get_page(self): - """ - Get the page that the questions is inserted. - """ - - page = self.kwargs.get('question_page', '') - - return page - - def get_success_url(self): - """ - After answer the question the same page. - """ - - success_url = reverse_lazy( - 'questions:irat-list', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - success_url += "?page={0}".format(self.get_page()) - - return success_url - - def post(self, request, *args, **kwargs): - """ - Form to insert scores and answer question. - """ - - question = self.get_object() - - form1 = AnswerQuestionForm(request.POST, prefix="alternative01") - form2 = AnswerQuestionForm(request.POST, prefix="alternative02") - form3 = AnswerQuestionForm(request.POST, prefix="alternative03") - form4 = AnswerQuestionForm(request.POST, prefix="alternative04") - - success = False - - if form1.is_valid() and \ - form2.is_valid() and \ - form3.is_valid() and \ - form4.is_valid(): - - score = self.get_question_score( - question=question, - forms=[form1, form2, form3, form4] - ) - - scores = self.get_form_scores( - forms=[form1, form2, form3, form4] - ) - - success = self.validate_answer(scores, question) - - correct_alternative = None - for alternative in question.alternatives.all(): - if alternative.is_correct: - correct_alternative = alternative - - if success: - messages.success( - self.request, - _("Question answered successfully.") - ) - - IRATSubmission.objects.create( - session=self.get_session(), - user=self.request.user, - question=question, - correct_alternative=correct_alternative.title, - score=score - ) - - return redirect(self.get_success_url()) - - def get_question_score(self, question, forms): - """ - Get the score from correct alternative. - """ - - form1, form2, form3, form4 = forms - score = 0 - - if question.alternatives.all()[0].is_correct: - score = int(form1['score'].value()) - elif question.alternatives.all()[1].is_correct: - score = int(form2['score'].value()) - elif question.alternatives.all()[2].is_correct: - score = int(form3['score'].value()) - else: - score = int(form4['score'].value()) - - return score - - def get_form_scores(self, forms): - """ - Get the total scores from forms. - """ - - scores = 0 - - for form in forms: - scores += int(form['score'].value()) - - return scores - - def validate_answer(self, scores, question): - """ - Validate the submission. - """ - - if 0 <= scores <= 4: - - submissions = IRATSubmission.objects.filter( - session=self.get_session(), - question=question, - user=self.request.user - ) - - if submissions.count() == 0: - return True - - messages.error( - self.request, - _("You can only submit the question once.") - ) - - return False - - messages.error( - self.request, - _("You only have 4 points to distribute to the \ - 4 alternatives.") - ) - - return False - - -class IRATResultView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - Show the result of iRAT test. - """ - - template_name = 'questions/irat_result.html' - context_object_name = 'submissions' - - # Permissions - permissions_required = [ - 'show_questions_permission', - 'show_test_result' - ] - - def get_failure_redirect_path(self): - """ - Get the failure redirect path. - """ - - messages.error( - self.request, - _("The results only be available when gRAT is done.") - ) - - failure_redirect_path = reverse_lazy( - 'TBLSessions:details', - kwargs={ - 'slug': self.kwargs.get('slug', ''), - 'pk': self.kwargs.get('pk', '') - } - ) - - return failure_redirect_path - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_questions(self): - """ - Get all exercise list questions. - """ - - questions = Question.objects.filter( - session=self.get_session(), - is_exercise=False - ) - - return questions - - def get_student_group(self): - """ - Get current student group. - """ - - groups = Group.objects.filter( - discipline=self.get_discipline() - ) - - for group in groups: - if self.request.user in group.students.all(): - return group - - def get_context_data(self, **kwargs): - """ - Insert discipline, session into iRAT result context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(IRATResultView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['result'] = self.result() - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - submissions = IRATSubmission.objects.filter( - session=self.get_session(), - user=self.request.user - ) - - return submissions - - def result(self): - """ - Get the total scores about iRAT. - """ - - questions = self.get_questions() - submissions = self.get_queryset() - - # Calcule the grade - score = 0 - grade = 0 - - total = 4*questions.count() - - for submission in submissions: - score += submission.score - - if total > 0: - grade = (score/total) * 10 - - # Create a grade for specific student - discipline = self.get_discipline() - - grades = Grade.objects.filter( - session=self.get_session(), - student=self.request.user - ) - - if grades.count() == 0 and self.request.user in discipline.students.all(): - Grade.objects.create( - session=self.get_session(), - student=self.request.user, - group=self.get_student_group(), - irat=grade - ) - - # Store the result and return it - result = { - 'score': score, - 'total': total, - 'grade': "{0:.2f}".format(grade) - } - - return result diff --git a/pgtbl/questions/views_question.py b/pgtbl/questions/views_question.py deleted file mode 100644 index d6afc17..0000000 --- a/pgtbl/questions/views_question.py +++ /dev/null @@ -1,516 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse_lazy -from django.contrib import messages -from django.db import transaction -from django.views.generic import ( - ListView, CreateView, UpdateView, DeleteView -) - - -# App imports -from core.permissions import PermissionMixin -from disciplines.models import Discipline -from TBLSessions.models import TBLSession -from TBLSessions.utils import get_datetimes -from .models import Question -from .forms import AlternativeFormSet, AnswerQuestionForm - - -class ExerciseListView(LoginRequiredMixin, - PermissionMixin, - ListView): - """ - View to see all the questions that the students will answer. - """ - - template_name = 'questions/list.html' - paginate_by = 1 - context_object_name = 'questions' - - # Permissions - permissions_required = [ - 'show_questions_permission' - ] - - def get_discipline(self): - """ - Get the discipline from url kwargs. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - get the session from url kwargs. - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline, session and form into exercise list context data. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(ExerciseListView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - context['form1'] = AnswerQuestionForm(prefix="alternative01") - context['form2'] = AnswerQuestionForm(prefix="alternative02") - context['form3'] = AnswerQuestionForm(prefix="alternative03") - context['form4'] = AnswerQuestionForm(prefix="alternative04") - return context - - def get_queryset(self): - """ - Get the questions queryset from model database. - """ - - session = self.get_session() - - questions = Question.objects.filter( - session=session, - is_exercise=True - ) - - return questions - - -class CreateQuestionView(LoginRequiredMixin, - PermissionMixin, - CreateView): - """ - View to create a new question with alternatives. - """ - - model = Question - fields = ['title', 'level', 'topic', 'is_exercise'] - template_name = 'questions/add.html' - - permissions_required = [ - 'crud_question_permission' - ] - - def get_discipline(self): - """ - Take the discipline that the question belongs to. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the TBL session that the question belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_context_data(self, **kwargs): - """ - Insert discipline and session and alternatives formset into add - question template. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(CreateQuestionView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - - if self.request.POST: - context['alternatives'] = AlternativeFormSet(self.request.POST) - else: - context['alternatives'] = AlternativeFormSet() - - return context - - def form_valid(self, form): - """ - Receive the form already validated to create a new question with - for alternatives to fill. - """ - - form.instance.session = self.get_session() - - context = self.get_context_data() - alternatives = context['alternatives'] - - # Before a view is called, django initializes a transaction. If the - # response return with success, django commits the transaction. If - # there are any exceptions, django roll back the database. - # Atomic allows us to create a block of code within atomicity in the - # database is guaranteed. If the code block runs successfully, the - # modification are inserted into the database, if give an exception - # the modifications are discarted - with transaction.atomic(): - self.object = form.save(commit=False) - - if alternatives.is_valid(): - alternatives.instance = self.object - - success = self.validate_alternatives(alternatives) - - if not success: - return super(CreateQuestionView, self).form_invalid(form) - - form.save() - alternatives.save() - else: - return self.form_invalid(form) - - messages.success(self.request, _('Question created successfully.')) - - return super(CreateQuestionView, self).form_valid(form) - - def validate_alternatives(self, alternatives): - """ - Verify if only one alternative is correct and if it has 4 alternatives. - """ - - counter_true = 0 - counter_false = 0 - - for alternative_form in alternatives: - - if alternative_form.instance.title == '': - - messages.error( - self.request, - _('All the alternatives need to be filled.') - ) - - return False - - if alternative_form.instance.is_correct is True: - counter_true += 1 - else: - counter_false += 1 - - if counter_true > 1 or counter_false == 4: - - messages.error( - self.request, - _('The question only needs one correct alternative, \ - check if there is more than one or no longer insert one') - ) - - return False - - return True - - def form_invalid(self, form): - """ - Redirect to form with form errors. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the questions fields and \ - alternative fields correctly.") - ) - - return super(CreateQuestionView, self).form_invalid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - - success_url = reverse_lazy( - 'questions:list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - return success_url - - -class UpdateQuestionView(LoginRequiredMixin, - PermissionMixin, - UpdateView): - """ - View to update a new question with alternatives. - """ - - model = Question - fields = ['title', 'level', 'topic', 'is_exercise'] - template_name = 'questions/update.html' - - permissions_required = [ - 'crud_question_permission' - ] - - def get_discipline(self): - """ - Take the discipline that the question belongs to. - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the TBL session that the question belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Take the specific question to update. - """ - - question = Question.objects.get( - session=self.get_session(), - pk=self.kwargs.get('question_id', '') - ) - - return question - - def get_context_data(self, **kwargs): - """ - Insert discipline and session and alternatives formset into add - question template. - """ - - irat_datetime, grat_datetime = get_datetimes(self.get_session()) - - context = super(UpdateQuestionView, self).get_context_data(**kwargs) - context['irat_datetime'] = irat_datetime - context['grat_datetime'] = grat_datetime - context['discipline'] = self.get_discipline() - context['session'] = self.get_session() - - if self.request.POST: - context['alternatives'] = AlternativeFormSet( - self.request.POST, - instance=self.object - ) - else: - context['alternatives'] = AlternativeFormSet( - instance=self.object - ) - - return context - - def form_valid(self, form): - """ - Receive the form already validated to update the question with - for alternatives. - """ - - form.instance.session = self.get_session() - - context = self.get_context_data() - alternatives = context['alternatives'] - - with transaction.atomic(): - self.object = form.save(commit=False) - - if alternatives.is_valid(): - alternatives.instance = self.object - - success = self.validate_alternatives(alternatives) - - if not success: - return super(UpdateQuestionView, self).form_invalid(form) - - form.save() - alternatives.save() - else: - return self.form_invalid(form) - - messages.success(self.request, _('Question updated successfully.')) - - return super(UpdateQuestionView, self).form_valid(form) - - def validate_alternatives(self, alternatives): - """ - Verify if only one alternative is correct and if it has 4 alternatives. - """ - - counter_true = 0 - counter_false = 0 - - for alternative_form in alternatives: - - if alternative_form.instance.title == '': - - messages.error( - self.request, - _('All the alternatives need to be filled.') - ) - - return False - - if alternative_form.instance.is_correct is True: - counter_true += 1 - else: - counter_false += 1 - - if counter_true > 1 or counter_false == 4: - - messages.error( - self.request, - _('The question only needs one correct alternative, \ - check if there is more than one or no longer insert one') - ) - - return False - - return True - - def form_invalid(self, form): - """ - Redirect to form with form errors. - """ - - messages.error( - self.request, - _("Invalid fields, please fill in the questions fields and \ - alternative fields correctly.") - ) - - return super(UpdateQuestionView, self).form_invalid(form) - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - question = self.get_object() - - if question.is_exercise: - success_url = reverse_lazy( - 'questions:list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - else: - success_url = reverse_lazy( - 'questions:irat-list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - - return success_url - - -class DeleteQuestionView(LoginRequiredMixin, - PermissionMixin, - DeleteView): - """ - View to delete a specific question. - """ - - model = Question - - permissions_required = [ - 'crud_question_permission' - ] - - def get_discipline(self): - """ - Take the discipline that the tbl session belongs to - """ - - discipline = Discipline.objects.get( - slug=self.kwargs.get('slug', '') - ) - - return discipline - - def get_session(self): - """ - Take the TBL session that the question belongs to - """ - - session = TBLSession.objects.get( - pk=self.kwargs.get('pk', '') - ) - - return session - - def get_object(self): - """ - Take the specific question to delete. - """ - - question = Question.objects.get( - session=self.get_session(), - pk=self.kwargs.get('question_id', '') - ) - - return question - - def get_success_url(self): - """ - Get success url to redirect. - """ - - discipline = self.get_discipline() - session = self.get_session() - question = self.get_object() - - if question.is_exercise: - success_url = reverse_lazy( - 'questions:list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - else: - success_url = reverse_lazy( - 'questions:irat-list', - kwargs={ - 'slug': discipline.slug, - 'pk': session.id - } - ) - - - messages.success(self.request, _("Question deleted successfully.")) - - return success_url From c7239842cb6a7a1cc6fc1a5bdf1f868e83196f5e Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 03:27:49 -0300 Subject: [PATCH 27/56] Refactoring questions template --- .../irat_info.html => exercise/info.html} | 0 .../{questions => exercise}/list.html | 6 ++--- .../{questions => exercise}/pagination.html | 0 .../{questions => exercise}/progress_bar.html | 0 .../{questions => exercise}/result.html | 0 .../grat_date.html => grat/date.html} | 0 .../templates/{questions => grat}/grat.html | 10 +++---- .../grat_info.html => grat/info.html} | 0 .../pagination.html} | 0 .../templates/grat/progress_bar.html | 12 +++++++++ .../grat_result.html => grat/result.html} | 2 +- .../grat_update.html => grat/update.html} | 0 .../irat_date.html => irat/date.html} | 0 pgtbl/questions/templates/irat/info.html | 27 +++++++++++++++++++ .../templates/{questions => irat}/irat.html | 10 +++---- .../pagination.html} | 0 .../templates/irat/progress_bar.html | 12 +++++++++ .../irat_result.html => irat/result.html} | 2 +- .../irat_update.html => irat/update.html} | 0 pgtbl/questions/templates/questions/add.html | 2 +- .../questions/templates/questions/update.html | 2 +- pgtbl/questions/views/__init__.py | 4 +-- .../views/exercise/answer_question_view.py | 2 +- .../exercise_list_view.py | 2 +- .../views/exercise/exercise_result_view.py | 2 +- .../views/grat/grat_answer_question_view.py | 2 +- .../views/grat/grat_date_update_view.py | 2 +- .../questions/views/grat/grat_result_view.py | 2 +- .../questions/views/grat/grat_update_view.py | 2 +- pgtbl/questions/views/grat/grat_view.py | 2 +- .../views/irat/irat_answer_question_view.py | 2 +- .../views/irat/irat_date_update_view.py | 2 +- .../questions/views/irat/irat_result_view.py | 2 +- .../questions/views/irat/irat_update_view.py | 2 +- pgtbl/questions/views/irat/irat_view.py | 2 +- 35 files changed, 83 insertions(+), 32 deletions(-) rename pgtbl/questions/templates/{questions/irat_info.html => exercise/info.html} (100%) rename pgtbl/questions/templates/{questions => exercise}/list.html (97%) rename pgtbl/questions/templates/{questions => exercise}/pagination.html (100%) rename pgtbl/questions/templates/{questions => exercise}/progress_bar.html (100%) rename pgtbl/questions/templates/{questions => exercise}/result.html (100%) rename pgtbl/questions/templates/{questions/grat_date.html => grat/date.html} (100%) rename pgtbl/questions/templates/{questions => grat}/grat.html (96%) rename pgtbl/questions/templates/{questions/grat_info.html => grat/info.html} (100%) rename pgtbl/questions/templates/{questions/grat_pagination.html => grat/pagination.html} (100%) create mode 100644 pgtbl/questions/templates/grat/progress_bar.html rename pgtbl/questions/templates/{questions/grat_result.html => grat/result.html} (98%) rename pgtbl/questions/templates/{questions/grat_update.html => grat/update.html} (100%) rename pgtbl/questions/templates/{questions/irat_date.html => irat/date.html} (100%) create mode 100644 pgtbl/questions/templates/irat/info.html rename pgtbl/questions/templates/{questions => irat}/irat.html (96%) rename pgtbl/questions/templates/{questions/irat_pagination.html => irat/pagination.html} (100%) create mode 100644 pgtbl/questions/templates/irat/progress_bar.html rename pgtbl/questions/templates/{questions/irat_result.html => irat/result.html} (98%) rename pgtbl/questions/templates/{questions/irat_update.html => irat/update.html} (100%) rename pgtbl/questions/views/{question => exercise}/exercise_list_view.py (98%) diff --git a/pgtbl/questions/templates/questions/irat_info.html b/pgtbl/questions/templates/exercise/info.html similarity index 100% rename from pgtbl/questions/templates/questions/irat_info.html rename to pgtbl/questions/templates/exercise/info.html diff --git a/pgtbl/questions/templates/questions/list.html b/pgtbl/questions/templates/exercise/list.html similarity index 97% rename from pgtbl/questions/templates/questions/list.html rename to pgtbl/questions/templates/exercise/list.html index d00b57e..4dbbd5a 100644 --- a/pgtbl/questions/templates/questions/list.html +++ b/pgtbl/questions/templates/exercise/list.html @@ -65,12 +65,12 @@

data-target="#irat-info"> - {% include 'questions/irat_info.html' %} + {% include 'exercise/info.html' %}
- {% include 'questions/progress_bar.html' %} + {% include 'exercise/progress_bar.html' %} {% for question in questions %}
@@ -179,7 +179,7 @@

{% trans 'There is no questions in this session.' %}

{% endfor %} {% if questions.count > 0 %} - {% include 'questions/pagination.html' %} + {% include 'exercise/pagination.html' %} {% endif %} {% if user == discipline.teacher or user in discipline.monitors.all %}
diff --git a/pgtbl/questions/templates/questions/pagination.html b/pgtbl/questions/templates/exercise/pagination.html similarity index 100% rename from pgtbl/questions/templates/questions/pagination.html rename to pgtbl/questions/templates/exercise/pagination.html diff --git a/pgtbl/questions/templates/questions/progress_bar.html b/pgtbl/questions/templates/exercise/progress_bar.html similarity index 100% rename from pgtbl/questions/templates/questions/progress_bar.html rename to pgtbl/questions/templates/exercise/progress_bar.html diff --git a/pgtbl/questions/templates/questions/result.html b/pgtbl/questions/templates/exercise/result.html similarity index 100% rename from pgtbl/questions/templates/questions/result.html rename to pgtbl/questions/templates/exercise/result.html diff --git a/pgtbl/questions/templates/questions/grat_date.html b/pgtbl/questions/templates/grat/date.html similarity index 100% rename from pgtbl/questions/templates/questions/grat_date.html rename to pgtbl/questions/templates/grat/date.html diff --git a/pgtbl/questions/templates/questions/grat.html b/pgtbl/questions/templates/grat/grat.html similarity index 96% rename from pgtbl/questions/templates/questions/grat.html rename to pgtbl/questions/templates/grat/grat.html index a202de6..70e6f70 100644 --- a/pgtbl/questions/templates/questions/grat.html +++ b/pgtbl/questions/templates/grat/grat.html @@ -59,7 +59,7 @@

{{session.grat_duration}}:00

- {% include 'questions/grat_update.html' %} + {% include 'grat/update.html' %} {% else %}

@@ -76,7 +76,7 @@

- {% include 'questions/grat_date.html' %} + {% include 'grat/date.html' %} {% else %}

{{session.grat_datetime|date:"d/m/Y H:i"}} @@ -103,12 +103,12 @@

data-target="#grat-info"> - {% include 'questions/grat_info.html' %} + {% include 'grat/info.html' %}

- {% include 'questions/progress_bar.html' %} + {% include 'grat/progress_bar.html' %} {% for question in questions %}
@@ -217,7 +217,7 @@

{% trans 'There is no questions in this session.' %}

{% endfor %} {% if questions.count > 0 %} - {% include 'questions/grat_pagination.html' %} + {% include 'grat/pagination.html' %} {% endif %}

diff --git a/pgtbl/questions/templates/questions/grat_info.html b/pgtbl/questions/templates/grat/info.html similarity index 100% rename from pgtbl/questions/templates/questions/grat_info.html rename to pgtbl/questions/templates/grat/info.html diff --git a/pgtbl/questions/templates/questions/grat_pagination.html b/pgtbl/questions/templates/grat/pagination.html similarity index 100% rename from pgtbl/questions/templates/questions/grat_pagination.html rename to pgtbl/questions/templates/grat/pagination.html diff --git a/pgtbl/questions/templates/grat/progress_bar.html b/pgtbl/questions/templates/grat/progress_bar.html new file mode 100644 index 0000000..9b87ce0 --- /dev/null +++ b/pgtbl/questions/templates/grat/progress_bar.html @@ -0,0 +1,12 @@ + +
+
+ {% widthratio 100 paginator.count page_obj.number %}% +
+
diff --git a/pgtbl/questions/templates/questions/grat_result.html b/pgtbl/questions/templates/grat/result.html similarity index 98% rename from pgtbl/questions/templates/questions/grat_result.html rename to pgtbl/questions/templates/grat/result.html index 08a83e2..dbe333c 100644 --- a/pgtbl/questions/templates/questions/grat_result.html +++ b/pgtbl/questions/templates/grat/result.html @@ -1,4 +1,4 @@ -{% extends 'questions/grat.html' %} +{% extends 'grat/grat.html' %} {% load static %} {% load i18n %} diff --git a/pgtbl/questions/templates/questions/grat_update.html b/pgtbl/questions/templates/grat/update.html similarity index 100% rename from pgtbl/questions/templates/questions/grat_update.html rename to pgtbl/questions/templates/grat/update.html diff --git a/pgtbl/questions/templates/questions/irat_date.html b/pgtbl/questions/templates/irat/date.html similarity index 100% rename from pgtbl/questions/templates/questions/irat_date.html rename to pgtbl/questions/templates/irat/date.html diff --git a/pgtbl/questions/templates/irat/info.html b/pgtbl/questions/templates/irat/info.html new file mode 100644 index 0000000..e14eeb7 --- /dev/null +++ b/pgtbl/questions/templates/irat/info.html @@ -0,0 +1,27 @@ +{% load i18n %} + + diff --git a/pgtbl/questions/templates/questions/irat.html b/pgtbl/questions/templates/irat/irat.html similarity index 96% rename from pgtbl/questions/templates/questions/irat.html rename to pgtbl/questions/templates/irat/irat.html index 87ee889..c610087 100644 --- a/pgtbl/questions/templates/questions/irat.html +++ b/pgtbl/questions/templates/irat/irat.html @@ -59,7 +59,7 @@

{{session.irat_duration}}:00

- {% include 'questions/irat_update.html' %} + {% include 'irat/update.html' %} {% else %}

@@ -76,7 +76,7 @@

- {% include 'questions/irat_date.html' %} + {% include 'irat/date.html' %} {% else %}

{{session.irat_datetime|date:"d/m/Y H:i"}} @@ -103,12 +103,12 @@

data-target="#irat-info"> - {% include 'questions/irat_info.html' %} + {% include 'irat/info.html' %}

- {% include 'questions/progress_bar.html' %} + {% include 'irat/progress_bar.html' %} {% for question in questions %}
@@ -217,7 +217,7 @@

{% trans 'There is no questions in this session.' %}

{% endfor %} {% if questions.count > 0 %} - {% include 'questions/irat_pagination.html' %} + {% include 'irat/pagination.html' %} {% endif %}

diff --git a/pgtbl/questions/templates/questions/irat_pagination.html b/pgtbl/questions/templates/irat/pagination.html similarity index 100% rename from pgtbl/questions/templates/questions/irat_pagination.html rename to pgtbl/questions/templates/irat/pagination.html diff --git a/pgtbl/questions/templates/irat/progress_bar.html b/pgtbl/questions/templates/irat/progress_bar.html new file mode 100644 index 0000000..9b87ce0 --- /dev/null +++ b/pgtbl/questions/templates/irat/progress_bar.html @@ -0,0 +1,12 @@ + +
+
+ {% widthratio 100 paginator.count page_obj.number %}% +
+
diff --git a/pgtbl/questions/templates/questions/irat_result.html b/pgtbl/questions/templates/irat/result.html similarity index 98% rename from pgtbl/questions/templates/questions/irat_result.html rename to pgtbl/questions/templates/irat/result.html index e92fcd2..cf75c41 100644 --- a/pgtbl/questions/templates/questions/irat_result.html +++ b/pgtbl/questions/templates/irat/result.html @@ -1,4 +1,4 @@ -{% extends 'questions/irat.html' %} +{% extends 'irat/irat.html' %} {% load static %} {% load i18n %} diff --git a/pgtbl/questions/templates/questions/irat_update.html b/pgtbl/questions/templates/irat/update.html similarity index 100% rename from pgtbl/questions/templates/questions/irat_update.html rename to pgtbl/questions/templates/irat/update.html diff --git a/pgtbl/questions/templates/questions/add.html b/pgtbl/questions/templates/questions/add.html index a15c4d3..c2bf283 100644 --- a/pgtbl/questions/templates/questions/add.html +++ b/pgtbl/questions/templates/questions/add.html @@ -1,4 +1,4 @@ -{% extends 'questions/list.html' %} +{% extends 'exercise/list.html' %} {% load static %} {% load widget_tweaks %} {% load i18n %} diff --git a/pgtbl/questions/templates/questions/update.html b/pgtbl/questions/templates/questions/update.html index 090f86a..ff51d51 100644 --- a/pgtbl/questions/templates/questions/update.html +++ b/pgtbl/questions/templates/questions/update.html @@ -1,4 +1,4 @@ -{% extends 'questions/list.html' %} +{% extends 'exercise/list.html' %} {% load static %} {% load widget_tweaks %} {% load i18n %} diff --git a/pgtbl/questions/views/__init__.py b/pgtbl/questions/views/__init__.py index e4a9fe3..57b404a 100644 --- a/pgtbl/questions/views/__init__.py +++ b/pgtbl/questions/views/__init__.py @@ -1,7 +1,8 @@ from .exercise.answer_question_view import AnswerQuestionView -from .exercise.csv import get_csv from .exercise.exercise_result_view import ExerciseResultView from .exercise.reset_exercise_view import ResetExerciseView +from .exercise.exercise_list_view import ExerciseListView +from .exercise.csv import get_csv from .grat.grat_answer_question_view import GRATAnswerQuestionView from .grat.grat_date_update_view import GRATDateUpdateView from .grat.grat_result_view import GRATResultView @@ -14,5 +15,4 @@ from .irat.irat_view import IRATView from .question.create_question_view import CreateQuestionView from .question.delete_question_view import DeleteQuestionView -from .question.exercise_list_view import ExerciseListView from .question.update_question_view import UpdateQuestionView diff --git a/pgtbl/questions/views/exercise/answer_question_view.py b/pgtbl/questions/views/exercise/answer_question_view.py index 2deff48..6573dd4 100644 --- a/pgtbl/questions/views/exercise/answer_question_view.py +++ b/pgtbl/questions/views/exercise/answer_question_view.py @@ -16,7 +16,7 @@ class AnswerQuestionView(LoginRequiredMixin, FormView): Answer the respective question. """ - template_name = 'questions/list.html' + template_name = 'exercise/list.html' form_class = AnswerQuestionForm # Permissions diff --git a/pgtbl/questions/views/question/exercise_list_view.py b/pgtbl/questions/views/exercise/exercise_list_view.py similarity index 98% rename from pgtbl/questions/views/question/exercise_list_view.py rename to pgtbl/questions/views/exercise/exercise_list_view.py index 17d32e6..9273c27 100644 --- a/pgtbl/questions/views/question/exercise_list_view.py +++ b/pgtbl/questions/views/exercise/exercise_list_view.py @@ -16,7 +16,7 @@ class ExerciseListView(LoginRequiredMixin, View to see all the questions that the students will answer. """ - template_name = 'questions/list.html' + template_name = 'exercise/list.html' paginate_by = 1 context_object_name = 'questions' diff --git a/pgtbl/questions/views/exercise/exercise_result_view.py b/pgtbl/questions/views/exercise/exercise_result_view.py index 0d5951d..91bac81 100644 --- a/pgtbl/questions/views/exercise/exercise_result_view.py +++ b/pgtbl/questions/views/exercise/exercise_result_view.py @@ -15,7 +15,7 @@ class ExerciseResultView(LoginRequiredMixin, Show the result of exercise list. """ - template_name = 'questions/result.html' + template_name = 'exercise/result.html' context_object_name = 'submissions' # Permissions diff --git a/pgtbl/questions/views/grat/grat_answer_question_view.py b/pgtbl/questions/views/grat/grat_answer_question_view.py index 27888b0..84a408e 100644 --- a/pgtbl/questions/views/grat/grat_answer_question_view.py +++ b/pgtbl/questions/views/grat/grat_answer_question_view.py @@ -17,7 +17,7 @@ class GRATAnswerQuestionView(LoginRequiredMixin, FormView): Answer the respective gRAT question. """ - template_name = 'questions/grat.html' + template_name = 'grat/grat.html' form_class = AnswerGRATQuestionForm # Permissions diff --git a/pgtbl/questions/views/grat/grat_date_update_view.py b/pgtbl/questions/views/grat/grat_date_update_view.py index f389123..df4a585 100644 --- a/pgtbl/questions/views/grat/grat_date_update_view.py +++ b/pgtbl/questions/views/grat/grat_date_update_view.py @@ -24,7 +24,7 @@ class GRATDateUpdateView(LoginRequiredMixin, """ model = TBLSession - template_name = 'questions/grat.html' + template_name = 'grat/grat.html' form_class = GRATDateForm # Permissions diff --git a/pgtbl/questions/views/grat/grat_result_view.py b/pgtbl/questions/views/grat/grat_result_view.py index 94d0540..ae3fdba 100644 --- a/pgtbl/questions/views/grat/grat_result_view.py +++ b/pgtbl/questions/views/grat/grat_result_view.py @@ -17,7 +17,7 @@ class GRATResultView(LoginRequiredMixin, Show the result of gRAT test. """ - template_name = 'questions/grat_result.html' + template_name = 'grat/result.html' context_object_name = 'submissions' # Permissions diff --git a/pgtbl/questions/views/grat/grat_update_view.py b/pgtbl/questions/views/grat/grat_update_view.py index aa4c58b..f118857 100644 --- a/pgtbl/questions/views/grat/grat_update_view.py +++ b/pgtbl/questions/views/grat/grat_update_view.py @@ -19,7 +19,7 @@ class GRATUpdateView(LoginRequiredMixin, """ model = TBLSession - template_name = 'questions/grat.html' + template_name = 'grat/grat.html' form_class = GRATForm # Permissions diff --git a/pgtbl/questions/views/grat/grat_view.py b/pgtbl/questions/views/grat/grat_view.py index e9c5cfd..e3ee0b1 100644 --- a/pgtbl/questions/views/grat/grat_view.py +++ b/pgtbl/questions/views/grat/grat_view.py @@ -20,7 +20,7 @@ class GRATView(LoginRequiredMixin, gRAT (Group Readiness Assurance Test) """ - template_name = 'questions/grat.html' + template_name = 'grat/grat.html' paginate_by = 1 context_object_name = 'questions' diff --git a/pgtbl/questions/views/irat/irat_answer_question_view.py b/pgtbl/questions/views/irat/irat_answer_question_view.py index 9d5967f..6b62edc 100644 --- a/pgtbl/questions/views/irat/irat_answer_question_view.py +++ b/pgtbl/questions/views/irat/irat_answer_question_view.py @@ -16,7 +16,7 @@ class IRATAnswerQuestionView(LoginRequiredMixin, FormView): Answer the respective iRAT question. """ - template_name = 'questions/irat-list.html' + template_name = 'irat/list.html' form_class = AnswerQuestionForm # Permissions diff --git a/pgtbl/questions/views/irat/irat_date_update_view.py b/pgtbl/questions/views/irat/irat_date_update_view.py index 52e2fe3..3b14c11 100644 --- a/pgtbl/questions/views/irat/irat_date_update_view.py +++ b/pgtbl/questions/views/irat/irat_date_update_view.py @@ -20,7 +20,7 @@ class IRATDateUpdateView(LoginRequiredMixin, """ model = TBLSession - template_name = 'questions/irat.html' + template_name = 'irat/irat.html' form_class = IRATDateForm # Permissions diff --git a/pgtbl/questions/views/irat/irat_result_view.py b/pgtbl/questions/views/irat/irat_result_view.py index dce3b16..785d699 100644 --- a/pgtbl/questions/views/irat/irat_result_view.py +++ b/pgtbl/questions/views/irat/irat_result_view.py @@ -20,7 +20,7 @@ class IRATResultView(LoginRequiredMixin, Show the result of iRAT test. """ - template_name = 'questions/irat_result.html' + template_name = 'irat/result.html' context_object_name = 'submissions' # Permissions diff --git a/pgtbl/questions/views/irat/irat_update_view.py b/pgtbl/questions/views/irat/irat_update_view.py index f5cd6b6..202163a 100644 --- a/pgtbl/questions/views/irat/irat_update_view.py +++ b/pgtbl/questions/views/irat/irat_update_view.py @@ -18,7 +18,7 @@ class IRATUpdateView(LoginRequiredMixin, """ model = TBLSession - template_name = 'questions/irat.html' + template_name = 'irat/irat.html' form_class = IRATForm # Permissions diff --git a/pgtbl/questions/views/irat/irat_view.py b/pgtbl/questions/views/irat/irat_view.py index 33bffce..cb9e2a1 100644 --- a/pgtbl/questions/views/irat/irat_view.py +++ b/pgtbl/questions/views/irat/irat_view.py @@ -19,7 +19,7 @@ class IRATView(LoginRequiredMixin, iRAT (Individual Readiness Assurance Test) """ - template_name = 'questions/irat.html' + template_name = 'irat/irat.html' paginate_by = 1 context_object_name = 'questions' From 19ebdc6f15d43f6ce3113d3f8002add827e432fd Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 03:33:03 -0300 Subject: [PATCH 28/56] Organize questions tests --- pgtbl/questions/tests/__init__.py | 0 .../tests/{test_answer_question.py => test_question_answer.py} | 0 .../tests/{test_create_question.py => test_question_create.py} | 0 .../tests/{test_delete_question.py => test_question_delete.py} | 0 .../tests/{test_update_question.py => test_question_update.py} | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pgtbl/questions/tests/__init__.py rename pgtbl/questions/tests/{test_answer_question.py => test_question_answer.py} (100%) rename pgtbl/questions/tests/{test_create_question.py => test_question_create.py} (100%) rename pgtbl/questions/tests/{test_delete_question.py => test_question_delete.py} (100%) rename pgtbl/questions/tests/{test_update_question.py => test_question_update.py} (100%) diff --git a/pgtbl/questions/tests/__init__.py b/pgtbl/questions/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pgtbl/questions/tests/test_answer_question.py b/pgtbl/questions/tests/test_question_answer.py similarity index 100% rename from pgtbl/questions/tests/test_answer_question.py rename to pgtbl/questions/tests/test_question_answer.py diff --git a/pgtbl/questions/tests/test_create_question.py b/pgtbl/questions/tests/test_question_create.py similarity index 100% rename from pgtbl/questions/tests/test_create_question.py rename to pgtbl/questions/tests/test_question_create.py diff --git a/pgtbl/questions/tests/test_delete_question.py b/pgtbl/questions/tests/test_question_delete.py similarity index 100% rename from pgtbl/questions/tests/test_delete_question.py rename to pgtbl/questions/tests/test_question_delete.py diff --git a/pgtbl/questions/tests/test_update_question.py b/pgtbl/questions/tests/test_question_update.py similarity index 100% rename from pgtbl/questions/tests/test_update_question.py rename to pgtbl/questions/tests/test_question_update.py From 314d481cde138c3130b9c1e341f5c9a73bdfdb7b Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sat, 14 Jul 2018 15:18:48 -0300 Subject: [PATCH 29/56] Change TBLSessions to modules --- pgtbl/TBLSessions/apps.py | 5 - .../templates/disciplines/sidebar.html | 2 +- pgtbl/files/models/module_file.py | 2 +- pgtbl/files/templates/files/module/form.html | 2 +- pgtbl/files/templates/files/module/list.html | 2 +- pgtbl/files/views/module_file/create_view.py | 2 +- pgtbl/files/views/module_file/delete_view.py | 2 +- pgtbl/files/views/module_file/list_view.py | 4 +- pgtbl/files/views/module_file/update_view.py | 4 +- pgtbl/grades/models/grade.py | 2 +- pgtbl/grades/templates/grades/list.html | 2 +- pgtbl/grades/views/grade_list_view.py | 4 +- pgtbl/grades/views/grade_module_csv.py | 2 +- pgtbl/grades/views/grade_update_view.py | 4 +- pgtbl/{TBLSessions => modules}/__init__.py | 0 pgtbl/{TBLSessions => modules}/admin.py | 2 +- pgtbl/modules/apps.py | 5 + .../forms/__init__.py | 0 .../forms/practical_test_form.py | 2 +- .../forms/tbl_session_form.py | 2 +- .../locale/pt_BR/LC_MESSAGES/django.po | 180 +++++++++--------- .../migrations/__init__.py | 0 .../models/__init__.py | 0 .../models/tbl_session.py | 0 pgtbl/{TBLSessions => modules}/permissions.py | 0 .../static/modules}/css/delete.css | 0 .../static/modules}/css/edit.css | 0 .../static/modules}/css/list.css | 0 .../static/practical_test/css/detail.css | 0 .../static/practical_test/css/update.css | 0 .../templates/modules}/add.html | 2 +- .../templates/modules}/delete.html | 4 +- .../templates/modules}/details.html | 6 +- .../templates/modules}/form.html | 8 +- .../templates/modules}/list.html | 14 +- .../templates/modules}/sidebar.html | 4 +- .../templates/practical_test/detail.html | 6 +- .../templates/practical_test/info.html | 0 .../templates/practical_test/update.html | 4 +- .../tests/__init__.py | 0 .../tests/test_practical_detail.py | 2 +- .../tests/test_practical_update.py | 2 +- .../tests/test_tbl_session_create.py | 2 +- .../tests/test_tbl_session_delete.py | 2 +- .../tests/test_tbl_session_list.py | 2 +- .../tests/test_tbl_session_update.py | 2 +- pgtbl/{TBLSessions => modules}/urls.py | 2 +- pgtbl/{TBLSessions => modules}/utils.py | 0 .../views/__init__.py | 0 .../views/practical_test_detail_view.py | 6 +- .../views/practical_test_update_view.py | 8 +- .../views/tbl_session_create_view.py | 8 +- .../views/tbl_session_delete_view.py | 4 +- .../views/tbl_session_detail_view.py | 6 +- .../views/tbl_session_list_view.py | 6 +- .../views/tbl_session_update_view.py | 8 +- pgtbl/questions/forms/grat_form.py | 2 +- pgtbl/questions/forms/irat_form.py | 2 +- pgtbl/questions/models/exercise_submission.py | 2 +- pgtbl/questions/models/grat_submission.py | 2 +- pgtbl/questions/models/irat_submission.py | 2 +- pgtbl/questions/models/question.py | 2 +- pgtbl/questions/templates/exercise/list.html | 2 +- .../questions/templates/exercise/result.html | 2 +- pgtbl/questions/templates/grat/grat.html | 2 +- pgtbl/questions/templates/irat/irat.html | 2 +- .../views/exercise/answer_question_view.py | 2 +- pgtbl/questions/views/exercise/csv.py | 2 +- .../views/exercise/exercise_list_view.py | 4 +- .../views/exercise/exercise_result_view.py | 4 +- .../views/exercise/reset_exercise_view.py | 2 +- .../views/grat/grat_answer_question_view.py | 4 +- .../views/grat/grat_date_update_view.py | 2 +- .../questions/views/grat/grat_result_view.py | 4 +- .../questions/views/grat/grat_update_view.py | 2 +- pgtbl/questions/views/grat/grat_view.py | 6 +- .../views/irat/irat_answer_question_view.py | 4 +- .../views/irat/irat_date_update_view.py | 2 +- .../questions/views/irat/irat_result_view.py | 6 +- .../questions/views/irat/irat_update_view.py | 2 +- pgtbl/questions/views/irat/irat_view.py | 6 +- .../views/question/create_question_view.py | 4 +- .../views/question/delete_question_view.py | 2 +- .../views/question/update_question_view.py | 4 +- pgtbl/tbl/config/apps.py | 2 +- pgtbl/tbl/urls.py | 2 +- 86 files changed, 212 insertions(+), 212 deletions(-) delete mode 100644 pgtbl/TBLSessions/apps.py rename pgtbl/{TBLSessions => modules}/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/admin.py (63%) create mode 100644 pgtbl/modules/apps.py rename pgtbl/{TBLSessions => modules}/forms/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/forms/practical_test_form.py (93%) rename pgtbl/{TBLSessions => modules}/forms/tbl_session_form.py (91%) rename pgtbl/{TBLSessions => modules}/locale/pt_BR/LC_MESSAGES/django.po (60%) rename pgtbl/{TBLSessions => modules}/migrations/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/models/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/models/tbl_session.py (100%) rename pgtbl/{TBLSessions => modules}/permissions.py (100%) rename pgtbl/{TBLSessions/static/TBLSessions => modules/static/modules}/css/delete.css (100%) rename pgtbl/{TBLSessions/static/TBLSessions => modules/static/modules}/css/edit.css (100%) rename pgtbl/{TBLSessions/static/TBLSessions => modules/static/modules}/css/list.css (100%) rename pgtbl/{TBLSessions => modules}/static/practical_test/css/detail.css (100%) rename pgtbl/{TBLSessions => modules}/static/practical_test/css/update.css (100%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/add.html (93%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/delete.html (89%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/details.html (84%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/form.html (91%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/list.html (88%) rename pgtbl/{TBLSessions/templates/TBLSessions => modules/templates/modules}/sidebar.html (95%) rename pgtbl/{TBLSessions => modules}/templates/practical_test/detail.html (92%) rename pgtbl/{TBLSessions => modules}/templates/practical_test/info.html (100%) rename pgtbl/{TBLSessions => modules}/templates/practical_test/update.html (92%) rename pgtbl/{TBLSessions => modules}/tests/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/tests/test_practical_detail.py (95%) rename pgtbl/{TBLSessions => modules}/tests/test_practical_update.py (94%) rename pgtbl/{TBLSessions => modules}/tests/test_tbl_session_create.py (97%) rename pgtbl/{TBLSessions => modules}/tests/test_tbl_session_delete.py (96%) rename pgtbl/{TBLSessions => modules}/tests/test_tbl_session_list.py (95%) rename pgtbl/{TBLSessions => modules}/tests/test_tbl_session_update.py (97%) rename pgtbl/{TBLSessions => modules}/urls.py (98%) rename pgtbl/{TBLSessions => modules}/utils.py (100%) rename pgtbl/{TBLSessions => modules}/views/__init__.py (100%) rename pgtbl/{TBLSessions => modules}/views/practical_test_detail_view.py (94%) rename pgtbl/{TBLSessions => modules}/views/practical_test_update_view.py (93%) rename pgtbl/{TBLSessions => modules}/views/tbl_session_create_view.py (91%) rename pgtbl/{TBLSessions => modules}/views/tbl_session_delete_view.py (94%) rename pgtbl/{TBLSessions => modules}/views/tbl_session_detail_view.py (92%) rename pgtbl/{TBLSessions => modules}/views/tbl_session_list_view.py (90%) rename pgtbl/{TBLSessions => modules}/views/tbl_session_update_view.py (91%) diff --git a/pgtbl/TBLSessions/apps.py b/pgtbl/TBLSessions/apps.py deleted file mode 100644 index 89d0fdb..0000000 --- a/pgtbl/TBLSessions/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class TBLSessionsConfig(AppConfig): - name = 'TBLSessions' diff --git a/pgtbl/disciplines/templates/disciplines/sidebar.html b/pgtbl/disciplines/templates/disciplines/sidebar.html index 2154418..2189145 100644 --- a/pgtbl/disciplines/templates/disciplines/sidebar.html +++ b/pgtbl/disciplines/templates/disciplines/sidebar.html @@ -50,7 +50,7 @@ - 1);\n" -#: TBLSessions/models.py:24 +#: modules/models.py:24 msgid "Title" msgstr "TĆ­tulo" -#: TBLSessions/models.py:26 +#: modules/models.py:26 msgid "Session title." msgstr "TĆ­tulo da sessĆ£o" -#: TBLSessions/models.py:30 TBLSessions/models.py:99 +#: modules/models.py:30 modules/models.py:99 msgid "Description" msgstr "DescriĆ§Ć£o" -#: TBLSessions/models.py:31 +#: modules/models.py:31 msgid "TBL session description." msgstr "DescriĆ§Ć£o da sessĆ£o de TBL" -#: TBLSessions/models.py:35 +#: modules/models.py:35 msgid "Is closed?" msgstr "EstĆ” fechada?" -#: TBLSessions/models.py:37 +#: modules/models.py:37 msgid "Close TBL session." msgstr "Fechar SessĆ£o de TBL" -#: TBLSessions/models.py:42 +#: modules/models.py:42 msgid "iRAT date" msgstr "Data da avaliaĆ§Ć£o iRAT" -#: TBLSessions/models.py:45 +#: modules/models.py:45 msgid "Date and time to provide the iRAT test." msgstr "Data e hora que serĆ” disponibilizado a avaliaĆ§Ć£o iRAT." -#: TBLSessions/models.py:49 +#: modules/models.py:49 msgid "iRAT weight" msgstr "Peso da avaliaĆ§Ć£o iRAT" -#: TBLSessions/models.py:52 +#: modules/models.py:52 msgid "iRAT test weight." msgstr "Peso da avaliaĆ§Ć£o iRAT" -#: TBLSessions/models.py:56 +#: modules/models.py:56 msgid "iRAT durantion in minutes" msgstr "DuraĆ§Ć£o da avaliaĆ§Ć£o iRAT em minutos" -#: TBLSessions/models.py:59 +#: modules/models.py:59 msgid "iRAT duration in minutes to be answered." msgstr "DuraĆ§Ć£o da avaliaĆ§Ć£o iRAT em minutos para ser respondida." -#: TBLSessions/models.py:64 +#: modules/models.py:64 msgid "gRAT date" msgstr "Data da avaliaĆ§Ć£o gRAT" -#: TBLSessions/models.py:67 +#: modules/models.py:67 msgid "Date and time to provide the gRAT test." msgstr "Data e hora que serĆ” disponibilizado a avaliaĆ§Ć£o gRAT" -#: TBLSessions/models.py:71 +#: modules/models.py:71 msgid "gRAT test weight" msgstr "Peso da avaliaĆ§Ć£o gRAT" -#: TBLSessions/models.py:74 +#: modules/models.py:74 msgid "gRAT test weight." msgstr "Peso da avaliaĆ§Ć£o gRAT." -#: TBLSessions/models.py:78 +#: modules/models.py:78 msgid "gRAT durantion in minutes" msgstr "DuraĆ§Ć£o da avaliaĆ§Ć£o gRAT em minutos" -#: TBLSessions/models.py:81 +#: modules/models.py:81 msgid "gRAT duration in minutes to be answered." msgstr "DuraĆ§Ć£o da avaliaĆ§Ć£o gRAT em minutos para ser respondida." -#: TBLSessions/models.py:86 +#: modules/models.py:86 msgid "Release the practical test" msgstr "Disponibilizar a avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/models.py:88 +#: modules/models.py:88 msgid "Release the practical test." msgstr "Disponibilizar a avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/models.py:92 +#: modules/models.py:92 msgid "Practical test weight" msgstr "Peso da avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/models.py:95 +#: modules/models.py:95 msgid "Practical test weight." msgstr "Peso da avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/models.py:100 +#: modules/models.py:100 msgid "Practical test description." msgstr "DescriĆ§Ć£o da avaliaĆ§Ć£o prĆ”tica." -#: TBLSessions/models.py:105 +#: modules/models.py:105 msgid "Release the peer review test" msgstr "Disponibilizar a avaliaĆ§Ć£o em pares" -#: TBLSessions/models.py:107 +#: modules/models.py:107 msgid "Release the peer review test to be answered." msgstr "Disponibilizar a avaliaĆ§Ć£o em pares para ser respondida." -#: TBLSessions/models.py:111 +#: modules/models.py:111 msgid "Peer review weight" msgstr "Peso da avaliaĆ§Ć£o em pares" -#: TBLSessions/models.py:114 +#: modules/models.py:114 msgid "Peer review weight." msgstr "Peso da avaliaĆ§Ć£o em pares." -#: TBLSessions/models.py:118 +#: modules/models.py:118 msgid "Created at" msgstr "Criado em" -#: TBLSessions/models.py:119 +#: modules/models.py:119 msgid "Date that the session is created." msgstr "Data na qual a sessĆ£o de TBL foi criada." -#: TBLSessions/models.py:124 +#: modules/models.py:124 msgid "Updated at" msgstr "Atualizado em" -#: TBLSessions/models.py:125 +#: modules/models.py:125 msgid "Date that the session is updated." msgstr "Data na qual a sessĆ£o de TBL foi atualizada" -#: TBLSessions/models.py:155 +#: modules/models.py:155 msgid "TBL Session" msgstr "SessĆ£o TBL" -#: TBLSessions/models.py:156 +#: modules/models.py:156 msgid "TBL Sessions" msgstr "SessƵes TBL" -#: TBLSessions/templates/TBLSessions/add.html:14 +#: modules/templates/modules/add.html:14 msgid "Add TBL session" msgstr "Adicionar sessƵes de TBL" -#: TBLSessions/templates/TBLSessions/add.html:22 +#: modules/templates/modules/add.html:22 msgid "Session title" msgstr "TĆ­tulo da sessĆ£o" -#: TBLSessions/templates/TBLSessions/add.html:26 +#: modules/templates/modules/add.html:26 msgid "Session description" msgstr "DescriĆ§Ć£o da sessĆ£o" -#: TBLSessions/templates/TBLSessions/add.html:32 +#: modules/templates/modules/add.html:32 msgid "Close session" msgstr "Fechar sessĆ£o" -#: TBLSessions/templates/TBLSessions/add.html:37 +#: modules/templates/modules/add.html:37 msgid "Add" msgstr "Adicionar" -#: TBLSessions/templates/TBLSessions/delete.html:20 -#: TBLSessions/templates/TBLSessions/delete.html:42 -#: TBLSessions/templates/TBLSessions/list.html:84 +#: modules/templates/modules/delete.html:20 +#: modules/templates/modules/delete.html:42 +#: modules/templates/modules/list.html:84 msgid "Delete" msgstr "Deletar" -#: TBLSessions/templates/TBLSessions/delete.html:27 +#: modules/templates/modules/delete.html:27 msgid "Are you sure you want to delete" msgstr "Tem certeza que deseja deletar" -#: TBLSessions/templates/TBLSessions/delete.html:51 +#: modules/templates/modules/delete.html:51 msgid "Cancel" msgstr "Cancelar" -#: TBLSessions/templates/TBLSessions/form.html:17 -#: TBLSessions/templates/TBLSessions/form.html:27 -#: TBLSessions/templates/TBLSessions/form.html:104 -#: TBLSessions/templates/TBLSessions/list.html:71 -#: TBLSessions/templates/TBLSessions/practical_update.html:79 +#: modules/templates/modules/form.html:17 +#: modules/templates/modules/form.html:27 +#: modules/templates/modules/form.html:104 +#: modules/templates/modules/list.html:71 +#: modules/templates/modules/practical_update.html:79 msgid "Edit" msgstr "Editar" -#: TBLSessions/templates/TBLSessions/form.html:86 -#: TBLSessions/templates/TBLSessions/practical_update.html:69 +#: modules/templates/modules/form.html:86 +#: modules/templates/modules/practical_update.html:69 msgid "Preview" msgstr "Visualizar" -#: TBLSessions/templates/TBLSessions/form.html:96 +#: modules/templates/modules/form.html:96 msgid "Make session unavailable" msgstr "Fazer a sessĆ£o ficar indisponĆ­vel" -#: TBLSessions/templates/TBLSessions/list.html:14 +#: modules/templates/modules/list.html:14 msgid "TBL session list" msgstr "Lista de sessƵes de TBL" -#: TBLSessions/templates/TBLSessions/list.html:24 +#: modules/templates/modules/list.html:24 msgid "TBL sessions" msgstr "SessƵes de TBL" -#: TBLSessions/templates/TBLSessions/list.html:42 +#: modules/templates/modules/list.html:42 msgid "Unavailable" msgstr "IndisponĆ­vel" -#: TBLSessions/templates/TBLSessions/list.html:46 +#: modules/templates/modules/list.html:46 msgid "Available" msgstr "DisponĆ­vel" -#: TBLSessions/templates/TBLSessions/list.html:64 -#: TBLSessions/templates/TBLSessions/list.html:98 +#: modules/templates/modules/list.html:64 +#: modules/templates/modules/list.html:98 msgid "Enter" msgstr "Entrar" -#: TBLSessions/templates/TBLSessions/list.html:107 +#: modules/templates/modules/list.html:107 msgid "There is no sessions available." msgstr "NĆ£o hĆ” sessƵes de TBL disponĆ­veis" -#: TBLSessions/templates/TBLSessions/practical_info.html:8 +#: modules/templates/modules/practical_info.html:8 msgid "Rules" msgstr "Regras" -#: TBLSessions/templates/TBLSessions/practical_info.html:11 +#: modules/templates/modules/practical_info.html:11 msgid "The rules of practical test" msgstr "Regras para a avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/templates/TBLSessions/practical_info.html:13 +#: modules/templates/modules/practical_info.html:13 msgid "Carefully read the full context of the evaluation." msgstr "Cuidadosamente leia todo o contexto da avaliaĆ§Ć£o." -#: TBLSessions/templates/TBLSessions/practical_info.html:14 +#: modules/templates/modules/practical_info.html:14 msgid "Perform what the practical project asks." msgstr "Execute o que a avaliaĆ§Ć£o prĆ”tica pede." -#: TBLSessions/templates/TBLSessions/practical_info.html:15 +#: modules/templates/modules/practical_info.html:15 msgid "Delivered to the teacher." msgstr "Entregue ao professor." -#: TBLSessions/templates/TBLSessions/practical_test.html:14 +#: modules/templates/modules/practical_test.html:14 msgid "Practical test" msgstr "AvaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/templates/TBLSessions/practical_test.html:25 +#: modules/templates/modules/practical_test.html:25 msgid "Practical Test" msgstr "AvaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/templates/TBLSessions/practical_test.html:36 +#: modules/templates/modules/practical_test.html:36 msgid "Course" msgstr "Curso" -#: TBLSessions/templates/TBLSessions/practical_test.html:41 +#: modules/templates/modules/practical_test.html:41 msgid "Discipline" msgstr "Disciplina" -#: TBLSessions/templates/TBLSessions/practical_test.html:46 +#: modules/templates/modules/practical_test.html:46 msgid "Teacher" msgstr "Professor" -#: TBLSessions/templates/TBLSessions/practical_test.html:59 +#: modules/templates/modules/practical_test.html:59 msgid "PRACTICAL TEST" msgstr "AVALIAƇƃO PRƁTICA" -#: TBLSessions/templates/TBLSessions/practical_update.html:17 -#: TBLSessions/templates/TBLSessions/practical_update.html:27 +#: modules/templates/modules/practical_update.html:17 +#: modules/templates/modules/practical_update.html:27 msgid "Edit practical test" msgstr "Editar avaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/templates/TBLSessions/practical_update.html:50 +#: modules/templates/modules/practical_update.html:50 msgid "Make practical test available" msgstr "Tornar a avaliaĆ§Ć£o prĆ”tica acessĆ­vel" -#: TBLSessions/templates/TBLSessions/sidebar.html:12 +#: modules/templates/modules/sidebar.html:12 msgid "Session" msgstr "SessĆ£o" -#: TBLSessions/templates/TBLSessions/sidebar.html:20 +#: modules/templates/modules/sidebar.html:20 msgid "Files" msgstr "Arquivos" -#: TBLSessions/templates/TBLSessions/sidebar.html:28 +#: modules/templates/modules/sidebar.html:28 msgid "Session Grades" msgstr "Notas da sessĆ£o" -#: TBLSessions/templates/TBLSessions/sidebar.html:36 +#: modules/templates/modules/sidebar.html:36 msgid "Exercise list" msgstr "Lista de exercĆ­cios" -#: TBLSessions/templates/TBLSessions/sidebar.html:44 +#: modules/templates/modules/sidebar.html:44 msgid "Dashboard" msgstr "RelatĆ³rio" -#: TBLSessions/templates/TBLSessions/sidebar.html:53 +#: modules/templates/modules/sidebar.html:53 msgid "Test iRAT Result" msgstr "Resultado da avaliaĆ§Ć£o iRAT" -#: TBLSessions/templates/TBLSessions/sidebar.html:61 +#: modules/templates/modules/sidebar.html:61 msgid "Test iRAT" msgstr "AvaliaĆ§Ć£o iRAT" -#: TBLSessions/templates/TBLSessions/sidebar.html:72 +#: modules/templates/modules/sidebar.html:72 msgid "Test gRAT Result" msgstr "Resultado da avaliaĆ§Ć£o gRAT" -#: TBLSessions/templates/TBLSessions/sidebar.html:80 +#: modules/templates/modules/sidebar.html:80 msgid "Test gRAT" msgstr "AvaliaĆ§Ć£o gRAT" -#: TBLSessions/templates/TBLSessions/sidebar.html:90 +#: modules/templates/modules/sidebar.html:90 msgid "Test practical" msgstr "AvaliaĆ§Ć£o prĆ”tica" -#: TBLSessions/templates/TBLSessions/sidebar.html:99 +#: modules/templates/modules/sidebar.html:99 msgid "Test Peer" msgstr "AvaliaĆ§Ć£o em pares" -#: TBLSessions/templates/TBLSessions/sidebar.html:108 +#: modules/templates/modules/sidebar.html:108 msgid "Appeal" msgstr "ApelaĆ§Ć£o" -#: TBLSessions/views_practical.py:40 +#: modules/views_practical.py:40 msgid "You are not authorized to do this action." msgstr "VocĆŖ nĆ£o estĆ” autorizado a fazer estĆ” aĆ§Ć£o." -#: TBLSessions/views_practical.py:154 +#: modules/views_practical.py:154 msgid "Practical test updated successfully." msgstr "AvaliaĆ§Ć£o prĆ”tica atualizada com sucesso." -#: TBLSessions/views_session.py:102 +#: modules/views_session.py:102 msgid "TBL session created successfully." msgstr "SessĆ£o de TBL criado com sucesso." -#: TBLSessions/views_session.py:113 +#: modules/views_session.py:113 msgid "Invalid fields, please fill in the fields correctly." msgstr "Campos invalidos, por favor preencha os campos corretamente." -#: TBLSessions/views_session.py:175 +#: modules/views_session.py:175 msgid "TBL session updated successfully." msgstr "SessĆ£o de TBL atualizada com sucesso." -#: TBLSessions/views_session.py:230 +#: modules/views_session.py:230 msgid "TBL session deleted successfully." msgstr "SessĆ£o de TBL deletada com sucesso." diff --git a/pgtbl/TBLSessions/migrations/__init__.py b/pgtbl/modules/migrations/__init__.py similarity index 100% rename from pgtbl/TBLSessions/migrations/__init__.py rename to pgtbl/modules/migrations/__init__.py diff --git a/pgtbl/TBLSessions/models/__init__.py b/pgtbl/modules/models/__init__.py similarity index 100% rename from pgtbl/TBLSessions/models/__init__.py rename to pgtbl/modules/models/__init__.py diff --git a/pgtbl/TBLSessions/models/tbl_session.py b/pgtbl/modules/models/tbl_session.py similarity index 100% rename from pgtbl/TBLSessions/models/tbl_session.py rename to pgtbl/modules/models/tbl_session.py diff --git a/pgtbl/TBLSessions/permissions.py b/pgtbl/modules/permissions.py similarity index 100% rename from pgtbl/TBLSessions/permissions.py rename to pgtbl/modules/permissions.py diff --git a/pgtbl/TBLSessions/static/TBLSessions/css/delete.css b/pgtbl/modules/static/modules/css/delete.css similarity index 100% rename from pgtbl/TBLSessions/static/TBLSessions/css/delete.css rename to pgtbl/modules/static/modules/css/delete.css diff --git a/pgtbl/TBLSessions/static/TBLSessions/css/edit.css b/pgtbl/modules/static/modules/css/edit.css similarity index 100% rename from pgtbl/TBLSessions/static/TBLSessions/css/edit.css rename to pgtbl/modules/static/modules/css/edit.css diff --git a/pgtbl/TBLSessions/static/TBLSessions/css/list.css b/pgtbl/modules/static/modules/css/list.css similarity index 100% rename from pgtbl/TBLSessions/static/TBLSessions/css/list.css rename to pgtbl/modules/static/modules/css/list.css diff --git a/pgtbl/TBLSessions/static/practical_test/css/detail.css b/pgtbl/modules/static/practical_test/css/detail.css similarity index 100% rename from pgtbl/TBLSessions/static/practical_test/css/detail.css rename to pgtbl/modules/static/practical_test/css/detail.css diff --git a/pgtbl/TBLSessions/static/practical_test/css/update.css b/pgtbl/modules/static/practical_test/css/update.css similarity index 100% rename from pgtbl/TBLSessions/static/practical_test/css/update.css rename to pgtbl/modules/static/practical_test/css/update.css diff --git a/pgtbl/TBLSessions/templates/TBLSessions/add.html b/pgtbl/modules/templates/modules/add.html similarity index 93% rename from pgtbl/TBLSessions/templates/TBLSessions/add.html rename to pgtbl/modules/templates/modules/add.html index 0ba4363..d2cab39 100644 --- a/pgtbl/TBLSessions/templates/TBLSessions/add.html +++ b/pgtbl/modules/templates/modules/add.html @@ -15,7 +15,7 @@
- {% include 'groups/delete.html' %} + {% include 'groups/delete.html' %} diff --git a/pgtbl/questions/templates/exercise/list.html b/pgtbl/questions/templates/exercise/list.html index 48308d6..27db65f 100644 --- a/pgtbl/questions/templates/exercise/list.html +++ b/pgtbl/questions/templates/exercise/list.html @@ -76,7 +76,7 @@

{% if user == discipline.teacher or user in discipline.monitors.all %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

@@ -104,7 +104,7 @@

{% else %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

diff --git a/pgtbl/questions/templates/grat/grat.html b/pgtbl/questions/templates/grat/grat.html index 4926a41..16ab75b 100644 --- a/pgtbl/questions/templates/grat/grat.html +++ b/pgtbl/questions/templates/grat/grat.html @@ -114,7 +114,7 @@

{% if user == discipline.teacher %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

@@ -142,7 +142,7 @@

{% else %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

diff --git a/pgtbl/questions/templates/irat/irat.html b/pgtbl/questions/templates/irat/irat.html index 78e61cd..bc10f4d 100644 --- a/pgtbl/questions/templates/irat/irat.html +++ b/pgtbl/questions/templates/irat/irat.html @@ -114,7 +114,7 @@

{% if user == discipline.teacher %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

@@ -142,7 +142,7 @@

{% else %}
-

+

{{page_obj.number}}) {{question.title}}
{{question.topic}} - ({{question.level}})

From 459d24f5aa7c796c4277c1d5c57de09ffa3d3827 Mon Sep 17 00:00:00 2001 From: Victor Arnaud Date: Sun, 15 Jul 2018 17:52:44 -0300 Subject: [PATCH 56/56] Fix MediaOrderConflictWarning exception --- .../templates/disciplines/form.html | 27 +-- .../templates/files/discipline/form.html | 9 - pgtbl/files/templates/files/module/form.html | 9 - pgtbl/grades/templates/grades/form.html | 9 - pgtbl/groups/templates/groups/form.html | 9 - pgtbl/modules/templates/modules/form.html | 17 +- .../templates/practical_test/update.html | 8 +- pgtbl/questions/templates/questions/add.html | 177 ------------------ .../questions/{update.html => form.html} | 38 ++-- .../views/question/create_question_view.py | 2 +- .../views/question/update_question_view.py | 2 +- 11 files changed, 49 insertions(+), 258 deletions(-) delete mode 100644 pgtbl/questions/templates/questions/add.html rename pgtbl/questions/templates/questions/{update.html => form.html} (86%) diff --git a/pgtbl/disciplines/templates/disciplines/form.html b/pgtbl/disciplines/templates/disciplines/form.html index fc69b1e..e33830b 100644 --- a/pgtbl/disciplines/templates/disciplines/form.html +++ b/pgtbl/disciplines/templates/disciplines/form.html @@ -6,16 +6,13 @@ - {{form.media}} -{% endblock %} - -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Create Discipline' %} - -
  • + + + + + + + {% endblock %} {% block content %} @@ -59,6 +56,7 @@

    name="{{form.title.name}}" class="form-control" placeholder="{{form.title.help_text}}" + value="{{discipline.title}}" required />

    @@ -88,6 +86,7 @@

    name="{{form.course.name}}" class="form-control" placeholder="{{form.course.help_text}}" + value="{{discipline.course}}" />

    @@ -110,7 +109,7 @@

    name="{{form.description.name}}" placeholder="{{form.description.help_text}}" id="{{form.description.id_for_label}}" - cols="130" rows="10"> + cols="130" rows="10">{{discipline.description}}

    @@ -149,6 +148,7 @@

    name="{{form.classroom.name}}" class="form-control" placeholder="{{form.classroom.help_text}}" + value="{{discipline.classroom}}" required />

    @@ -178,6 +178,7 @@

    name="{{form.password.name}}" class="form-control" placeholder="{{form.password.help_text}}" + value="{{discipline.password}}" />

    @@ -204,11 +205,11 @@

    @@ -236,7 +237,7 @@

    {% endblock %} -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Edit' %} {{file}} - -
  • -{% endblock %} - {% block content %}
    diff --git a/pgtbl/files/templates/files/module/form.html b/pgtbl/files/templates/files/module/form.html index f4d8db2..4eabeaa 100644 --- a/pgtbl/files/templates/files/module/form.html +++ b/pgtbl/files/templates/files/module/form.html @@ -7,15 +7,6 @@ {% endblock %} -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Edit' %} {{file}} - -
  • -{% endblock %} - {% block content %}
    diff --git a/pgtbl/grades/templates/grades/form.html b/pgtbl/grades/templates/grades/form.html index 9e2a404..8007be7 100644 --- a/pgtbl/grades/templates/grades/form.html +++ b/pgtbl/grades/templates/grades/form.html @@ -8,15 +8,6 @@ {% endblock %} -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Edit grade' %} - -
  • -{% endblock %} - {% block content %}
    diff --git a/pgtbl/groups/templates/groups/form.html b/pgtbl/groups/templates/groups/form.html index 2d62011..fd0cc5f 100644 --- a/pgtbl/groups/templates/groups/form.html +++ b/pgtbl/groups/templates/groups/form.html @@ -7,15 +7,6 @@ {% endblock %} -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Edit' %} {{group}} - -
  • -{% endblock %} - {% block content %}
    diff --git a/pgtbl/modules/templates/modules/form.html b/pgtbl/modules/templates/modules/form.html index 7dce422..279e420 100644 --- a/pgtbl/modules/templates/modules/form.html +++ b/pgtbl/modules/templates/modules/form.html @@ -6,16 +6,13 @@ - {{form.media}} -{% endblock %} - -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Edit' %} {{session}} - -
  • + + + + + + + {% endblock %} {% block content %} diff --git a/pgtbl/modules/templates/practical_test/update.html b/pgtbl/modules/templates/practical_test/update.html index a3a6a77..9f01227 100644 --- a/pgtbl/modules/templates/practical_test/update.html +++ b/pgtbl/modules/templates/practical_test/update.html @@ -6,7 +6,13 @@ - {{form.media}} + + + + + + + {% endblock %} {% block breadcrumb %} diff --git a/pgtbl/questions/templates/questions/add.html b/pgtbl/questions/templates/questions/add.html deleted file mode 100644 index b4bd1d1..0000000 --- a/pgtbl/questions/templates/questions/add.html +++ /dev/null @@ -1,177 +0,0 @@ -{% extends 'exercise/list.html' %} -{% load static %} -{% load i18n %} - -{% block css %} - - -{% endblock %} - -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Create Question' %} - -
  • -{% endblock %} - -{% block content %} -
    - - - - -
    -
    - - - - {% csrf_token %} - - - {% for error in form.non_field_errors %} -
    - {{ error }} -
    - {% endfor %} - - -
    - -
    - - - - - - - -
    - - - {% for error in form.title.errors %} - - {{ error }} - - {% endfor %} -
    - - -
    - -
    - - - - - - - -
    - - - {% for error in form.topic.errors %} - - {{ error }} - - {% endfor %} -
    - - -
    - -
    - -
    - - - {% for error in form.level.errors %} - - {{ error }} - - {% endfor %} -
    - - -
    - -
    - -
    - - - {% for error in form.is_exercise.errors %} - - {{ error }} - - {% endfor %} -
    - - -
    - {% trans 'Alternatives' %} - - {{ alternatives.management_form }} - - {% for form in alternatives.forms %} - - {% for hidden in form.hidden_fields %} - {{ hidden }} - {% endfor %} - -
    - -
    -
    - {{form.is_correct}} - {{ form.is_correct.label|capfirst }} -
    - {% endfor %} -
    - - - - -
    -
    -
    -{% endblock %} diff --git a/pgtbl/questions/templates/questions/update.html b/pgtbl/questions/templates/questions/form.html similarity index 86% rename from pgtbl/questions/templates/questions/update.html rename to pgtbl/questions/templates/questions/form.html index 230d608..eda4e9d 100644 --- a/pgtbl/questions/templates/questions/update.html +++ b/pgtbl/questions/templates/questions/form.html @@ -7,15 +7,6 @@ {% endblock %} -{% block breadcrumb %} - {{ block.super }} -
  • - - {% trans 'Update Question' %} - -
  • -{% endblock %} - {% block content %}
    @@ -30,7 +21,7 @@

    -
    + {% csrf_token %} @@ -149,13 +140,22 @@

    {% endfor %}
    - + {% if form.title.value %} + + {% else %} + + {% endif %}
    {{form.is_correct}} @@ -167,8 +167,8 @@

    diff --git a/pgtbl/questions/views/question/create_question_view.py b/pgtbl/questions/views/question/create_question_view.py index d05a40d..44d9cdf 100644 --- a/pgtbl/questions/views/question/create_question_view.py +++ b/pgtbl/questions/views/question/create_question_view.py @@ -22,7 +22,7 @@ class CreateQuestionView(LoginRequiredMixin, model = Question fields = ['title', 'level', 'topic', 'is_exercise'] - template_name = 'questions/add.html' + template_name = 'questions/form.html' permissions_required = [ 'crud_question_permission' diff --git a/pgtbl/questions/views/question/update_question_view.py b/pgtbl/questions/views/question/update_question_view.py index 51e24a8..c9f267a 100644 --- a/pgtbl/questions/views/question/update_question_view.py +++ b/pgtbl/questions/views/question/update_question_view.py @@ -22,7 +22,7 @@ class UpdateQuestionView(LoginRequiredMixin, model = Question fields = ['title', 'level', 'topic', 'is_exercise'] - template_name = 'questions/update.html' + template_name = 'questions/form.html' permissions_required = [ 'crud_question_permission'