mirror of https://github.com/ae-utbm/sith3.git
Compare commits
15 Commits
b49f204e20
...
358a625cc4
Author | SHA1 | Date |
---|---|---|
Antoine Bartuccio | 358a625cc4 | |
Antoine Bartuccio | d44fa73b2a | |
Antoine Bartuccio | 5ccb499665 | |
Antoine Bartuccio | c467165bf3 | |
Antoine Bartuccio | 8512f3c5d0 | |
Antoine Bartuccio | 5003e57338 | |
Antoine Bartuccio | b7c2da53fe | |
Antoine Bartuccio | 598cdc0284 | |
Antoine Bartuccio | 692d9a25e3 | |
Antoine Bartuccio | 38f6c27983 | |
Antoine Bartuccio | 1172402166 | |
Antoine Bartuccio | ab344ba02f | |
Antoine Bartuccio | ec33311715 | |
Antoine Bartuccio | 5bf5d0277c | |
Antoine Bartuccio | 31f6ee9ca4 |
|
@ -52,6 +52,7 @@ from counter.models import Customer, ProductType, Product, Counter, Selling, Stu
|
|||
from com.models import Sith, Weekmail, News, NewsDate
|
||||
from election.models import Election, Role, Candidature, ElectionList
|
||||
from forum.models import Forum, ForumTopic
|
||||
from pedagogy.models import UV
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -84,6 +85,7 @@ class Command(BaseCommand):
|
|||
Group(name="Banned to subscribe").save()
|
||||
Group(name="SAS admin").save()
|
||||
Group(name="Forum admin").save()
|
||||
Group(name="Pedagogy admin").save()
|
||||
self.reset_index("core", "auth")
|
||||
root = User(
|
||||
id=0,
|
||||
|
@ -857,6 +859,18 @@ Welcome to the wiki page!
|
|||
start_date=timezone.now(),
|
||||
role=settings.SITH_CLUB_ROLES_ID["Board member"],
|
||||
).save()
|
||||
# Adding user tutu
|
||||
tutu = User(
|
||||
username="tutu",
|
||||
last_name="Tu",
|
||||
first_name="Tu",
|
||||
email="tutu@git.an",
|
||||
date_of_birth="1942-06-12",
|
||||
)
|
||||
tutu.set_password("plop")
|
||||
tutu.save()
|
||||
tutu.groups = [settings.SITH_GROUP_PEDAGOGY_ADMIN_ID]
|
||||
tutu.save()
|
||||
|
||||
# Adding subscription for sli
|
||||
s = Subscription(
|
||||
|
@ -895,6 +909,18 @@ Welcome to the wiki page!
|
|||
start=s.subscription_start,
|
||||
)
|
||||
s.save()
|
||||
# Tutu
|
||||
s = Subscription(
|
||||
member=tutu,
|
||||
subscription_type=default_subscription,
|
||||
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
||||
)
|
||||
s.subscription_start = s.compute_start()
|
||||
s.subscription_end = s.compute_end(
|
||||
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]["duration"],
|
||||
start=s.subscription_start,
|
||||
)
|
||||
s.save()
|
||||
|
||||
Selling(
|
||||
label=dcons.name,
|
||||
|
@ -1077,3 +1103,35 @@ Welcome to the wiki page!
|
|||
start_date=friday + timedelta(hours=24 * 7 * i),
|
||||
end_date=friday + timedelta(hours=24 * 7 * i + 8),
|
||||
).save()
|
||||
|
||||
# Create som data for pedagogy
|
||||
|
||||
UV(
|
||||
code="PA00",
|
||||
author=User.objects.get(id=0),
|
||||
credit_type=settings.SITH_PEDAGOGY_UV_TYPE[3][0],
|
||||
manager="Laurent HEYBERGER",
|
||||
semester=settings.SITH_PEDAGOGY_UV_SEMESTER[3][0],
|
||||
language=settings.SITH_PEDAGOGY_UV_LANGUAGE[0][0],
|
||||
department=settings.SITH_PROFILE_DEPARTMENTS[-2][0],
|
||||
credits=5,
|
||||
title="Participation dans une association étudiante",
|
||||
objectives="* Permettre aux étudiants de réaliser, pendant un semestre, un projet culturel ou associatif et de le valoriser.",
|
||||
program="""* Semestre précédent proposition d'un projet et d'un cahier des charges
|
||||
* Evaluation par un jury de six membres
|
||||
* Si accord réalisation dans le cadre de l'UV
|
||||
* Compte-rendu de l'expérience
|
||||
* Présentation""",
|
||||
skills="""* Gérer un projet associatif ou une action éducative en autonomie:
|
||||
* en produisant un cahier des charges qui -définit clairement le contexte du projet personnel -pose les jalons de ce projet -estime de manière réaliste les moyens et objectifs du projet -définit exactement les livrables attendus
|
||||
* en étant capable de respecter ce cahier des charges ou, le cas échéant, de réviser le cahier des charges de manière argumentée.
|
||||
* Relater son expérience dans un rapport:
|
||||
* qui permettra à d'autres étudiants de poursuivre les actions engagées
|
||||
* qui montre la capacité à s'auto-évaluer et à adopter une distance critique sur son action.""",
|
||||
key_concepts="""* Autonomie
|
||||
* Responsabilité
|
||||
* Cahier des charges
|
||||
* Gestion de projet""",
|
||||
hours_THE=121,
|
||||
hours_TE=4,
|
||||
).save()
|
||||
|
|
|
@ -670,6 +670,10 @@ class AnonymousUser(AuthAnonymousUser):
|
|||
def was_subscribed(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_subscribed(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def subscribed(self):
|
||||
return False
|
||||
|
|
|
@ -185,7 +185,7 @@
|
|||
<a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a>
|
||||
<a href="/launderette">{% trans %}Launderette{% endtrans %}</a>
|
||||
<a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a>
|
||||
{# <a href="https://ae2.utbm.fr/uvs/">{% trans %}Pedagogy{% endtrans %}</a> #}
|
||||
<a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
# -*- coding:utf-8 -*
|
||||
#
|
||||
# Copyright 2016,2017
|
||||
# - Skia <skia@libskia.so>
|
||||
#
|
||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
||||
# http://ae.utbm.fr.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License a published by the Free Software
|
||||
# Foundation; either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
|
||||
from django import forms
|
||||
|
||||
from core.views.forms import MarkdownInput
|
||||
from core.models import User
|
||||
|
||||
from pedagogy.models import UV, UVComment
|
||||
|
||||
|
||||
class UVForm(forms.ModelForm):
|
||||
"""
|
||||
Form handeling creation and edit of an UV
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = UV
|
||||
fields = (
|
||||
"code",
|
||||
"author",
|
||||
"credit_type",
|
||||
"semester",
|
||||
"language",
|
||||
"department",
|
||||
"credits",
|
||||
"hours_CM",
|
||||
"hours_TD",
|
||||
"hours_TP",
|
||||
"hours_THE",
|
||||
"hours_TE",
|
||||
"manager",
|
||||
"title",
|
||||
"objectives",
|
||||
"program",
|
||||
"skills",
|
||||
"key_concepts",
|
||||
)
|
||||
widgets = {
|
||||
"objectives": MarkdownInput,
|
||||
"program": MarkdownInput,
|
||||
"skills": MarkdownInput,
|
||||
"key_concepts": MarkdownInput,
|
||||
"author": forms.HiddenInput,
|
||||
}
|
||||
|
||||
def __init__(self, author_id, *args, **kwargs):
|
||||
super(UVForm, self).__init__(*args, **kwargs)
|
||||
self.fields["author"].queryset = User.objects.filter(id=author_id).all()
|
||||
self.fields["author"].initial = author_id
|
||||
|
||||
|
||||
class UVCommentForm(forms.ModelForm):
|
||||
"""
|
||||
Form handeling creation and edit of an UVComment
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = UVComment
|
||||
fields = (
|
||||
"author",
|
||||
"uv",
|
||||
"grade_global",
|
||||
"grade_utility",
|
||||
"grade_interest",
|
||||
"grade_teaching",
|
||||
"grade_work_load",
|
||||
"comment",
|
||||
)
|
||||
widgets = {
|
||||
"comment": MarkdownInput,
|
||||
"author": forms.HiddenInput,
|
||||
"uv": forms.HiddenInput,
|
||||
}
|
||||
|
||||
def __init__(self, author_id, uv_id, *args, **kwargs):
|
||||
super(UVCommentForm, self).__init__(*args, **kwargs)
|
||||
self.fields["author"].queryset = User.objects.filter(id=author_id).all()
|
||||
self.fields["author"].initial = author_id
|
||||
self.fields["uv"].queryset = UV.objects.filter(id=uv_id).all()
|
||||
self.fields["uv"].initial = uv_id
|
|
@ -0,0 +1,347 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-06-18 08:52
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="UV",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"code",
|
||||
models.CharField(
|
||||
max_length=10,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
message="The code of an UV must only contains uppercase characters without accent and numbers",
|
||||
regex="([A-Z0-9]+)",
|
||||
)
|
||||
],
|
||||
verbose_name="code",
|
||||
),
|
||||
),
|
||||
(
|
||||
"credit_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("FREE", "Free"),
|
||||
("CS", "CS"),
|
||||
("TM", "TM"),
|
||||
("OM", "OM"),
|
||||
("QC", "QC"),
|
||||
("EC", "EC"),
|
||||
("RN", "RN"),
|
||||
("ST", "ST"),
|
||||
("EXT", "EXT"),
|
||||
],
|
||||
default="FREE",
|
||||
max_length=10,
|
||||
verbose_name="credit type",
|
||||
),
|
||||
),
|
||||
(
|
||||
"semester",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("CLOSED", "Closed"),
|
||||
("AUTUMN", "Autumn"),
|
||||
("SPRING", "Spring"),
|
||||
("AUTOMN_AND_SPRING", "Autumn and spring"),
|
||||
],
|
||||
default="CLOSED",
|
||||
max_length=20,
|
||||
verbose_name="semester",
|
||||
),
|
||||
),
|
||||
(
|
||||
"language",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("FR", "French"),
|
||||
("EN", "English"),
|
||||
("DE", "German"),
|
||||
("SP", "Spanich"),
|
||||
],
|
||||
default="FR",
|
||||
max_length=10,
|
||||
verbose_name="language",
|
||||
),
|
||||
),
|
||||
(
|
||||
"credits",
|
||||
models.IntegerField(
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="credits",
|
||||
),
|
||||
),
|
||||
(
|
||||
"department",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("TC", "TC"),
|
||||
("IMSI", "IMSI"),
|
||||
("IMAP", "IMAP"),
|
||||
("INFO", "INFO"),
|
||||
("GI", "GI"),
|
||||
("E", "E"),
|
||||
("EE", "EE"),
|
||||
("GESC", "GESC"),
|
||||
("GMC", "GMC"),
|
||||
("MC", "MC"),
|
||||
("EDIM", "EDIM"),
|
||||
("HUMA", "Humanities"),
|
||||
("NA", "N/A"),
|
||||
],
|
||||
default="NA",
|
||||
max_length=10,
|
||||
verbose_name="departmenmt",
|
||||
),
|
||||
),
|
||||
("title", models.CharField(max_length=300, verbose_name="title")),
|
||||
(
|
||||
"manager",
|
||||
models.CharField(max_length=300, verbose_name="uv manager"),
|
||||
),
|
||||
("objectives", models.TextField(verbose_name="objectives")),
|
||||
("program", models.TextField(verbose_name="program")),
|
||||
("skills", models.TextField(verbose_name="skills")),
|
||||
("key_concepts", models.TextField(verbose_name="key concepts")),
|
||||
(
|
||||
"hours_CM",
|
||||
models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="hours CM",
|
||||
),
|
||||
),
|
||||
(
|
||||
"hours_TD",
|
||||
models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="hours TD",
|
||||
),
|
||||
),
|
||||
(
|
||||
"hours_TP",
|
||||
models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="hours TP",
|
||||
),
|
||||
),
|
||||
(
|
||||
"hours_THE",
|
||||
models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="hours THE",
|
||||
),
|
||||
),
|
||||
(
|
||||
"hours_TE",
|
||||
models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="hours TE",
|
||||
),
|
||||
),
|
||||
(
|
||||
"author",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="uv_created",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="author",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UVComment",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("comment", models.TextField(verbose_name="comment")),
|
||||
(
|
||||
"grade_global",
|
||||
models.IntegerField(
|
||||
default=-1,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(-1),
|
||||
django.core.validators.MaxValueValidator(4),
|
||||
],
|
||||
verbose_name="global grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"grade_utility",
|
||||
models.IntegerField(
|
||||
default=-1,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(-1),
|
||||
django.core.validators.MaxValueValidator(4),
|
||||
],
|
||||
verbose_name="utility grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"grade_interest",
|
||||
models.IntegerField(
|
||||
default=-1,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(-1),
|
||||
django.core.validators.MaxValueValidator(4),
|
||||
],
|
||||
verbose_name="interest grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"grade_teaching",
|
||||
models.IntegerField(
|
||||
default=-1,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(-1),
|
||||
django.core.validators.MaxValueValidator(4),
|
||||
],
|
||||
verbose_name="teaching grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"grade_work_load",
|
||||
models.IntegerField(
|
||||
default=-1,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(-1),
|
||||
django.core.validators.MaxValueValidator(4),
|
||||
],
|
||||
verbose_name="work load grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"publish_date",
|
||||
models.DateField(auto_now=True, verbose_name="publish date"),
|
||||
),
|
||||
(
|
||||
"author",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="uv_comments",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="author",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uv",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="comments",
|
||||
to="pedagogy.UV",
|
||||
verbose_name="uv",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UVCommentReport",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UVResult",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"grade",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("A", "A"),
|
||||
("B", "B"),
|
||||
("C", "C"),
|
||||
("D", "D"),
|
||||
("E", "E"),
|
||||
("FX", "FX"),
|
||||
("F", "F"),
|
||||
("ABS", "Abs"),
|
||||
],
|
||||
default="A",
|
||||
max_length=10,
|
||||
verbose_name="grade",
|
||||
),
|
||||
),
|
||||
(
|
||||
"semester",
|
||||
models.CharField(
|
||||
max_length=5,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator("[AP][0-9]{3}")
|
||||
],
|
||||
verbose_name="semester",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="uv_results",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="user",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uv",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="results",
|
||||
to="pedagogy.UV",
|
||||
verbose_name="uv",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -23,6 +23,11 @@
|
|||
#
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core import validators
|
||||
from django.conf import settings
|
||||
|
||||
from core.models import User
|
||||
|
||||
# Create your models here.
|
||||
|
||||
|
@ -32,7 +37,120 @@ class UV(models.Model):
|
|||
Contains infos about an UV (course)
|
||||
"""
|
||||
|
||||
pass
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
Can be created by superuser, root or pedagogy admin user
|
||||
"""
|
||||
return user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
|
||||
def can_be_viewed_by(self, user):
|
||||
"""
|
||||
Only visible by subscribers
|
||||
"""
|
||||
return user.is_subscribed
|
||||
|
||||
def __str__(self):
|
||||
return self.code
|
||||
|
||||
code = models.CharField(
|
||||
_("code"),
|
||||
max_length=10,
|
||||
unique=True,
|
||||
validators=[
|
||||
validators.RegexValidator(
|
||||
regex="([A-Z0-9]+)",
|
||||
message=_(
|
||||
"The code of an UV must only contains uppercase characters without accent and numbers"
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
author = models.ForeignKey(
|
||||
User,
|
||||
related_name="uv_created",
|
||||
verbose_name=_("author"),
|
||||
null=False,
|
||||
blank=False,
|
||||
)
|
||||
credit_type = models.CharField(
|
||||
_("credit type"),
|
||||
max_length=10,
|
||||
choices=settings.SITH_PEDAGOGY_UV_TYPE,
|
||||
default=settings.SITH_PEDAGOGY_UV_TYPE[0][0],
|
||||
)
|
||||
manager = models.CharField(_("uv manager"), max_length=300)
|
||||
semester = models.CharField(
|
||||
_("semester"),
|
||||
max_length=20,
|
||||
choices=settings.SITH_PEDAGOGY_UV_SEMESTER,
|
||||
default=settings.SITH_PEDAGOGY_UV_SEMESTER[0][0],
|
||||
)
|
||||
language = models.CharField(
|
||||
_("language"),
|
||||
max_length=10,
|
||||
choices=settings.SITH_PEDAGOGY_UV_LANGUAGE,
|
||||
default=settings.SITH_PEDAGOGY_UV_LANGUAGE[0][0],
|
||||
)
|
||||
credits = models.IntegerField(
|
||||
_("credits"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
)
|
||||
# Double star type not implemented yet
|
||||
|
||||
department = models.CharField(
|
||||
_("departmenmt"),
|
||||
max_length=10,
|
||||
choices=settings.SITH_PROFILE_DEPARTMENTS,
|
||||
default=settings.SITH_PROFILE_DEPARTMENTS[-1][0],
|
||||
)
|
||||
|
||||
# All texts about the UV
|
||||
title = models.CharField(_("title"), max_length=300)
|
||||
manager = models.CharField(_("uv manager"), max_length=300)
|
||||
objectives = models.TextField(_("objectives"))
|
||||
program = models.TextField(_("program"))
|
||||
skills = models.TextField(_("skills"))
|
||||
key_concepts = models.TextField(_("key concepts"))
|
||||
|
||||
# Hours types CM, TD, TP, THE and TE
|
||||
# Kind of dirty but I have nothing else in mind for now
|
||||
hours_CM = models.IntegerField(
|
||||
_("hours CM"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=0,
|
||||
)
|
||||
hours_TD = models.IntegerField(
|
||||
_("hours TD"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=0,
|
||||
)
|
||||
hours_TP = models.IntegerField(
|
||||
_("hours TP"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=0,
|
||||
)
|
||||
hours_THE = models.IntegerField(
|
||||
_("hours THE"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=0,
|
||||
)
|
||||
hours_TE = models.IntegerField(
|
||||
_("hours TE"),
|
||||
validators=[validators.MinValueValidator(0)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=0,
|
||||
)
|
||||
|
||||
|
||||
class UVComment(models.Model):
|
||||
|
@ -40,7 +158,86 @@ class UVComment(models.Model):
|
|||
A comment about an UV
|
||||
"""
|
||||
|
||||
pass
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
Is owned by a pedagogy admin, a superuser or the author himself
|
||||
"""
|
||||
return self.author == user or user.is_owner(self.uv)
|
||||
|
||||
def __str__(self):
|
||||
return "%s - %s" % (self.uv, self.author)
|
||||
|
||||
author = models.ForeignKey(
|
||||
User,
|
||||
related_name="uv_comments",
|
||||
verbose_name=_("author"),
|
||||
null=False,
|
||||
blank=False,
|
||||
)
|
||||
uv = models.ForeignKey(UV, related_name="comments", verbose_name=_("uv"))
|
||||
comment = models.TextField(_("comment"))
|
||||
grade_global = models.IntegerField(
|
||||
_("global grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=-1,
|
||||
)
|
||||
grade_utility = models.IntegerField(
|
||||
_("utility grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=-1,
|
||||
)
|
||||
grade_interest = models.IntegerField(
|
||||
_("interest grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=-1,
|
||||
)
|
||||
grade_teaching = models.IntegerField(
|
||||
_("teaching grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=-1,
|
||||
)
|
||||
grade_work_load = models.IntegerField(
|
||||
_("work load grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
blank=False,
|
||||
null=False,
|
||||
default=-1,
|
||||
)
|
||||
publish_date = models.DateField(_("publish date"), auto_now=True)
|
||||
|
||||
|
||||
class UVResult(models.Model):
|
||||
"""
|
||||
Results got to an UV
|
||||
Views will be implemented after the first release
|
||||
Will list every UV done by an user
|
||||
Linked to user
|
||||
uv
|
||||
Contains a grade settings.SITH_PEDAGOGY_UV_RESULT_GRADE
|
||||
a semester (P/A)20xx
|
||||
"""
|
||||
|
||||
uv = models.ForeignKey(UV, related_name="results", verbose_name=_("uv"))
|
||||
user = models.ForeignKey(User, related_name="uv_results", verbose_name=("user"))
|
||||
grade = models.CharField(
|
||||
_("grade"),
|
||||
max_length=10,
|
||||
choices=settings.SITH_PEDAGOGY_UV_RESULT_GRADE,
|
||||
default=settings.SITH_PEDAGOGY_UV_RESULT_GRADE[0][0],
|
||||
)
|
||||
semester = models.CharField(
|
||||
_("semester"),
|
||||
max_length=5,
|
||||
validators=[validators.RegexValidator("[AP][0-9]{3}")],
|
||||
)
|
||||
|
||||
|
||||
class UVCommentReport(models.Model):
|
||||
|
@ -49,19 +246,3 @@ class UVCommentReport(models.Model):
|
|||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class EducationDepartment(models.Model):
|
||||
"""
|
||||
Education department of the school
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class StudyField(models.Model):
|
||||
"""
|
||||
Speciality inside an Education Department
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}UV Guide{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if can_create_uv(user) %}
|
||||
<p>
|
||||
<a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% for uv in object_list %}
|
||||
<p>
|
||||
<a href="{{ url('pedagogy:uv_detail', uv_id=uv.id) }}">{{ uv.code }}</a>
|
||||
{% if user.is_owner(uv) -%}
|
||||
<a href="{{ url('pedagogy:uv_update', uv_id=uv.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('pedagogy:uv_delete', uv_id=uv.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{%- endif -%}
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% endblock content %}
|
|
@ -0,0 +1,40 @@
|
|||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}UV Details{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p><a href="{{ url('pedagogy:guide') }}">{% trans %}Back{% endtrans %}</a></p>
|
||||
<h1>{{ object.code }} - {{ object.title }}</h1>
|
||||
<p>{% trans %}Department: {% endtrans %}{{ object.department }}</p>
|
||||
<p>{{ object.objectives|markdown }}</p>
|
||||
<p>{{ object.program|markdown }}</p>
|
||||
<p>{{ object.skills|markdown }}</p>
|
||||
<p>{{ object.key_concepts|markdown }}</p>
|
||||
|
||||
{% if object.comments.exists() %}
|
||||
<h2>{% trans %}Comments{% endtrans %}</h2>
|
||||
{% for comment in object.comments.all() %}
|
||||
<p>{{ comment.grade_global }}</p>
|
||||
<p>{{ comment.grade_utility }}</p>
|
||||
<p>{{ comment.grade_interest }}</p>
|
||||
<p>{{ comment.grade_teaching }}</p>
|
||||
<p>{{ comment.grade_work_load }}</p>
|
||||
<p>{{ comment.comment }}</p>
|
||||
<p>{% trans %}Published: {% endtrans %}{{ comment.publish_date }}</p>
|
||||
<p>{% trans %}Author: {% endtrans %}{{ comment.author }}</p>
|
||||
{% if user.is_owner(comment) %}
|
||||
<p><a href="{{ url('pedagogy:comment_update', comment_id=comment.id) }}">{% trans %}Edit{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('pedagogy:comment_delete', comment_id=comment.id) }}">{% trans %}Delete{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans %}Leave comment{% endtrans %}</h2>
|
||||
<form action="{{ url('pedagogy:uv_detail', uv_id=object.id) }}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Comment{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -23,5 +23,546 @@
|
|||
#
|
||||
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.management import call_command
|
||||
|
||||
# Create your tests here.
|
||||
from core.models import User
|
||||
|
||||
from pedagogy.models import UV, UVComment
|
||||
|
||||
|
||||
def create_uv_template(user_id, code="IFC1", exclude_list=[]):
|
||||
"""
|
||||
Factory to help UV creation/update in post requests
|
||||
"""
|
||||
uv = {
|
||||
"code": code,
|
||||
"author": user_id,
|
||||
"credit_type": "TM",
|
||||
"semester": "SPRING",
|
||||
"language": "FR",
|
||||
"department": "TC",
|
||||
"credits": 3,
|
||||
"hours_CM": 10,
|
||||
"hours_TD": 28,
|
||||
"hours_TP": 0,
|
||||
"hours_THE": 37,
|
||||
"hours_TE": 0,
|
||||
"manager": "Gilles BERTRAND",
|
||||
"title": "Algorithmique et programmation : niveau I, initiés - partie I",
|
||||
"objectives": """* Introduction à l'algorithmique et à la programmation pour initiés.
|
||||
* Pratiques et développement en langage C.""",
|
||||
"program": """* Découverte des outils élémentaires utilisés pour écrire, compiler et exécuter un programme écrit en langage C
|
||||
* Règles de programmation : normes en cours, règles de présentation du code, commentaires
|
||||
* Initiation à l'algorithmique et découverte des bases du langage C :
|
||||
* les conditions
|
||||
* les boucles
|
||||
* les types de données
|
||||
* les tableaux à une dimension
|
||||
* manipulations des chaînes de caractères
|
||||
* les fonctions et procédures""",
|
||||
"skills": "* D'écrire un algorithme et de l'implémenter en C",
|
||||
"key_concepts": """* Algorithme
|
||||
* Variables scalaires et vectorielles
|
||||
* Structures alternatives, répétitives
|
||||
* Fonctions, procédures
|
||||
* Chaînes de caractères""",
|
||||
}
|
||||
for excluded in exclude_list:
|
||||
uv.pop(excluded)
|
||||
return uv
|
||||
|
||||
|
||||
# UV class tests
|
||||
|
||||
|
||||
class UVCreation(TestCase):
|
||||
"""
|
||||
Test uv creation
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
self.bibou = User.objects.filter(username="root").first()
|
||||
self.tutu = User.objects.filter(username="tutu").first()
|
||||
self.sli = User.objects.filter(username="sli").first()
|
||||
self.guy = User.objects.filter(username="guy").first()
|
||||
|
||||
def test_create_uv_admin_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(self.bibou.id)
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
self.assertTrue(UV.objects.filter(code="IFC1").exists())
|
||||
|
||||
def test_create_uv_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(self.tutu.id)
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
self.assertTrue(UV.objects.filter(code="IFC1").exists())
|
||||
|
||||
def test_create_uv_unauthorized_fail(self):
|
||||
# Test with anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(0)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Test with subscribed user
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(self.sli.id)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Test with non subscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(self.guy.id)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the UV has never been created
|
||||
self.assertFalse(UV.objects.filter(code="IFC1").exists())
|
||||
|
||||
def test_create_uv_bad_request_fail(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
|
||||
# Test with wrong user id (if someone cheats on the hidden input)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"), create_uv_template(self.bibou.id)
|
||||
)
|
||||
self.assertNotEquals(response.status_code, 302)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
# Remove a required field
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_create"),
|
||||
create_uv_template(self.tutu.id, exclude_list=["title"]),
|
||||
)
|
||||
self.assertNotEquals(response.status_code, 302)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
# Check that the UV hase never been created
|
||||
self.assertFalse(UV.objects.filter(code="IFC1").exists())
|
||||
|
||||
|
||||
class UVListTest(TestCase):
|
||||
"""
|
||||
Test guide display rights
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
def test_uv_list_display_success(self):
|
||||
# Display for root
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:guide"))
|
||||
self.assertContains(response, text="PA00")
|
||||
|
||||
# Display for pedagogy admin
|
||||
self.client.login(username="tutu", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:guide"))
|
||||
self.assertContains(response, text="PA00")
|
||||
|
||||
# Display for simple subscriber
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:guide"))
|
||||
self.assertContains(response, text="PA00")
|
||||
|
||||
def test_uv_list_display_fail(self):
|
||||
# Don't display for anonymous user
|
||||
response = self.client.get(reverse("pedagogy:guide"))
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Don't display for none subscribed users
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:guide"))
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
|
||||
class UVDeleteTest(TestCase):
|
||||
"""
|
||||
Test UV deletion rights
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
def test_uv_delete_root_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_delete", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
)
|
||||
)
|
||||
self.assertFalse(UV.objects.filter(code="PA00").exists())
|
||||
|
||||
def test_uv_delete_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_delete", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
)
|
||||
)
|
||||
self.assertFalse(UV.objects.filter(code="PA00").exists())
|
||||
|
||||
def test_uv_delete_pedagogy_unauthorized_fail(self):
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_delete", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Not subscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_delete", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Simply subscribed user
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_delete", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
)
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the UV still exists
|
||||
self.assertTrue(UV.objects.filter(code="PA00").exists())
|
||||
|
||||
|
||||
class UVUpdateTest(TestCase):
|
||||
"""
|
||||
Test UV update rights
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
self.bibou = User.objects.filter(username="root").first()
|
||||
self.tutu = User.objects.filter(username="tutu").first()
|
||||
self.sli = User.objects.filter(username="sli").first()
|
||||
self.guy = User.objects.filter(username="guy").first()
|
||||
|
||||
def test_uv_update_root_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_update", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
),
|
||||
create_uv_template(self.bibou.id, code="PA00"),
|
||||
)
|
||||
self.assertEquals(UV.objects.get(code="PA00").credit_type, "TM")
|
||||
|
||||
def test_uv_update_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_update", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
),
|
||||
create_uv_template(self.tutu.id, code="PA00"),
|
||||
)
|
||||
self.assertEquals(UV.objects.get(code="PA00").credit_type, "TM")
|
||||
|
||||
def test_uv_update_pedagogy_unauthorized_fail(self):
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_update", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
),
|
||||
create_uv_template(0, code="PA00"),
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Not subscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_update", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
),
|
||||
create_uv_template(self.guy.id, code="PA00"),
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Simply subscribed user
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"pedagogy:uv_update", kwargs={"uv_id": UV.objects.get(code="PA00").id}
|
||||
),
|
||||
create_uv_template(self.sli.id, code="PA00"),
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the UV has not changed
|
||||
self.assertEquals(UV.objects.get(code="PA00").credit_type, "OM")
|
||||
|
||||
|
||||
# UVComment class tests
|
||||
|
||||
|
||||
def create_uv_comment_template(user_id, uv_code="PA00", exclude_list=[]):
|
||||
"""
|
||||
Factory to help UVComment creation/update in post requests
|
||||
"""
|
||||
comment = {
|
||||
"author": user_id,
|
||||
"uv": UV.objects.get(code=uv_code).id,
|
||||
"grade_global": 4,
|
||||
"grade_utility": 4,
|
||||
"grade_interest": 4,
|
||||
"grade_teaching": -1,
|
||||
"grade_work_load": 2,
|
||||
"comment": "Superbe UV qui fait vivre la vie associative de l'école",
|
||||
}
|
||||
for excluded in exclude_list:
|
||||
comment.pop(excluded)
|
||||
return comment
|
||||
|
||||
|
||||
class UVCommentCreationAndDisplay(TestCase):
|
||||
"""
|
||||
Test UVComment creation and it's display
|
||||
Display and creation are the same view
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
self.bibou = User.objects.filter(username="root").first()
|
||||
self.tutu = User.objects.filter(username="tutu").first()
|
||||
self.sli = User.objects.filter(username="sli").first()
|
||||
self.guy = User.objects.filter(username="guy").first()
|
||||
self.uv = UV.objects.get(code="PA00")
|
||||
|
||||
def test_create_uv_comment_admin_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(self.bibou.id),
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
response = self.client.get(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id})
|
||||
)
|
||||
self.assertContains(response, text="Superbe UV")
|
||||
|
||||
def test_create_uv_comment_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(self.tutu.id),
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
response = self.client.get(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id})
|
||||
)
|
||||
self.assertContains(response, text="Superbe UV")
|
||||
|
||||
def test_create_uv_comment_subscriber_success(self):
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(self.sli.id),
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
response = self.client.get(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id})
|
||||
)
|
||||
self.assertContains(response, text="Superbe UV")
|
||||
|
||||
def test_create_uv_comment_unauthorized_fail(self):
|
||||
# Test with anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(0),
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Test with non subscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(self.guy.id),
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the comment has never been created
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.get(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id})
|
||||
)
|
||||
self.assertNotContains(response, text="Superbe UV")
|
||||
|
||||
def test_create_uv_comment_bad_form_fail(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id}),
|
||||
create_uv_comment_template(self.bibou.id, exclude_list=["grade_global"]),
|
||||
)
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
response = self.client.get(
|
||||
reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv.id})
|
||||
)
|
||||
self.assertNotContains(response, text="Superbe UV")
|
||||
|
||||
|
||||
class UVCommentDeleteTest(TestCase):
|
||||
"""
|
||||
Test UVComment deletion rights
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
comment_kwargs = create_uv_comment_template(
|
||||
User.objects.get(username="krophil").id
|
||||
)
|
||||
comment_kwargs["author"] = User.objects.get(id=comment_kwargs["author"])
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment = UVComment(**comment_kwargs)
|
||||
self.comment.save()
|
||||
|
||||
def test_uv_comment_delete_root_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment.id).exists())
|
||||
|
||||
def test_uv_comment_delete_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment.id).exists())
|
||||
|
||||
def test_uv_comment_delete_author_success(self):
|
||||
self.client.login(username="krophil", password="plop")
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment.id).exists())
|
||||
|
||||
def test_uv_comment_delete_unauthorized_fail(self):
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Unsbscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Subscribed user (not author of the comment)
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the comment still exists
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment.id).exists())
|
||||
|
||||
|
||||
class UVCommentUpdateTest(TestCase):
|
||||
"""
|
||||
Test UVComment update rights
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
self.krophil = User.objects.get(username="krophil")
|
||||
|
||||
# Prepare a comment
|
||||
comment_kwargs = create_uv_comment_template(self.krophil.id)
|
||||
comment_kwargs["author"] = self.krophil
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment = UVComment(**comment_kwargs)
|
||||
self.comment.save()
|
||||
|
||||
# Prepare edit of this comment for post requests
|
||||
self.comment_edit = create_uv_comment_template(self.krophil.id)
|
||||
self.comment_edit["comment"] = "Edited"
|
||||
|
||||
def test_uv_comment_update_root_success(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
self.comment.refresh_from_db()
|
||||
self.assertEquals(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_pedagogy_admin_success(self):
|
||||
self.client.login(username="tutu", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
self.comment.refresh_from_db()
|
||||
self.assertEquals(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_author_success(self):
|
||||
self.client.login(username="krophil", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
self.comment.refresh_from_db()
|
||||
self.assertEquals(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_unauthorized_fail(self):
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Unsbscribed user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Subscribed user (not author of the comment)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Check that the comment hasn't change
|
||||
self.comment.refresh_from_db()
|
||||
self.assertNotEquals(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_original_author_does_not_change(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
self.comment_edit["author"] = User.objects.get(username="root").id
|
||||
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertEquals(self.comment.author, self.krophil)
|
||||
|
|
|
@ -31,9 +31,14 @@ urlpatterns = [
|
|||
url(r"^$", UVListView.as_view(), name="guide"),
|
||||
url(r"^uv/(?P<uv_id>[0-9]+)$", UVDetailFormView.as_view(), name="uv_detail"),
|
||||
url(
|
||||
r"^comment/(?P<comment_id>[0-9]+)$",
|
||||
UVCommentDetailView.as_view(),
|
||||
name="comment_detail",
|
||||
r"^comment/(?P<comment_id>[0-9]+)/edit$",
|
||||
UVCommentUpdateView.as_view(),
|
||||
name="comment_update",
|
||||
),
|
||||
url(
|
||||
r"^comment/(?P<comment_id>[0-9]+)/delete$",
|
||||
UVCommentDeleteView.as_view(),
|
||||
name="comment_delete",
|
||||
),
|
||||
url(
|
||||
r"^comment/(?P<comment_id>[0-9]+)/report$",
|
||||
|
@ -46,20 +51,5 @@ urlpatterns = [
|
|||
# Administration : Create Update Delete Edit
|
||||
url(r"^uv/create$", UVCreateView.as_view(), name="uv_create"),
|
||||
url(r"^uv/(?P<uv_id>[0-9]+)/delete$", UVDeleteView.as_view(), name="uv_delete"),
|
||||
url(
|
||||
r"^department/create$",
|
||||
EducationDepartmentCreateView.as_view(),
|
||||
name="department_create",
|
||||
),
|
||||
url(
|
||||
r"^department/(?P<department_id>[0-9]+)/delete$",
|
||||
EducationDepartmentDeleteView.as_view(),
|
||||
name="department_delete",
|
||||
),
|
||||
url(r"^study/create$", StudyFieldCreateView.as_view(), name="study_create"),
|
||||
url(
|
||||
r"^study/(?P<study_id>[0-9]+)/delete$",
|
||||
StudyFieldDeleteView.as_view(),
|
||||
name="study_delete",
|
||||
),
|
||||
url(r"^uv/(?P<uv_id>[0-9]+)/edit$", UVUpdateView.as_view(), name="uv_update"),
|
||||
]
|
||||
|
|
|
@ -22,34 +22,127 @@
|
|||
#
|
||||
#
|
||||
|
||||
from django.views.generic import CreateView, DeleteView, DetailView, ListView, FormView
|
||||
from django.views.generic import (
|
||||
CreateView,
|
||||
DeleteView,
|
||||
DetailView,
|
||||
UpdateView,
|
||||
ListView,
|
||||
FormView,
|
||||
View,
|
||||
)
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from core.views import DetailFormView
|
||||
from core.views import (
|
||||
DetailFormView,
|
||||
CanCreateMixin,
|
||||
CanEditMixin,
|
||||
CanViewMixin,
|
||||
CanEditPropMixin,
|
||||
)
|
||||
|
||||
from pedagogy.forms import UVForm, UVCommentForm
|
||||
from pedagogy.models import UV, UVComment
|
||||
|
||||
# Some mixins
|
||||
|
||||
|
||||
class UVDetailFormView(DetailFormView):
|
||||
class CanCreateUVFunctionMixin(View):
|
||||
"""
|
||||
Add the function can_create_uv(user) into the template
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def can_create_uv(user):
|
||||
"""
|
||||
Creates a dummy instance of UV and test is_owner
|
||||
"""
|
||||
return user.is_owner(UV())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""
|
||||
Pass the function to the template
|
||||
"""
|
||||
kwargs = super(CanCreateUVFunctionMixin, self).get_context_data(**kwargs)
|
||||
kwargs["can_create_uv"] = self.can_create_uv
|
||||
return kwargs
|
||||
|
||||
|
||||
# Acutal views
|
||||
|
||||
|
||||
class UVDetailFormView(CanViewMixin, CanCreateUVFunctionMixin, DetailFormView):
|
||||
"""
|
||||
Dispaly every comment of an UV and detailed infos about it
|
||||
Allow to comment the UV
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UV
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "pedagogy/uv_detail.jinja"
|
||||
form_class = UVCommentForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UVDetailFormView, self).get_form_kwargs()
|
||||
kwargs["author_id"] = self.request.user.id
|
||||
kwargs["uv_id"] = self.get_object().id
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
return super(UVDetailFormView, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy(
|
||||
"pedagogy:uv_detail", kwargs={"uv_id": self.get_object().id}
|
||||
)
|
||||
|
||||
|
||||
class UVCommentDetailView(DetailView):
|
||||
class UVCommentUpdateView(CanEditPropMixin, UpdateView):
|
||||
"""
|
||||
Display a specified UVComment (for easy sharing of the comment)
|
||||
Allow edit of a given comment
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UVComment
|
||||
form_class = UVCommentForm
|
||||
pk_url_kwarg = "comment_id"
|
||||
template_name = "core/edit.jinja"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UVCommentUpdateView, self).get_form_kwargs()
|
||||
obj = self.get_object()
|
||||
kwargs["author_id"] = obj.author.id
|
||||
kwargs["uv_id"] = obj.uv.id
|
||||
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
|
||||
|
||||
|
||||
class UVListView(ListView):
|
||||
class UVCommentDeleteView(CanEditPropMixin, DeleteView):
|
||||
"""
|
||||
Allow delete of a given comment
|
||||
"""
|
||||
|
||||
model = UVComment
|
||||
pk_url_kwarg = "comment_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
|
||||
|
||||
|
||||
class UVListView(CanViewMixin, CanCreateUVFunctionMixin, ListView):
|
||||
"""
|
||||
UV guide main page
|
||||
"""
|
||||
|
||||
pass
|
||||
# This is very basic and is prone to changment
|
||||
|
||||
model = UV
|
||||
ordering = ["code"]
|
||||
template_name = "pedagogy/guide.jinja"
|
||||
|
||||
|
||||
class UVCommentReportCreateView(CreateView):
|
||||
|
@ -76,49 +169,51 @@ class UVModerationFormView(FormView):
|
|||
pass
|
||||
|
||||
|
||||
class UVCreateView(CreateView):
|
||||
class UVCreateView(CanCreateMixin, CreateView):
|
||||
"""
|
||||
Add a new UV (Privileged)
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UV
|
||||
form_class = UVForm
|
||||
template_name = "core/edit.jinja"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UVCreateView, self).get_form_kwargs()
|
||||
kwargs["author_id"] = self.request.user.id
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})
|
||||
|
||||
|
||||
class UVDeleteView(DeleteView):
|
||||
class UVDeleteView(CanEditPropMixin, DeleteView):
|
||||
"""
|
||||
Allow to delete an UV (Privileged)
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UV
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:guide")
|
||||
|
||||
|
||||
class EducationDepartmentCreateView(CreateView):
|
||||
class UVUpdateView(CanEditPropMixin, UpdateView):
|
||||
"""
|
||||
Add a new Education Department (Privileged)
|
||||
Allow to edit an UV (Privilegied)
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UV
|
||||
form_class = UVForm
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "core/edit.jinja"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UVUpdateView, self).get_form_kwargs()
|
||||
kwargs["author_id"] = self.request.user.id
|
||||
return kwargs
|
||||
|
||||
class EducationDepartmentDeleteView(DeleteView):
|
||||
"""
|
||||
Allow to delete an Education Department (Privileged)
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class StudyFieldCreateView(CreateView):
|
||||
"""
|
||||
Add a new Study Field (Privileged)
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class StudyFieldDeleteView(DeleteView):
|
||||
"""
|
||||
Allow to delete an Study Field (Privileged)
|
||||
"""
|
||||
|
||||
pass
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})
|
||||
|
|
|
@ -322,6 +322,7 @@ SITH_GROUP_BANNED_COUNTER_ID = 9
|
|||
SITH_GROUP_BANNED_SUBSCRIPTION_ID = 10
|
||||
SITH_GROUP_SAS_ADMIN_ID = 11
|
||||
SITH_GROUP_FORUM_ADMIN_ID = 12
|
||||
SITH_GROUP_PEDAGOGY_ADMIN_ID = 13
|
||||
|
||||
|
||||
SITH_CLUB_REFOUND_ID = 89
|
||||
|
@ -404,6 +405,43 @@ SITH_COUNTER_BANK = [
|
|||
("LA-POSTE", "La Poste"),
|
||||
]
|
||||
|
||||
SITH_PEDAGOGY_UV_TYPE = [
|
||||
("FREE", _("Free")),
|
||||
("CS", _("CS")),
|
||||
("TM", _("TM")),
|
||||
("OM", _("OM")),
|
||||
("QC", _("QC")),
|
||||
("EC", _("EC")),
|
||||
("RN", _("RN")),
|
||||
("ST", _("ST")),
|
||||
("EXT", _("EXT")),
|
||||
]
|
||||
|
||||
SITH_PEDAGOGY_UV_SEMESTER = [
|
||||
("CLOSED", _("Closed")),
|
||||
("AUTUMN", _("Autumn")),
|
||||
("SPRING", _("Spring")),
|
||||
("AUTOMN_AND_SPRING", _("Autumn and spring")),
|
||||
]
|
||||
|
||||
SITH_PEDAGOGY_UV_LANGUAGE = [
|
||||
("FR", _("French")),
|
||||
("EN", _("English")),
|
||||
("DE", _("German")),
|
||||
("SP", _("Spanich")),
|
||||
]
|
||||
|
||||
SITH_PEDAGOGY_UV_RESULT_GRADE = [
|
||||
("A", _("A")),
|
||||
("B", _("B")),
|
||||
("C", _("C")),
|
||||
("D", _("D")),
|
||||
("E", _("E")),
|
||||
("FX", _("FX")),
|
||||
("F", _("F")),
|
||||
("ABS", _("Abs")),
|
||||
]
|
||||
|
||||
SITH_ECOCUP_CONS = 1152
|
||||
|
||||
SITH_ECOCUP_DECO = 1151
|
||||
|
|
Loading…
Reference in New Issue