Commit a2b431b1 authored by Sli's avatar Sli

Merge branch 'pedagogy_v2' into 'master'

New version of the pedagogy

See merge request !212
parents 78b61642 d844bccb
Pipeline #1916 passed with stage
in 23 minutes and 14 seconds
......@@ -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()
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-07-04 13:00
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [("core", "0029_auto_20180426_2013")]
operations = [
migrations.AlterField(
model_name="notification",
name="type",
field=models.CharField(
choices=[
("POSTER_MODERATION", "A new poster needs to be moderated"),
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
(
"PEDAGOGY_MODERATION",
"A new pedagogy comment has been signaled for moderation",
),
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
("FILE_MODERATION", "New files to be moderated"),
(
"SAS_MODERATION",
"There are %s pictures to be moderated in the SAS",
),
("NEW_PICTURES", "You've been identified on some pictures"),
("REFILLING", "You just refilled of %s €"),
("SELLING", "You just bought %s"),
("GENERIC", "You have a notification"),
],
default="GENERIC",
max_length=32,
verbose_name="type",
),
)
]
......@@ -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
......
This diff is collapsed.
......@@ -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">
......
......@@ -104,6 +104,16 @@
<li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
{% endfor %}
</ul>
<hr>
<h4>{% trans %}Pedagogy{% endtrans %}</h4>
<ul>
{% if user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID) or user.is_root %}
<li><a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a></li>
<li><a href="{{ url('pedagogy:moderation') }}">{% trans %}Moderate comments{% endtrans %}</a></li>
{% endif %}
</ul>
<hr>
<h4>{% trans %}Elections{% endtrans %}</h4>
<ul>
......@@ -113,6 +123,8 @@
<li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li>
{%- endif -%}
</ul>
<hr>
<h4>{% trans %}Other tools{% endtrans %}</h4>
<ul>
<li><a href="{{ url('core:to_markdown') }}">{% trans %}Convert dokuwiki/BBcode syntax to Markdown{% endtrans %}</a></li>
......
This diff is collapsed.
......@@ -77,6 +77,7 @@ from forum.models import (
ForumMessageMeta,
ForumUserInfo,
)
from pedagogy.models import UV, UVComment, UVResult
db = MySQLdb.connect(**settings.OLD_MYSQL_INFOS)
start = datetime.datetime.now()
......@@ -1568,6 +1569,103 @@ def migrate_club_again():
pass
def migrate_pedagogy():
cur = db.cursor(MySQLdb.cursors.SSDictCursor)
print("Migrating UVs")
root = User.objects.get(id=0)
semester_conversion = {
"closed": "CLOSED",
"A": "AUTUMN",
"P": "SPRING",
"AP": "AUTUMN_AND_SPRING",
}
def department_conversion(department):
# Default of this enum is HUMA
if not department or department == "Humas":
return "HUMA"
return department
def convert_number(num, default=0):
if not num:
return default
return num
def convert_text(text):
if not text:
return ""
return doku_to_markdown(to_unicode(text))
cur.execute(
"""
SELECT * FROM pedag_uv
LEFT JOIN pedag_uv_dept dept
ON dept.id_uv = pedag_uv.id_uv
"""
)
for uv in cur:
UV(
id=uv["id_uv"],
code=uv["code"],
author=root,
credit_type=uv["type"],
semester=semester_conversion[uv["semestre"]],
language="FR", # No infos in previous guide about that
credits=convert_number(uv["guide_credits"]),
department=department_conversion(uv["departement"]),
title=convert_text(uv["intitule"]),
manager=convert_text(uv["responsable"]),
objectives=convert_text(uv["guide_objectifs"]),
program=convert_text(uv["guide_programme"]),
skills="", # No info in previous guide about that
key_concepts="", # No info either
hours_CM=convert_number(uv["guide_c"]),
hours_TD=convert_number(uv["guide_td"]),
hours_TP=convert_number(uv["guide_tp"]),
hours_THE=convert_number(uv["guide_the"]),
hours_TE=0, # No info either
).save()
print("Migrating UV Comments")
cur.execute("SELECT * FROM pedag_uv_commentaire")
for comment in cur:
author = User.objects.filter(id=comment["id_utilisateur"]).first()
uv = UV.objects.filter(id=comment["id_uv"]).first()
if not author or not uv:
continue
UVComment(
id=comment["id_commentaire"],
author=author,
uv=uv,
comment=convert_text(comment["content"]),
grade_global=convert_number(comment["note_generale"], -1),
grade_utility=convert_number(comment["note_utilite"], -1),
grade_interest=convert_number(comment["note_interet"], -1),
grade_teaching=convert_number(comment["note_enseignement"], -1),
grade_work_load=convert_number(comment["note_travail"], -1),
publish_date=comment["date"].replace(tzinfo=timezone("Europe/Paris")),
).save()
print("Migrating UV Results")
cur.execute("SELECT * FROM pedag_resultat")
for result in cur:
author = User.objects.filter(id=comment["id_utilisateur"]).first()
uv = UV.objects.filter(id=comment["id_uv"]).first()
if not author or not uv:
continue
UVResult(
id=result["id_resultat"],
uv=uv,
user=author,
grade=result["note"],
semester=result["semestre"],
).save()
def main():
print("Start at %s" % start)
# Core
......@@ -1590,7 +1688,9 @@ def main():
# migrate_forum()
# reset_index('forum')
# migrate_mailings()
migrate_club_again()
# migrate_club_again()
migrate_pedagogy()
reset_index("pedagogy")
end = datetime.datetime.now()
print("End at %s" % end)
print("Running time: %s" % (end - start))
......
# -*- coding:utf-8 -*
#
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# 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.
#
#
# -*- coding:utf-8 -*
#
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# 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.contrib import admin
# Register your models here.
# -*- 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 django.utils.translation import ugettext_lazy as _
from django.forms.widgets import Widget
from django.templatetags.static import static
from core.views.forms import MarkdownInput
from core.models import User
from pedagogy.models import UV, UVComment, UVCommentReport
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 StarList(forms.NumberInput):
template_name = "pedagogy/starlist.jinja"
def __init__(self, nubmer_of_stars=0):
super(StarList, self).__init__(None)
self.number_of_stars = nubmer_of_stars
def get_context(self, name, value, attrs):
context = super(StarList, self).get_context(name, value, attrs)
context["number_of_stars"] = range(0, self.number_of_stars)
context["translations"] = {"do_not_vote": _("Do not vote")}
return context
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,
"grade_global": StarList(5),
"grade_utility": StarList(5),
"grade_interest": StarList(5),
"grade_teaching": StarList(5),
"grade_work_load": StarList(5),
}
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
class UVCommentReportForm(forms.ModelForm):
"""
Form handeling creation and edit of an UVReport
"""
class Meta:
model = UVCommentReport
fields = ("comment", "reporter", "reason")
widgets = {
"comment": forms.HiddenInput,
"reporter": forms.HiddenInput,
"reason": MarkdownInput,
}
def __init__(self, reporter_id, comment_id, *args, **kwargs):
super(UVCommentReportForm, self).__init__(*args, **kwargs)
self.fields["reporter"].queryset = User.objects.filter(id=reporter_id).all()
self.fields["reporter"].initial = reporter_id
self.fields["comment"].queryset = UVComment.objects.filter(id=comment_id).all()
self.fields["comment"].initial = comment_id
class UVCommentModerationForm(forms.Form):
"""
Form handeling bulk comment deletion
"""
accepted_reports = forms.ModelMultipleChoiceField(
UVCommentReport.objects.all(),
label=_("Accepted reports"),
widget=forms.CheckboxSelectMultiple,
required=False,
)
denied_reports = forms.ModelMultipleChoiceField(
UVCommentReport.objects.all(),
label=_("Denied reports"),
widget=forms.CheckboxSelectMultiple,
required=False,
)
This diff is collapsed.
# -*- coding:utf-8 -*
#
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# 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.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.core import validators
from django.conf import settings
from django.utils.functional import cached_property
from django.core.urlresolvers import reverse
from rest_framework import serializers
from core.models import User
# Create your models here.
class UV(models.Model):
"""
Contains infos about an UV (course)
"""
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,
)
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 __grade_average_generic(self, field):
comments = self.comments.filter(**{field + "__gte": 0})
if not comments.exists():
return -1
return int(sum(comments.values_list(field, flat=True)) / comments.count())
def get_absolute_url(self):
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.id})
@cached_property
def grade_global_average(self):
return self.__grade_average_generic("grade_global")
@cached_property
def grade_utility_average(self):
return self.__grade_average_generic("grade_utility")
@cached_property
def grade_interest_average(self):
return self.__grade_average_generic("grade_interest")
@cached_property
def grade_teaching_average(self):
return self.__grade_average_generic("grade_teaching")
@cached_property
def grade_work_load_average(self):
return self.__grade_average_generic("grade_work_load")
def __str__(self):
return self.code
class UVComment(models.Model):
"""
A comment about an UV
"""
author = models.ForeignKey(
User,
related_name="uv_comments",
verbose_name=_("author"),
null=False,
blank=False,