forked from ScoDoc/ScoDoc
Compare commits
15 Commits
0b1eaf4464
...
f89cbc8a90
Author | SHA1 | Date |
---|---|---|
Sébastien Lehmann | f89cbc8a90 | |
Emmanuel Viennet | 7369b67601 | |
Emmanuel Viennet | 828e813b10 | |
Emmanuel Viennet | 4f40fbd028 | |
Emmanuel Viennet | 98f6ba2dd7 | |
Emmanuel Viennet | 0eb00b0919 | |
Emmanuel Viennet | 6483110992 | |
Emmanuel Viennet | 5e18936d03 | |
Emmanuel Viennet | 7aa4d4b86b | |
Emmanuel Viennet | 23ce4be3c2 | |
Emmanuel Viennet | 632e285d26 | |
Emmanuel Viennet | 96531f839c | |
Emmanuel Viennet | 1dfe754793 | |
Emmanuel Viennet | e0188ebc2d | |
Emmanuel Viennet | c79eb6410a |
|
@ -20,5 +20,5 @@ ignored-classes=Permission,
|
|||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=entreprises
|
||||
|
||||
good-names=d,e,f,i,j,k,n,nt,t,u,ue,v,x,y,z,H,F
|
||||
good-names=d,df,e,f,i,j,k,n,nt,t,u,ue,v,x,y,z,H,F
|
||||
|
||||
|
|
|
@ -273,5 +273,5 @@ def evaluation_delete(evaluation_id: int):
|
|||
sco_saisie_notes.evaluation_suppress_alln(
|
||||
evaluation_id=evaluation_id, dialog_confirmed=True
|
||||
)
|
||||
sco_evaluation_db.do_evaluation_delete(evaluation_id)
|
||||
evaluation.delete()
|
||||
return "ok"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import datetime
|
||||
|
||||
from flask import flash, g, request, url_for
|
||||
from flask import g, request, url_for
|
||||
from flask_json import as_json
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
|
|
|
@ -141,6 +141,44 @@ class Evaluation(db.Model):
|
|||
n = 0 # the only one
|
||||
return n
|
||||
|
||||
def delete(self):
|
||||
"delete evaluation (commit) (check permission)"
|
||||
from app.scodoc import sco_evaluation_db
|
||||
|
||||
modimpl: ModuleImpl = self.moduleimpl
|
||||
if not modimpl.can_edit_evaluation(current_user):
|
||||
raise AccessDenied(
|
||||
f"Modification évaluation impossible pour {current_user.get_nomplogin()}"
|
||||
)
|
||||
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(
|
||||
self.id
|
||||
) # { etudid : value }
|
||||
notes = [x["value"] for x in notes_db.values()]
|
||||
if notes:
|
||||
raise ScoValueError(
|
||||
"Impossible de supprimer cette évaluation: il reste des notes"
|
||||
)
|
||||
log(f"deleting evaluation {self}")
|
||||
db.session.delete(self)
|
||||
db.session.commit()
|
||||
|
||||
# inval cache pour ce semestre
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=modimpl.formsemestre_id)
|
||||
# news
|
||||
url = url_for(
|
||||
"notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=modimpl.id,
|
||||
)
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_NOTE,
|
||||
obj=modimpl.id,
|
||||
text=f"""Suppression d'une évaluation dans <a href="{
|
||||
url
|
||||
}">{modimpl.module.titre}</a>""",
|
||||
url=url,
|
||||
)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"Représentation dict (riche, compat ScoDoc 7)"
|
||||
e_dict = dict(self.__dict__)
|
||||
|
|
|
@ -118,6 +118,32 @@ class ModuleImpl(db.Model):
|
|||
|
||||
return False
|
||||
|
||||
def can_edit_notes(self, user: "User", allow_ens=True) -> bool:
|
||||
"""True if authuser can enter or edit notes in this module.
|
||||
If allow_ens, grant access to all ens in this module
|
||||
|
||||
Si des décisions de jury ont déjà été saisies dans ce semestre,
|
||||
seul le directeur des études peut saisir des notes (et il ne devrait pas).
|
||||
"""
|
||||
# was sco_permissions_check.can_edit_notes
|
||||
from app.scodoc import sco_cursus_dut
|
||||
|
||||
if not self.formsemestre.etat:
|
||||
return False # semestre verrouillé
|
||||
is_dir_etud = user.id in (u.id for u in self.formsemestre.responsables)
|
||||
can_edit_all_notes = user.has_permission(Permission.ScoEditAllNotes)
|
||||
if sco_cursus_dut.formsemestre_has_decisions(self.formsemestre_id):
|
||||
# il y a des décisions de jury dans ce semestre !
|
||||
return can_edit_all_notes or is_dir_etud
|
||||
if (
|
||||
not can_edit_all_notes
|
||||
and user.id != self.responsable_id
|
||||
and not is_dir_etud
|
||||
):
|
||||
# enseignant (chargé de TD) ?
|
||||
return allow_ens and user.id in (ens.id for ens in self.enseignants)
|
||||
return True
|
||||
|
||||
def can_change_ens_by(self, user: User, raise_exc=False) -> bool:
|
||||
"""Check if user can modify module resp.
|
||||
If raise_exc, raises exception (AccessDenied or ScoLockedSemError) if not.
|
||||
|
|
|
@ -0,0 +1,511 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 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 Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""Génération calendrier (ancienne présentation)
|
||||
"""
|
||||
|
||||
import calendar
|
||||
import datetime
|
||||
import html
|
||||
import time
|
||||
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
|
||||
from app.scodoc import sco_preferences
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
|
||||
def is_work_saturday():
|
||||
"Vrai si le samedi est travaillé"
|
||||
return int(sco_preferences.get_preference("work_saturday"))
|
||||
|
||||
|
||||
def MonthNbDays(month, year):
|
||||
"returns nb of days in month"
|
||||
if month > 7:
|
||||
month = month + 1
|
||||
if month % 2:
|
||||
return 31
|
||||
elif month == 2:
|
||||
if calendar.isleap(year):
|
||||
return 29
|
||||
else:
|
||||
return 28
|
||||
else:
|
||||
return 30
|
||||
|
||||
|
||||
class ddmmyyyy(object):
|
||||
"""immutable dates"""
|
||||
|
||||
def __init__(self, date=None, fmt="ddmmyyyy", work_saturday=False):
|
||||
self.work_saturday = work_saturday
|
||||
if date is None:
|
||||
return
|
||||
try:
|
||||
if fmt == "ddmmyyyy":
|
||||
self.day, self.month, self.year = date.split("/")
|
||||
elif fmt == "iso":
|
||||
self.year, self.month, self.day = date.split("-")
|
||||
else:
|
||||
raise ValueError("invalid format spec. (%s)" % fmt)
|
||||
self.year = int(self.year)
|
||||
self.month = int(self.month)
|
||||
self.day = int(self.day)
|
||||
except ValueError:
|
||||
raise ScoValueError("date invalide: %s" % date)
|
||||
# accept years YYYY or YY, uses 1970 as pivot
|
||||
if self.year < 1970:
|
||||
if self.year > 100:
|
||||
raise ScoInvalidDateError("Année invalide: %s" % self.year)
|
||||
if self.year < 70:
|
||||
self.year = self.year + 2000
|
||||
else:
|
||||
self.year = self.year + 1900
|
||||
if self.month < 1 or self.month > 12:
|
||||
raise ScoInvalidDateError("Mois invalide: %s" % self.month)
|
||||
|
||||
if self.day < 1 or self.day > MonthNbDays(self.month, self.year):
|
||||
raise ScoInvalidDateError("Jour invalide: %s" % self.day)
|
||||
|
||||
# weekday in 0-6, where 0 is monday
|
||||
self.weekday = calendar.weekday(self.year, self.month, self.day)
|
||||
|
||||
self.time = time.mktime((self.year, self.month, self.day, 0, 0, 0, 0, 0, 0))
|
||||
|
||||
def iswork(self):
|
||||
"returns true if workable day"
|
||||
if self.work_saturday:
|
||||
nbdays = 6
|
||||
else:
|
||||
nbdays = 5
|
||||
if (
|
||||
self.weekday >= 0 and self.weekday < nbdays
|
||||
): # monday-friday or monday-saturday
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __repr__(self):
|
||||
return "'%02d/%02d/%04d'" % (self.day, self.month, self.year)
|
||||
|
||||
def __str__(self):
|
||||
return "%02d/%02d/%04d" % (self.day, self.month, self.year)
|
||||
|
||||
def ISO(self):
|
||||
"iso8601 representation of the date"
|
||||
return "%04d-%02d-%02d" % (self.year, self.month, self.day)
|
||||
|
||||
def next_day(self, days=1):
|
||||
"date for the next day (nota: may be a non workable day)"
|
||||
day = self.day + days
|
||||
month = self.month
|
||||
year = self.year
|
||||
|
||||
while day > MonthNbDays(month, year):
|
||||
day = day - MonthNbDays(month, year)
|
||||
month = month + 1
|
||||
if month > 12:
|
||||
month = 1
|
||||
year = year + 1
|
||||
return self.__class__(
|
||||
"%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday
|
||||
)
|
||||
|
||||
def prev(self, days=1):
|
||||
"date for previous day"
|
||||
day = self.day - days
|
||||
month = self.month
|
||||
year = self.year
|
||||
while day <= 0:
|
||||
month = month - 1
|
||||
if month == 0:
|
||||
month = 12
|
||||
year = year - 1
|
||||
day = day + MonthNbDays(month, year)
|
||||
|
||||
return self.__class__(
|
||||
"%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday
|
||||
)
|
||||
|
||||
def next_monday(self):
|
||||
"date of next monday"
|
||||
return self.next_day((7 - self.weekday) % 7)
|
||||
|
||||
def prev_monday(self):
|
||||
"date of last monday, but on sunday, pick next monday"
|
||||
if self.weekday == 6:
|
||||
return self.next_monday()
|
||||
else:
|
||||
return self.prev(self.weekday)
|
||||
|
||||
def __cmp__(self, other): # #py3 TODO à supprimer
|
||||
"""return a negative integer if self < other,
|
||||
zero if self == other, a positive integer if self > other"""
|
||||
return int(self.time - other.time)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.time == other.time
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.time != other.time
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.time < other.time
|
||||
|
||||
def __le__(self, other):
|
||||
return self.time <= other.time
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.time > other.time
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.time >= other.time
|
||||
|
||||
def __hash__(self):
|
||||
"we are immutable !"
|
||||
return hash(self.time) ^ hash(str(self))
|
||||
|
||||
|
||||
# d = ddmmyyyy( '21/12/99' )
|
||||
def DateRangeISO(date_beg, date_end, workable=1):
|
||||
"""returns list of dates in [date_beg,date_end]
|
||||
workable = 1 => keeps only workable days"""
|
||||
if not date_beg:
|
||||
raise ScoValueError("pas de date spécifiée !")
|
||||
if not date_end:
|
||||
date_end = date_beg
|
||||
r = []
|
||||
work_saturday = is_work_saturday()
|
||||
try:
|
||||
cur = ddmmyyyy(date_beg, work_saturday=work_saturday)
|
||||
end = ddmmyyyy(date_end, work_saturday=work_saturday)
|
||||
except (AttributeError, ValueError) as e:
|
||||
raise ScoValueError("date invalide !") from e
|
||||
while cur <= end:
|
||||
if (not workable) or cur.iswork():
|
||||
r.append(cur)
|
||||
cur = cur.next_day()
|
||||
|
||||
return [x.ISO() for x in r]
|
||||
|
||||
|
||||
def day_names():
|
||||
"""Returns week day names.
|
||||
If work_saturday property is set, include saturday
|
||||
"""
|
||||
if is_work_saturday():
|
||||
return scu.DAY_NAMES[:-1]
|
||||
else:
|
||||
return scu.DAY_NAMES[:-2]
|
||||
|
||||
|
||||
def next_iso_day(date):
|
||||
"return date after date"
|
||||
d = ddmmyyyy(date, fmt="iso", work_saturday=is_work_saturday())
|
||||
return d.next_day().ISO()
|
||||
|
||||
|
||||
def YearTable(
|
||||
year,
|
||||
events=[],
|
||||
firstmonth=9,
|
||||
lastmonth=7,
|
||||
halfday=0,
|
||||
dayattributes="",
|
||||
pad_width=8,
|
||||
):
|
||||
"""Generate a calendar table
|
||||
events = list of tuples (date, text, color, href [,halfday])
|
||||
where date is a string in ISO format (yyyy-mm-dd)
|
||||
halfday is boolean (true: morning, false: afternoon)
|
||||
text = text to put in calendar (must be short, 1-5 cars) (optional)
|
||||
if halfday, generate 2 cells per day (morning, afternoon)
|
||||
"""
|
||||
T = [
|
||||
'<table id="maincalendar" class="maincalendar" border="3" cellpadding="1" cellspacing="1" frame="box">'
|
||||
]
|
||||
T.append("<tr>")
|
||||
month = firstmonth
|
||||
while 1:
|
||||
T.append('<td valign="top">')
|
||||
T.append(MonthTableHead(month))
|
||||
T.append(
|
||||
MonthTableBody(
|
||||
month,
|
||||
year,
|
||||
events,
|
||||
halfday,
|
||||
dayattributes,
|
||||
is_work_saturday(),
|
||||
pad_width=pad_width,
|
||||
)
|
||||
)
|
||||
T.append(MonthTableTail())
|
||||
T.append("</td>")
|
||||
if month == lastmonth:
|
||||
break
|
||||
month = month + 1
|
||||
if month > 12:
|
||||
month = 1
|
||||
year = year + 1
|
||||
T.append("</table>")
|
||||
return "\n".join(T)
|
||||
|
||||
|
||||
# ------ HTML Calendar functions (see YearTable function)
|
||||
|
||||
# MONTH/DAY NAMES:
|
||||
|
||||
MONTHNAMES = (
|
||||
"Janvier",
|
||||
"Février",
|
||||
"Mars",
|
||||
"Avril",
|
||||
"Mai",
|
||||
"Juin",
|
||||
"Juillet",
|
||||
"Aout",
|
||||
"Septembre",
|
||||
"Octobre",
|
||||
"Novembre",
|
||||
"Décembre",
|
||||
)
|
||||
|
||||
MONTHNAMES_ABREV = (
|
||||
"Jan.",
|
||||
"Fév.",
|
||||
"Mars",
|
||||
"Avr.",
|
||||
"Mai ",
|
||||
"Juin",
|
||||
"Juil",
|
||||
"Aout",
|
||||
"Sept",
|
||||
"Oct.",
|
||||
"Nov.",
|
||||
"Déc.",
|
||||
)
|
||||
|
||||
DAYNAMES = ("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche")
|
||||
|
||||
DAYNAMES_ABREV = ("L", "M", "M", "J", "V", "S", "D")
|
||||
|
||||
# COLORS:
|
||||
|
||||
WHITE = "#FFFFFF"
|
||||
GRAY1 = "#EEEEEE"
|
||||
GREEN3 = "#99CC99"
|
||||
WEEKDAYCOLOR = GRAY1
|
||||
WEEKENDCOLOR = GREEN3
|
||||
|
||||
|
||||
def MonthTableHead(month):
|
||||
color = WHITE
|
||||
return """<table class="monthcalendar" border="0" cellpadding="0" cellspacing="0" frame="box">
|
||||
<tr bgcolor="%s"><td class="calcol" colspan="2" align="center">%s</td></tr>\n""" % (
|
||||
color,
|
||||
MONTHNAMES_ABREV[month - 1],
|
||||
)
|
||||
|
||||
|
||||
def MonthTableTail():
|
||||
return "</table>\n"
|
||||
|
||||
|
||||
def MonthTableBody(
|
||||
month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8
|
||||
):
|
||||
firstday, nbdays = calendar.monthrange(year, month)
|
||||
localtime = time.localtime()
|
||||
current_weeknum = time.strftime("%U", localtime)
|
||||
current_year = localtime[0]
|
||||
T = []
|
||||
# cherche date du lundi de la 1ere semaine de ce mois
|
||||
monday = ddmmyyyy("1/%d/%d" % (month, year))
|
||||
while monday.weekday != 0:
|
||||
monday = monday.prev()
|
||||
|
||||
if work_saturday:
|
||||
weekend = ("D",)
|
||||
else:
|
||||
weekend = ("S", "D")
|
||||
|
||||
if not halfday:
|
||||
for d in range(1, nbdays + 1):
|
||||
weeknum = time.strftime(
|
||||
"%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y")
|
||||
)
|
||||
day = DAYNAMES_ABREV[(firstday + d - 1) % 7]
|
||||
if day in weekend:
|
||||
bgcolor = WEEKENDCOLOR
|
||||
weekclass = "wkend"
|
||||
attrs = ""
|
||||
else:
|
||||
bgcolor = WEEKDAYCOLOR
|
||||
weekclass = "wk" + str(monday).replace("/", "_")
|
||||
attrs = trattributes
|
||||
color = None
|
||||
legend = ""
|
||||
href = ""
|
||||
descr = ""
|
||||
# event this day ?
|
||||
# each event is a tuple (date, text, color, href)
|
||||
# where date is a string in ISO format (yyyy-mm-dd)
|
||||
for ev in events:
|
||||
ev_year = int(ev[0][:4])
|
||||
ev_month = int(ev[0][5:7])
|
||||
ev_day = int(ev[0][8:10])
|
||||
if year == ev_year and month == ev_month and ev_day == d:
|
||||
if ev[1]:
|
||||
legend = ev[1]
|
||||
if ev[2]:
|
||||
color = ev[2]
|
||||
if ev[3]:
|
||||
href = ev[3]
|
||||
if len(ev) > 4 and ev[4]:
|
||||
descr = ev[4]
|
||||
#
|
||||
cc = []
|
||||
if color is not None:
|
||||
cc.append('<td bgcolor="%s" class="calcell">' % color)
|
||||
else:
|
||||
cc.append('<td class="calcell">')
|
||||
|
||||
if href:
|
||||
href = 'href="%s"' % href
|
||||
if descr:
|
||||
descr = 'title="%s"' % html.escape(descr, quote=True)
|
||||
if href or descr:
|
||||
cc.append("<a %s %s>" % (href, descr))
|
||||
|
||||
if legend or d == 1:
|
||||
if pad_width is not None:
|
||||
n = pad_width - len(legend) # pad to 8 cars
|
||||
if n > 0:
|
||||
legend = (
|
||||
" " * (n // 2) + legend + " " * ((n + 1) // 2)
|
||||
)
|
||||
else:
|
||||
legend = " " # empty cell
|
||||
cc.append(legend)
|
||||
if href or descr:
|
||||
cc.append("</a>")
|
||||
cc.append("</td>")
|
||||
cell = "".join(cc)
|
||||
if day == "D":
|
||||
monday = monday.next_day(7)
|
||||
if (
|
||||
weeknum == current_weeknum
|
||||
and current_year == year
|
||||
and weekclass != "wkend"
|
||||
):
|
||||
weekclass += " currentweek"
|
||||
T.append(
|
||||
'<tr bgcolor="%s" class="%s" %s><td class="calday">%d%s</td>%s</tr>'
|
||||
% (bgcolor, weekclass, attrs, d, day, cell)
|
||||
)
|
||||
else:
|
||||
# Calendar with 2 cells / day
|
||||
for d in range(1, nbdays + 1):
|
||||
weeknum = time.strftime(
|
||||
"%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y")
|
||||
)
|
||||
day = DAYNAMES_ABREV[(firstday + d - 1) % 7]
|
||||
if day in weekend:
|
||||
bgcolor = WEEKENDCOLOR
|
||||
weekclass = "wkend"
|
||||
attrs = ""
|
||||
else:
|
||||
bgcolor = WEEKDAYCOLOR
|
||||
weekclass = "wk" + str(monday).replace("/", "_")
|
||||
attrs = trattributes
|
||||
if (
|
||||
weeknum == current_weeknum
|
||||
and current_year == year
|
||||
and weekclass != "wkend"
|
||||
):
|
||||
weeknum += " currentweek"
|
||||
|
||||
if day == "D":
|
||||
monday = monday.next_day(7)
|
||||
T.append(
|
||||
'<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>'
|
||||
% (bgcolor, weekclass, attrs, d, day)
|
||||
)
|
||||
cc = []
|
||||
for morning in (True, False):
|
||||
color = None
|
||||
legend = ""
|
||||
href = ""
|
||||
descr = ""
|
||||
for ev in events:
|
||||
ev_year = int(ev[0][:4])
|
||||
ev_month = int(ev[0][5:7])
|
||||
ev_day = int(ev[0][8:10])
|
||||
if ev[4] is not None:
|
||||
ev_half = int(ev[4])
|
||||
else:
|
||||
ev_half = 0
|
||||
if (
|
||||
year == ev_year
|
||||
and month == ev_month
|
||||
and ev_day == d
|
||||
and morning == ev_half
|
||||
):
|
||||
if ev[1]:
|
||||
legend = ev[1]
|
||||
if ev[2]:
|
||||
color = ev[2]
|
||||
if ev[3]:
|
||||
href = ev[3]
|
||||
if len(ev) > 5 and ev[5]:
|
||||
descr = ev[5]
|
||||
#
|
||||
if color is not None:
|
||||
cc.append('<td bgcolor="%s" class="calcell">' % (color))
|
||||
else:
|
||||
cc.append('<td class="calcell">')
|
||||
if href:
|
||||
href = 'href="%s"' % href
|
||||
if descr:
|
||||
descr = 'title="%s"' % html.escape(descr, quote=True)
|
||||
if href or descr:
|
||||
cc.append("<a %s %s>" % (href, descr))
|
||||
if legend or d == 1:
|
||||
n = 3 - len(legend) # pad to 3 cars
|
||||
if n > 0:
|
||||
legend = (
|
||||
" " * (n // 2) + legend + " " * ((n + 1) // 2)
|
||||
)
|
||||
else:
|
||||
legend = " " # empty cell
|
||||
cc.append(legend)
|
||||
if href or descr:
|
||||
cc.append("</a>")
|
||||
cc.append("</td>\n")
|
||||
T.append("".join(cc) + "</tr>")
|
||||
return "\n".join(T)
|
|
@ -28,19 +28,17 @@
|
|||
"""Gestion évaluations (ScoDoc7, code en voie de modernisation)
|
||||
"""
|
||||
|
||||
import pprint
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
from flask_login import current_user
|
||||
|
||||
from app import db, log
|
||||
|
||||
from app.models import Evaluation, ModuleImpl, ScolarNews
|
||||
from app.models import Evaluation
|
||||
from app.models.evaluations import check_convert_evaluation_args
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||
from app.scodoc.sco_exceptions import AccessDenied
|
||||
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_moduleimpl
|
||||
|
@ -119,42 +117,6 @@ def do_evaluation_edit(args):
|
|||
)
|
||||
|
||||
|
||||
def do_evaluation_delete(evaluation_id):
|
||||
"delete evaluation"
|
||||
evaluation: Evaluation = Evaluation.query.get_or_404(evaluation_id)
|
||||
modimpl: ModuleImpl = evaluation.moduleimpl
|
||||
if not modimpl.can_edit_evaluation(current_user):
|
||||
raise AccessDenied(
|
||||
f"Modification évaluation impossible pour {current_user.get_nomplogin()}"
|
||||
)
|
||||
notes_db = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
||||
notes = [x["value"] for x in notes_db.values()]
|
||||
if notes:
|
||||
raise ScoValueError(
|
||||
"Impossible de supprimer cette évaluation: il reste des notes"
|
||||
)
|
||||
log(f"deleting evaluation {evaluation}")
|
||||
db.session.delete(evaluation)
|
||||
db.session.commit()
|
||||
|
||||
# inval cache pour ce semestre
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=modimpl.formsemestre_id)
|
||||
# news
|
||||
url = url_for(
|
||||
"notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=modimpl.id,
|
||||
)
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_NOTE,
|
||||
obj=modimpl.id,
|
||||
text=f"""Suppression d'une évaluation dans <a href="{
|
||||
url
|
||||
}">{modimpl.module.titre}</a>""",
|
||||
url=url,
|
||||
)
|
||||
|
||||
|
||||
# ancien _notes_getall
|
||||
def do_evaluation_get_all_notes(
|
||||
evaluation_id, table="notes_notes", filter_suppressed=True, by_uid=None
|
||||
|
|
|
@ -351,14 +351,15 @@ def evaluation_create_form(
|
|||
else:
|
||||
date_debut = None
|
||||
args.pop("jour", None)
|
||||
if args.get("heure_debut"):
|
||||
if date_debut and args.get("heure_debut"):
|
||||
try:
|
||||
heure_debut = heure_to_time(args["heure_debut"])
|
||||
except ValueError as exc:
|
||||
raise ScoValueError("Heure début invalide") from exc
|
||||
args["date_debut"] = datetime.datetime.combine(date_debut, heure_debut)
|
||||
args.pop("heure_debut", None)
|
||||
if args.get("heure_fin"):
|
||||
# note: ce formulaire ne permet de créer que des évaluation avec debut et fin sur le même jour.
|
||||
if date_debut and args.get("heure_fin"):
|
||||
try:
|
||||
heure_fin = heure_to_time(args["heure_fin"])
|
||||
except ValueError as exc:
|
||||
|
|
|
@ -30,16 +30,17 @@
|
|||
import collections
|
||||
import datetime
|
||||
import operator
|
||||
import time
|
||||
|
||||
from flask import url_for
|
||||
from flask import g
|
||||
from flask_login import current_user
|
||||
from flask import request
|
||||
|
||||
from app import db
|
||||
from app.auth.models import User
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import FormSemestre
|
||||
from app.models import Evaluation, FormSemestre
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
|
@ -645,78 +646,64 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
|||
"""HTML description of evaluation, for page headers
|
||||
edit_in_place: allow in-place editing when permitted (not implemented)
|
||||
"""
|
||||
E = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})[0]
|
||||
moduleimpl_id = E["moduleimpl_id"]
|
||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
u = sco_users.user_info(M["responsable_id"])
|
||||
resp = u["prenomnom"]
|
||||
nomcomplet = u["nomcomplet"]
|
||||
can_edit = sco_permissions_check.can_edit_notes(
|
||||
current_user, moduleimpl_id, allow_ens=False
|
||||
)
|
||||
evaluation: Evaluation = Evaluation.query.get_or_404(evaluation_id)
|
||||
modimpl = evaluation.moduleimpl
|
||||
responsable: User = db.session.get(User, modimpl.responsable_id)
|
||||
resp_nomprenom = responsable.get_prenomnom()
|
||||
resp_nomcomplet = responsable.get_nomcomplet()
|
||||
can_edit = modimpl.can_edit_notes(current_user, allow_ens=False)
|
||||
|
||||
link = (
|
||||
'<span class="evallink"><a class="stdlink" href="evaluation_listenotes?moduleimpl_id=%s">voir toutes les notes du module</a></span>'
|
||||
% moduleimpl_id
|
||||
)
|
||||
mod_descr = (
|
||||
'<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s'
|
||||
% (
|
||||
moduleimpl_id,
|
||||
Mod["code"] or "",
|
||||
Mod["titre"] or "?",
|
||||
nomcomplet,
|
||||
resp,
|
||||
link,
|
||||
)
|
||||
)
|
||||
mod_descr = f"""<a class="stdlink" href="{url_for("notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=modimpl.id,
|
||||
)}">{modimpl.module.code or ""} {modimpl.module.abbrev or modimpl.module.titre or "?"}</a>
|
||||
<span class="resp">(resp. <a title="{resp_nomcomplet}">{resp_nomprenom}</a>)</span>
|
||||
<span class="evallink"><a class="stdlink"
|
||||
href="{url_for(
|
||||
"notes.evaluation_listenotes",
|
||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
|
||||
}">voir toutes les notes du module</a></span>
|
||||
"""
|
||||
|
||||
etit = E["description"] or ""
|
||||
if etit:
|
||||
etit = ' "' + etit + '"'
|
||||
if Mod["module_type"] == ModuleType.MALUS:
|
||||
etit += ' <span class="eval_malus">(points de malus)</span>'
|
||||
eval_titre = f' "{evaluation.description}"' if evaluation.description else ""
|
||||
if modimpl.module.module_type == ModuleType.MALUS:
|
||||
eval_titre += ' <span class="eval_malus">(points de malus)</span>'
|
||||
H = [
|
||||
'<span class="eval_title">Évaluation%s</span><p><b>Module : %s</b></p>'
|
||||
% (etit, mod_descr)
|
||||
f"""<span class="eval_title">Évaluation{eval_titre}</span>
|
||||
<p><b>Module : {mod_descr}</b>
|
||||
</p>"""
|
||||
]
|
||||
if Mod["module_type"] == ModuleType.MALUS:
|
||||
if modimpl.module.module_type == ModuleType.MALUS:
|
||||
# Indique l'UE
|
||||
ue = sco_edit_ue.ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
||||
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
||||
ue = modimpl.module.ue
|
||||
H.append(f"<p><b>UE : {ue.acronyme}</b></p>")
|
||||
# store min/max values used by JS client-side checks:
|
||||
H.append(
|
||||
'<span id="eval_note_min" class="sco-hidden">-20.</span><span id="eval_note_max" class="sco-hidden">20.</span>'
|
||||
"""<span id="eval_note_min" class="sco-hidden">-20.</span>
|
||||
<span id="eval_note_max" class="sco-hidden">20.</span>"""
|
||||
)
|
||||
else:
|
||||
# date et absences (pas pour evals de malus)
|
||||
if E["jour"]:
|
||||
jour = E["jour"]
|
||||
H.append("<p>Réalisée le <b>%s</b> " % (jour))
|
||||
if E["heure_debut"] != E["heure_fin"]:
|
||||
H.append("de %s à %s " % (E["heure_debut"], E["heure_fin"]))
|
||||
group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
if evaluation.date_debut is not None:
|
||||
H.append(f"<p>Réalisée le <b>{evaluation.descr_date()}</b> ")
|
||||
group_id = sco_groups.get_default_group(modimpl.formsemestre_id)
|
||||
H.append(
|
||||
f"""<span class="noprint"><a href="{url_for(
|
||||
'assiduites.get_etat_abs_date',
|
||||
f"""<span class="evallink"><a class="stdlink" href="{url_for(
|
||||
'assiduites.etat_abs_date',
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
group_ids=group_id,
|
||||
desc=E["description"],
|
||||
jour=E["jour"],
|
||||
heure_debut=E["heure_debut"],
|
||||
heure_fin=E["heure_fin"],
|
||||
desc=evaluation.description or "",
|
||||
date_debut=evaluation.date_debut.isoformat(),
|
||||
date_fin=evaluation.date_fin.isoformat(),
|
||||
)
|
||||
}">(absences ce jour)</a></span>"""
|
||||
}">absences ce jour</a></span>"""
|
||||
)
|
||||
else:
|
||||
jour = "<em>pas de date</em>"
|
||||
H.append("<p>Réalisée le <b>%s</b> " % (jour))
|
||||
H.append("<p><em>sans date</em> ")
|
||||
|
||||
H.append(
|
||||
'</p><p>Coefficient dans le module: <b>%s</b>, notes sur <span id="eval_note_max">%g</span> '
|
||||
% (E["coefficient"], E["note_max"])
|
||||
f"""</p><p>Coefficient dans le module: <b>{evaluation.coefficient or "0"}</b>,
|
||||
notes sur <span id="eval_note_max">{(evaluation.note_max or 0):g}</span> """
|
||||
)
|
||||
H.append('<span id="eval_note_min" class="sco-hidden">0.</span>')
|
||||
if can_edit:
|
||||
|
@ -730,7 +717,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
|||
if link_saisie:
|
||||
H.append(
|
||||
f"""
|
||||
<a class="stdlink" href="{url_for(
|
||||
<a style="margin-left: 12px;" class="stdlink" href="{url_for(
|
||||
"notes.saisie_notes", scodoc_dept=g.scodoc_dept, evaluation_id=evaluation_id)
|
||||
}">saisie des notes</a>
|
||||
"""
|
||||
|
|
|
@ -50,7 +50,6 @@ from app.scodoc import htmlutils
|
|||
from app.scodoc import sco_cal
|
||||
from app.scodoc import sco_compute_moy
|
||||
from app.scodoc import sco_evaluations
|
||||
from app.scodoc import sco_evaluation_db
|
||||
from app.scodoc import sco_formsemestre_status
|
||||
from app.scodoc import sco_groups
|
||||
from app.scodoc import sco_moduleimpl
|
||||
|
@ -59,19 +58,15 @@ from app.tables import list_etuds
|
|||
|
||||
|
||||
# menu evaluation dans moduleimpl
|
||||
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
||||
def moduleimpl_evaluation_menu(evaluation: Evaluation, nbnotes: int = 0) -> str:
|
||||
"Menu avec actions sur une evaluation"
|
||||
E = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})[0]
|
||||
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
modimpl: ModuleImpl = evaluation.moduleimpl
|
||||
group_id = sco_groups.get_default_group(modimpl.formsemestre_id)
|
||||
evaluation_id = evaluation.id
|
||||
can_edit_notes = modimpl.can_edit_notes(current_user, allow_ens=False)
|
||||
can_edit_notes_ens = modimpl.can_edit_notes(current_user)
|
||||
|
||||
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
||||
|
||||
if (
|
||||
sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"], allow_ens=False
|
||||
)
|
||||
and nbnotes != 0
|
||||
):
|
||||
if can_edit_notes and nbnotes != 0:
|
||||
sup_label = "Supprimer évaluation impossible (il y a des notes)"
|
||||
else:
|
||||
sup_label = "Supprimer évaluation"
|
||||
|
@ -83,9 +78,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"]
|
||||
),
|
||||
"enabled": can_edit_notes_ens,
|
||||
},
|
||||
{
|
||||
"title": "Modifier évaluation",
|
||||
|
@ -93,9 +86,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
"enabled": can_edit_notes,
|
||||
},
|
||||
{
|
||||
"title": sup_label,
|
||||
|
@ -103,10 +94,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": nbnotes == 0
|
||||
and sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
"enabled": nbnotes == 0 and can_edit_notes,
|
||||
},
|
||||
{
|
||||
"title": "Supprimer toutes les notes",
|
||||
|
@ -114,9 +102,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
"enabled": can_edit_notes,
|
||||
},
|
||||
{
|
||||
"title": "Afficher les notes",
|
||||
|
@ -132,21 +118,18 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
current_user, E["moduleimpl_id"]
|
||||
),
|
||||
"enabled": can_edit_notes_ens,
|
||||
},
|
||||
{
|
||||
"title": "Absences ce jour",
|
||||
"endpoint": "assiduites.get_etat_abs_date",
|
||||
"endpoint": "assiduites.etat_abs_date",
|
||||
"args": {
|
||||
"group_ids": group_id,
|
||||
"desc": E["description"],
|
||||
"jour": E["jour"],
|
||||
"heure_debut": E["heure_debut"],
|
||||
"heure_fin": E["heure_fin"],
|
||||
"desc": evaluation.description or "",
|
||||
"date_debut": evaluation.date_debut.isoformat(),
|
||||
"date_fin": evaluation.date_fin.isoformat(),
|
||||
},
|
||||
"enabled": E["jour"],
|
||||
"enabled": evaluation.date_debut is not None,
|
||||
},
|
||||
{
|
||||
"title": "Vérifier notes vs absents",
|
||||
|
@ -154,7 +137,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||
"args": {
|
||||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": nbnotes > 0 and E["jour"],
|
||||
"enabled": nbnotes > 0 and evaluation.date_debut is not None,
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -714,7 +697,7 @@ def _ligne_evaluation(
|
|||
if can_edit_notes:
|
||||
H.append(
|
||||
moduleimpl_evaluation_menu(
|
||||
evaluation.id,
|
||||
evaluation,
|
||||
nbnotes=etat["nb_notes"],
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1315,7 +1315,7 @@ a.smallbutton {
|
|||
}
|
||||
|
||||
span.evallink {
|
||||
font-size: 80%;
|
||||
margin-left: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
|
|
@ -468,7 +468,8 @@
|
|||
if (to[0] != "n") {
|
||||
groupeSelected.closest(".grpPartitions").querySelector(`[value="${to}"]`).click();
|
||||
} else {
|
||||
groupeSelected.closest(".grpPartitions").querySelector(`[value="aucun"]`).click();
|
||||
let toNumber = to.split("-")[1];
|
||||
groupeSelected.closest(".grpPartitions").querySelector(`[data-idpartition="${toNumber}"] [value="aucun"]`).click();
|
||||
}
|
||||
|
||||
})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import datetime
|
||||
|
||||
from flask import g, request, render_template
|
||||
|
||||
from flask import abort, url_for
|
||||
from flask_login import current_user
|
||||
|
||||
from app import db
|
||||
from app.comp import res_sem
|
||||
|
@ -25,14 +25,16 @@ from app.views import ScoData
|
|||
# ---------------
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import safehtml
|
||||
from app.scodoc import sco_moduleimpl
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_groups_view
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_find_etud
|
||||
from flask_login import current_user
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc import sco_assiduites as scass
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
from app.tables.visu_assiduites import TableAssi, etuds_sorted_from_ids
|
||||
|
||||
|
@ -731,17 +733,23 @@ def visu_assiduites_group():
|
|||
).build()
|
||||
|
||||
|
||||
@bp.route("/EtatAbsencesDate")
|
||||
@bp.route("/etat_abs_date")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def get_etat_abs_date():
|
||||
infos_date = {
|
||||
"jour": request.args.get("jour"),
|
||||
"heure_debut": request.args.get("heure_debut"),
|
||||
"heure_fin": request.args.get("heure_fin"),
|
||||
"title": request.args.get("desc"),
|
||||
}
|
||||
def etat_abs_date():
|
||||
"""date_debut, date_fin en ISO"""
|
||||
date_debut_str = request.args.get("date_debut")
|
||||
date_fin_str = request.args.get("date_fin")
|
||||
title = request.args.get("desc")
|
||||
group_ids: list[int] = request.args.get("group_ids", None)
|
||||
try:
|
||||
date_debut = datetime.datetime.fromisoformat(date_debut_str)
|
||||
except ValueError as exc:
|
||||
raise ScoValueError("date_debut invalide") from exc
|
||||
try:
|
||||
date_fin = datetime.datetime.fromisoformat(date_fin_str)
|
||||
except ValueError as exc:
|
||||
raise ScoValueError("date_fin invalide") from exc
|
||||
if group_ids is None:
|
||||
group_ids = []
|
||||
else:
|
||||
|
@ -754,14 +762,6 @@ def get_etat_abs_date():
|
|||
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
|
||||
for m in groups_infos.members
|
||||
]
|
||||
|
||||
date_debut = scu.is_iso_formated(
|
||||
f"{infos_date['jour']}T{infos_date['heure_debut'].replace('h',':')}", True
|
||||
)
|
||||
date_fin = scu.is_iso_formated(
|
||||
f"{infos_date['jour']}T{infos_date['heure_fin'].replace('h',':')}", True
|
||||
)
|
||||
|
||||
assiduites: Assiduite = Assiduite.query.filter(
|
||||
Assiduite.etudid.in_([e["etudid"] for e in etuds])
|
||||
)
|
||||
|
@ -791,7 +791,7 @@ def get_etat_abs_date():
|
|||
etudiants = list(sorted(etudiants, key=lambda x: x["nom"]))
|
||||
|
||||
header: str = html_sco_header.sco_header(
|
||||
page_title=infos_date["title"],
|
||||
page_title=safehtml.html_to_safe_html(title),
|
||||
init_qtip=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -1654,30 +1654,37 @@ sco_publish(
|
|||
@scodoc7func
|
||||
def evaluation_delete(evaluation_id):
|
||||
"""Form delete evaluation"""
|
||||
El = sco_evaluation_db.get_evaluation_dict(args={"evaluation_id": evaluation_id})
|
||||
if not El:
|
||||
raise ScoValueError("Evaluation inexistante ! (%s)" % evaluation_id)
|
||||
E = El[0]
|
||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||
tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
|
||||
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
||||
evaluation: Evaluation = (
|
||||
Evaluation.query.filter_by(id=evaluation_id)
|
||||
.join(ModuleImpl)
|
||||
.join(FormSemestre)
|
||||
.filter_by(dept_id=g.scodoc_dept_id)
|
||||
.first_or_404()
|
||||
)
|
||||
|
||||
tit = f"""Suppression de l'évaluation {evaluation.description or ""} ({evaluation.descr_date()})"""
|
||||
etat = sco_evaluations.do_evaluation_etat(evaluation.id)
|
||||
H = [
|
||||
html_sco_header.html_sem_header(tit, with_h2=False),
|
||||
"""<h2 class="formsemestre">Module <tt>%(code)s</tt> %(titre)s</h2>""" % Mod,
|
||||
"""<h3>%s</h3>""" % tit,
|
||||
"""<p class="help">Opération <span class="redboldtext">irréversible</span>. Si vous supprimez l'évaluation, vous ne pourrez pas retrouver les notes associées.</p>""",
|
||||
f"""
|
||||
{html_sco_header.html_sem_header(tit, with_h2=False)}
|
||||
<h2 class="formsemestre">Module <tt>{evaluation.moduleimpl.module.code}</tt>
|
||||
{evaluation.moduleimpl.module.titre_str()}</h2>
|
||||
<h3>{tit}</h3>
|
||||
<p class="help">Opération <span class="redboldtext">irréversible</span>.
|
||||
Si vous supprimez l'évaluation, vous ne pourrez pas retrouver les notes associées.
|
||||
</p>
|
||||
""",
|
||||
]
|
||||
warning = False
|
||||
if etat["nb_notes_total"]:
|
||||
warning = True
|
||||
nb_desinscrits = etat["nb_notes_total"] - etat["nb_notes"]
|
||||
H.append(
|
||||
"""<div class="ue_warning"><span>Il y a %s notes""" % etat["nb_notes_total"]
|
||||
f"""<div class="ue_warning"><span>Il y a {etat["nb_notes_total"]} notes"""
|
||||
)
|
||||
if nb_desinscrits:
|
||||
H.append(
|
||||
""" (dont %s d'étudiants qui ne sont plus inscrits)""" % nb_desinscrits
|
||||
""" (dont {nb_desinscrits} d'étudiants qui ne sont plus inscrits)"""
|
||||
)
|
||||
H.append(""" dans l'évaluation</span>""")
|
||||
if etat["nb_notes"] == 0:
|
||||
|
@ -1687,8 +1694,13 @@ def evaluation_delete(evaluation_id):
|
|||
|
||||
if etat["nb_notes"]:
|
||||
H.append(
|
||||
"""<p>Suppression impossible (effacer les notes d'abord)</p><p><a class="stdlink" href="moduleimpl_status?moduleimpl_id=%s">retour au tableau de bord du module</a></p></div>"""
|
||||
% E["moduleimpl_id"]
|
||||
f"""<p>Suppression impossible (effacer les notes d'abord)</p>
|
||||
<p><a class="stdlink" href="{
|
||||
url_for("notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=evaluation.moduleimpl_id)
|
||||
}">retour au tableau de bord du module</a>
|
||||
</p>
|
||||
</div>"""
|
||||
)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
if warning:
|
||||
|
@ -1698,7 +1710,7 @@ def evaluation_delete(evaluation_id):
|
|||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
(("evaluation_id", {"input_type": "hidden"}),),
|
||||
initvalues=E,
|
||||
initvalues={"evaluation_id": evaluation.id},
|
||||
submitlabel="Confirmer la suppression",
|
||||
cancelbutton="Annuler",
|
||||
)
|
||||
|
@ -1709,17 +1721,17 @@ def evaluation_delete(evaluation_id):
|
|||
url_for(
|
||||
"notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=E["moduleimpl_id"],
|
||||
moduleimpl_id=evaluation.moduleimpl_id,
|
||||
)
|
||||
)
|
||||
else:
|
||||
sco_evaluation_db.do_evaluation_delete(E["evaluation_id"])
|
||||
evaluation.delete()
|
||||
return (
|
||||
"\n".join(H)
|
||||
+ f"""<p>OK, évaluation supprimée.</p>
|
||||
<p><a class="stdlink" href="{
|
||||
url_for("notes.moduleimpl_status", scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=E["moduleimpl_id"])
|
||||
moduleimpl_id=evaluation.moduleimpl_id)
|
||||
}">Continuer</a></p>"""
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.6.11"
|
||||
SCOVERSION = "9.6.16"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
|
|
@ -5,40 +5,51 @@
|
|||
"""Construction des fichiers exemples pour la documentation.
|
||||
|
||||
Usage:
|
||||
cd /opt/scodoc/tests/api
|
||||
python make_samples.py [entry_names]
|
||||
python make_samples.py -i <filepath> [entrynames]
|
||||
python tests/api/make_samples.py [entry_names]
|
||||
python tests/api/make_samples.py -i <filepath> [entrynames]
|
||||
|
||||
si entry_names est spécifié, la génération est restreints aux exemples cités. expl: `python make_samples departements departement-formsemestres`
|
||||
doit être exécutée immédiatement apres une initialisation de la base pour test API! (car dépendant des identifiants générés lors de la création des objets)
|
||||
cd /opt/scodoc/tests/api
|
||||
tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database
|
||||
Si entry_names est spécifié, la génération est restreinte aux exemples cités.
|
||||
Exemple:
|
||||
python make_samples departements departement-formsemestres
|
||||
|
||||
Créer éventuellement un fichier `.env` dans /opt/scodoc/tests/api
|
||||
avec la config du client API:
|
||||
```
|
||||
SCODOC_URL = "http://localhost:5000/"
|
||||
Doit être exécutée immédiatement apres une initialisation de la base pour test API!
|
||||
(car dépendant des identifiants générés lors de la création des objets)
|
||||
|
||||
Modifer le /opt/scodoc/.env pour pointer sur la base test
|
||||
SCODOC_DATABASE_URI="postgresql:///SCODOC_TEST_API"
|
||||
|
||||
puis re-créer cette base
|
||||
tools/create_database.sh --drop SCODOC_TEST_API
|
||||
flask db upgrade
|
||||
flask sco-db-init --erase
|
||||
flask init-test-database
|
||||
|
||||
et lancer le serveur test:
|
||||
flask run --debug
|
||||
```
|
||||
|
||||
Cet utilitaire prend en donnée le fichier de nom `samples.csv` contenant la description des exemples (séparés par une tabulation (\t), une ligne par exemple)
|
||||
* Le nom de l'exemple donne le nom du fichier généré (nom_exemple => nom_exemple.json.md). plusieurs lignes peuvent partager le même nom. dans ce cas le fichier contiendra chacun des exemples
|
||||
Cet utilitaire prend en argument le fichier de nom `samples.csv` contenant la description
|
||||
des exemples (séparés par une tabulation (\t), une ligne par exemple)
|
||||
* Le nom de l'exemple donne le nom du fichier généré (nom_exemple => nom_exemple.json.md).
|
||||
Plusieurs lignes peuvent partager le même nom. dans ce cas le fichier contiendra
|
||||
chacun des exemples
|
||||
* l'url utilisée
|
||||
* la permission nécessaire (par défaut ScoView)
|
||||
* la méthode GET,POST à utiliser (si commence par #, la ligne est ignorée)
|
||||
* les arguments éventuel (en cas de POST): une chaîne de caractère selon json
|
||||
|
||||
Implémentation:
|
||||
Le code complète une structure de données (Samples) qui est un dictionnaire de set (indicé par le nom des exemple.
|
||||
Le code complète une structure de données (Samples) qui est un dictionnaire de set
|
||||
(indicé par le nom des exemples).
|
||||
Chacun des éléments du set est un exemple (Sample)
|
||||
Quand la structure est complète, on génére tous les fichiers textes
|
||||
- nom de l exemple
|
||||
- un ou plusieurs exemples avec pour chaucn
|
||||
- l url utilisée
|
||||
- nom de l'exemple
|
||||
- un ou plusieurs exemples avec pour chacun
|
||||
- l'url utilisée
|
||||
- les arguments éventuels
|
||||
- le résultat
|
||||
Le tout mis en forme au format markdown et rangé dans le répertoire DATA_DIR (/tmp/samples) qui est créé ou écrasé si déjà existant
|
||||
|
||||
|
||||
Le tout mis en forme au format markdown et rangé dans le répertoire DATA_DIR (/tmp/samples)
|
||||
qui est créé ou écrasé si déjà existant.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
|
@ -50,7 +61,7 @@ from pprint import pprint as pp
|
|||
import urllib3
|
||||
import json
|
||||
|
||||
from pandas import read_csv
|
||||
import pandas as pd
|
||||
|
||||
from setup_test_api import (
|
||||
API_PASSWORD,
|
||||
|
@ -68,6 +79,10 @@ DATA_DIR = "/tmp/samples/"
|
|||
SAMPLES_FILENAME = "tests/ressources/samples/samples.csv"
|
||||
|
||||
|
||||
class SampleException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Sample:
|
||||
def __init__(self, url, method="GET", permission="ScoView", content=None):
|
||||
self.content = content
|
||||
|
@ -83,7 +98,7 @@ class Sample:
|
|||
elif permission == "ScoUsersAdmin":
|
||||
HEADERS = get_auth_headers("admin_api", "admin_api")
|
||||
else:
|
||||
raise Exception(f"Bad permission : {permission}")
|
||||
raise SampleException(f"Bad permission : {permission}")
|
||||
if self.method == "GET":
|
||||
self.result = GET(self.url, HEADERS)
|
||||
elif self.method == "POST":
|
||||
|
@ -94,20 +109,19 @@ class Sample:
|
|||
self.result = POST_JSON(self.url, json.loads(self.content), HEADERS)
|
||||
elif self.method[0] != "#":
|
||||
error = f'Bad method : "{self.method}"'
|
||||
raise Exception(error)
|
||||
raise SampleException(error)
|
||||
self.shorten()
|
||||
file = open(f"sample_TEST.json.md", "tw")
|
||||
self.dump(file)
|
||||
file.close()
|
||||
with open("sample_TEST.json.md", "tw", encoding="utf-8") as f:
|
||||
self.dump(f)
|
||||
|
||||
def _shorten(
|
||||
self, item
|
||||
): # abrege les longues listes (limite à 2 éléments et affiche "... etc. à la place"
|
||||
def _shorten(self, item):
|
||||
"Abrège les longues listes: limite à 2 éléments et affiche '...' etc. à la place"
|
||||
if isinstance(item, list):
|
||||
return [self._shorten(child) for child in item[:2]] + ["... etc."]
|
||||
return [self._shorten(child) for child in item[:2] + ["..."]]
|
||||
return item
|
||||
|
||||
def shorten(self):
|
||||
"Abrège le résultat"
|
||||
self.result = self._shorten(self.result)
|
||||
|
||||
def pp(self):
|
||||
|
@ -122,8 +136,8 @@ class Sample:
|
|||
|
||||
file.write(f"#### {self.method} {self.url}\n")
|
||||
if len(self.content) > 0:
|
||||
file.write(f"> `Content-Type: application/json`\n")
|
||||
file.write(f"> \n")
|
||||
file.write("> `Content-Type: application/json`\n")
|
||||
file.write("> \n")
|
||||
file.write(f"> `{self.content}`\n\n")
|
||||
|
||||
file.write("```json\n")
|
||||
|
@ -143,7 +157,7 @@ class Samples:
|
|||
"""Entry_names: la liste des entrées à reconstruire.
|
||||
si None, la totalité des lignes de samples.csv est prise en compte
|
||||
"""
|
||||
self.entries = defaultdict(lambda: set())
|
||||
self.entries = defaultdict(set)
|
||||
self.entry_names = entry_names
|
||||
|
||||
def add_sample(self, line):
|
||||
|
@ -171,35 +185,35 @@ class Samples:
|
|||
|
||||
def dump(self):
|
||||
for entry, samples in self.entries.items():
|
||||
file = open(f"{DATA_DIR}sample_{entry}.json.md", "tw")
|
||||
file.write(f"### {entry}\n\n")
|
||||
for sample in sorted(
|
||||
samples, key=lambda s: s.url
|
||||
): # sorted de façon à rendre le fichier résultat déterministe (i.e. indépendant de l ordre d arrivée des résultats)
|
||||
sample.dump(file)
|
||||
file.close()
|
||||
with open(f"{DATA_DIR}sample_{entry}.json.md", "tw", encoding="utf-8") as f:
|
||||
f.write(f"### {entry}\n\n")
|
||||
# Trié de façon à rendre le fichier indépendant de l'ordre des résultats
|
||||
for sample in sorted(samples, key=lambda s: s.url):
|
||||
sample.dump(f)
|
||||
|
||||
|
||||
def make_samples(samples_filename):
|
||||
if len(sys.argv) == 1:
|
||||
entry_names = None
|
||||
elif len(sys.argv) >= 3 and sys.argv[1] == "-i":
|
||||
"Génère les samples"
|
||||
entry_names = None
|
||||
if len(sys.argv) >= 3 and sys.argv[1] == "-i":
|
||||
samples_filename = sys.argv[2]
|
||||
entry_names = sys.argv[3:] if len(sys.argv) > 3 else None
|
||||
else:
|
||||
entry_names = sys.argv[1:]
|
||||
|
||||
if os.path.exists(DATA_DIR):
|
||||
if not os.path.isdir(DATA_DIR):
|
||||
raise f"{DATA_DIR} existe déjà et n'est pas un répertoire"
|
||||
else:
|
||||
# DATA_DIR existe déjà - effacer et recréer
|
||||
shutil.rmtree(DATA_DIR)
|
||||
os.mkdir(DATA_DIR)
|
||||
raise SampleException(f"{DATA_DIR} existe déjà et n'est pas un répertoire")
|
||||
# DATA_DIR existe déjà - effacer et recréer
|
||||
shutil.rmtree(DATA_DIR)
|
||||
os.mkdir(DATA_DIR)
|
||||
else:
|
||||
os.mkdir(DATA_DIR)
|
||||
|
||||
samples = Samples(entry_names)
|
||||
df = read_csv(
|
||||
df = pd.read_csv(
|
||||
samples_filename,
|
||||
comment="#",
|
||||
sep=";",
|
||||
quotechar='"',
|
||||
dtype={
|
||||
|
@ -212,11 +226,12 @@ def make_samples(samples_filename):
|
|||
keep_default_na=False,
|
||||
)
|
||||
df = df.reset_index()
|
||||
df.apply(lambda line: samples.add_sample(line), axis=1)
|
||||
df.apply(samples.add_sample, axis=1)
|
||||
samples.dump()
|
||||
return samples
|
||||
|
||||
|
||||
if not CHECK_CERTIFICATE:
|
||||
urllib3.disable_warnings()
|
||||
|
||||
make_samples(SAMPLES_FILENAME)
|
||||
|
|
|
@ -1,119 +1,120 @@
|
|||
"entry_name";"url";"permission";"method";"content"
|
||||
"assiduite_create";"/assiduite/1/create";"ScoView";"POST";"{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""absent""}"
|
||||
"assiduite_create";"/assiduite/1/create/batch";"ScoView";"POST";"{""batch"":[{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""absent""},{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""retard""},{""date_debut"": ""2022-10-27T11:00"",""date_fin"": ""2022-10-27T13:00"",""etat"": ""present""}]}"
|
||||
"assiduite_delete";"/assiduite/delete";"ScoView";"POST";"{""assiduite_id"": 1}"
|
||||
"assiduite_delete";"/assiduite/delete/batch";"ScoView";"POST";"{""batch"":[2,2,3]}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""etat"": ""retard"",""moduleimpl_id"":3}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""etat"":""absent""}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""moduleimpl_id"":2}"
|
||||
"assiduite";"/assiduite/1";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1/query?moduleimpl_id=1";"ScoView";"GET";
|
||||
"assiduites_count";"/assiduites/1/count";"ScoView";"GET";
|
||||
"assiduites_count";"/assiduites/1/count/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites_count";"/assiduites/1/count/query?etat=present,retard&metric=compte,heure";"ScoView";"GET";
|
||||
"assiduites_count";"/assiduites/1/count/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count/query?etat=present,retard&metric=compte,heure";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites_formsemestre";"/assiduites/formsemestre/1";"ScoView";"GET";
|
||||
"assiduites_formsemestre";"/assiduites/formsemestre/1/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites_formsemestre";"/assiduites/formsemestre/1/query?moduleimpl_id=1";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites_formsemestre_count";"/assiduites/formsemestre/1/count/query?etat=present,retard&metric=compte,heure";"ScoView";"GET";
|
||||
"assiduite_create";"/assiduite/1/create";"ScoView";"POST";"{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""absent""}"
|
||||
"assiduite_create";"/assiduite/1/create/batch";"ScoView";"POST";"{""batch"":[{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""absent""},{""date_debut"": ""2022-10-27T08:00"",""date_fin"": ""2022-10-27T10:00"",""etat"": ""retard""},{""date_debut"": ""2022-10-27T11:00"",""date_fin"": ""2022-10-27T13:00"",""etat"": ""present""}]}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""etat"":""absent""}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""moduleimpl_id"":2}"
|
||||
"assiduite_edit";"/assiduite/1/edit";"ScoView";"POST";"{""etat"": ""retard"",""moduleimpl_id"":3}"
|
||||
"assiduite_delete";"/assiduite/delete";"ScoView";"POST";"{""assiduite_id"": 1}"
|
||||
"assiduite_delete";"/assiduite/delete/batch";"ScoView";"POST";"{""batch"":[2,2,3]}"
|
||||
"departements";"/departements";"ScoView";"GET";
|
||||
"departements-ids";"/departements_ids";"ScoView";"GET";
|
||||
"departement";"/departement/TAPI";"ScoView";"GET";
|
||||
"departement";"/departement/id/1";"ScoView";"GET";
|
||||
"departement-etudiants";"/departement/TAPI/etudiants";"ScoView";"GET";
|
||||
"departement-etudiants";"/departement/id/1/etudiants";"ScoView";"GET";
|
||||
"departement-formsemestres_ids";"/departement/TAPI/formsemestres_ids";"ScoView";"GET";
|
||||
"departement-formsemestres_ids";"/departement/id/1/formsemestres_ids";"ScoView";"GET";
|
||||
"departement-formsemestres-courants";"/departement/TAPI/formsemestres_courants";"ScoView";"GET";
|
||||
"departement-formsemestres-courants";"/departement/id/1/formsemestres_courants";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1/query?etat=retard";"ScoView";"GET";
|
||||
"assiduites";"/assiduites/1/query?moduleimpl_id=1";"ScoView";"GET";
|
||||
"departement-create";"/departement/create";"ScoSuperAdmin";"POST";"{""acronym"": ""NEWONE"" , ""visible"": true}"
|
||||
"departement-edit";"/departement/NEWONE/edit";"ScoSuperAdmin";"POST";"{""visible"": false}"
|
||||
"departement-delete";"/departement/NEWONE/delete";"ScoSuperAdmin";"POST";
|
||||
"etudiants-courants";"/etudiants/courants?date_courante=2022-07-20";"ScoView";"GET";
|
||||
"etudiants-courants";"/etudiants/courants/long?date_courante=2022-07-20";"ScoView";"GET";
|
||||
"departement-edit";"/departement/NEWONE/edit";"ScoSuperAdmin";"POST";"{""visible"": false}"
|
||||
"departement-etudiants";"/departement/id/1/etudiants";"ScoView";"GET";
|
||||
"departement-etudiants";"/departement/TAPI/etudiants";"ScoView";"GET";
|
||||
"departement-formsemestres_ids";"/departement/id/1/formsemestres_ids";"ScoView";"GET";
|
||||
"departement-formsemestres_ids";"/departement/TAPI/formsemestres_ids";"ScoView";"GET";
|
||||
"departement-formsemestres-courants";"/departement/id/1/formsemestres_courants";"ScoView";"GET";
|
||||
"departement-formsemestres-courants";"/departement/TAPI/formsemestres_courants";"ScoView";"GET";
|
||||
"departement-logo";"/departement/id/1/logo/D";"ScoSuperAdmin";"GET";
|
||||
"departement-logo";"/departement/TAPI/logo/D";"ScoSuperAdmin";"GET";
|
||||
"departement-logos";"/departement/id/1/logos";"ScoSuperAdmin";"GET";
|
||||
"departement-logos";"/departement/TAPI/logos";"ScoSuperAdmin";"GET";
|
||||
"departement";"/departement/id/1";"ScoView";"GET";
|
||||
"departement";"/departement/TAPI";"ScoView";"GET";
|
||||
"departements-ids";"/departements_ids";"ScoView";"GET";
|
||||
"departements";"/departements";"ScoView";"GET";
|
||||
"etudiant_formsemestres";"/etudiant/nip/11/formsemestres";"ScoView";"GET";
|
||||
"etudiant-formsemestre-bulletin";"/etudiant/etudid/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
#"etudiant-formsemestre-bulletin";"/etudiant/ine/INE11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
#"etudiant-formsemestre-bulletin";"/etudiant/nip/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
#"etudiant-formsemestre-bulletin";"/etudiant/nip/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"etudiant-formsemestre-groups";"/etudiant/etudid/11/formsemestre/1/groups";"ScoView";"GET";
|
||||
"etudiant-formsemestres";"/etudiant/etudid/11/formsemestres";"ScoView";"GET";
|
||||
"etudiant-formsemestres";"/etudiant/ine/INE11/formsemestres";"ScoView";"GET";
|
||||
"etudiant";"/etudiant/etudid/11";"ScoView";"GET";
|
||||
"etudiant";"/etudiant/nip/11";"ScoView";"GET";
|
||||
"etudiant";"/etudiant/ine/INE11";"ScoView";"GET";
|
||||
"etudiant";"/etudiant/nip/11";"ScoView";"GET";
|
||||
"etudiants-clef";"/etudiants/etudid/11";"ScoView";"GET";
|
||||
"etudiants-clef";"/etudiants/ine/INE11";"ScoView";"GET";
|
||||
"etudiants-clef";"/etudiants/nip/11";"ScoView";"GET";
|
||||
"etudiant-formsemestres";"/etudiant/etudid/11/formsemestres";"ScoView";"GET";
|
||||
"etudiant-formsemestres";"/etudiant/ine/INE11/formsemestres";"ScoView";"GET";
|
||||
"etudiant_formsemestres";"/etudiant/nip/11/formsemestres";"ScoView";"GET";
|
||||
"etudiant-formsemestre-bulletin";"/etudiant/etudid/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"etudiant-formsemestre-bulletin";"/etudiant/ine/INE11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"etudiant-formsemestre-bulletin";"/etudiant/nip/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"etudiant-formsemestre-bulletin";"/etudiant/nip/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"etudiant-formsemestre-groups";"/etudiant/etudid/11/formsemestre/1/groups";"ScoView";"GET";
|
||||
"formations";"/formations";"ScoView";"GET";
|
||||
"formations_ids";"/formations_ids";"ScoView";"GET";
|
||||
"formation";"/formation/1";"ScoView";"GET";
|
||||
"formation-export";"/formation/1/export";"ScoView";"GET";
|
||||
"etudiants-courants";"/etudiants/courants?date_courante=2022-07-20";"ScoView";"GET";
|
||||
"etudiants-courants";"/etudiants/courants/long?date_courante=2022-07-20";"ScoView";"GET";
|
||||
"evaluation";"/evaluation/1";"ScoView";"GET";
|
||||
"evaluation-notes";"/evaluation/1/notes";"ScoView";"GET";
|
||||
"formation-export";"/formation/1/export_with_ids";"ScoView";"GET";
|
||||
"formation-export";"/formation/1/export";"ScoView";"GET";
|
||||
"formation-referentiel_competences";"/formation/1/referentiel_competences";"ScoView";"GET";
|
||||
"moduleimpl";"/moduleimpl/1";"ScoView";"GET";
|
||||
"formation";"/formation/1";"ScoView";"GET";
|
||||
"formations_ids";"/formations_ids";"ScoView";"GET";
|
||||
"formations";"/formations";"ScoView";"GET";
|
||||
"formsemestre-bulletins";"/formsemestre/1/bulletins";"ScoView";"GET";
|
||||
"formsemestre-decisions_jury";"/formsemestre/1/decisions_jury";"ScoView";"GET";
|
||||
"formsemestre-etat_evals";"/formsemestre/1/etat_evals";"ScoView";"GET";
|
||||
"formsemestre-etudiants-query";"/formsemestre/1/etudiants/query?etat=D";"ScoView";"GET";
|
||||
"formsemestre-etudiants";"/formsemestre/1/etudiants";"ScoView";"GET";
|
||||
"formsemestre-etudiants";"/formsemestre/1/etudiants/long";"ScoView";"GET";
|
||||
"formsemestre-partition-create";"/formsemestre/1/partition/create";"ScoSuperAdmin";"POST";"{""partition_name"": ""PART""} "
|
||||
"formsemestre-partitions-order";"/formsemestre/1/partitions/order";"ScoSuperAdmin";"POST";"[ 1 ]"
|
||||
"formsemestre-partitions";"/formsemestre/1/partitions";"ScoView";"GET";
|
||||
"formsemestre-programme";"/formsemestre/1/programme";"ScoView";"GET";
|
||||
"formsemestre-resultats";"/formsemestre/1/resultats";"ScoView";"GET";
|
||||
"formsemestre";"/formsemestre/1";"ScoView";"GET";
|
||||
"formsemestres-query";"/formsemestres/query?annee_scolaire=2022&etape_apo=A2";"ScoView";"GET";
|
||||
"formsemestres-query";"/formsemestres/query?nip=11";"ScoView";"GET";
|
||||
"formsemestre-bulletins";"/formsemestre/1/bulletins";"ScoView";"GET";
|
||||
"formsemestre-programme";"/formsemestre/1/programme";"ScoView";"GET";
|
||||
"formsemestre-etudiants";"/formsemestre/1/etudiants";"ScoView";"GET";
|
||||
"formsemestre-etudiants";"/formsemestre/1/etudiants/long";"ScoView";"GET";
|
||||
"formsemestre-etudiants-query";"/formsemestre/1/etudiants/query?etat=D";"ScoView";"GET";
|
||||
"formsemestre-etat_evals";"/formsemestre/1/etat_evals";"ScoView";"GET";
|
||||
"formsemestre-resultats";"/formsemestre/1/resultats";"ScoView";"GET";
|
||||
"formsemestre-decisions_jury";"/formsemestre/1/decisions_jury";"ScoView";"GET";
|
||||
"formsemestre-partitions";"/formsemestre/1/partitions";"ScoView";"GET";
|
||||
"partition";"/partition/1";"ScoView";"GET";
|
||||
"group-etudiants";"/group/1/etudiants";"ScoView";"GET";
|
||||
"group-etudiants-query";"/group/1/etudiants/query?etat=D";"ScoView";"GET";
|
||||
"moduleimpl-evaluations";"/moduleimpl/1/evaluations";"ScoView";"GET";
|
||||
"evaluation-notes";"/evaluation/1/notes";"ScoView";"GET";
|
||||
"user";"/user/1";"ScoView";"GET";
|
||||
"users-query";"/users/query?starts_with=u_";"ScoView";"GET";
|
||||
"permissions";"/permissions";"ScoView";"GET";
|
||||
"roles";"/roles";"ScoView";"GET";
|
||||
"role";"/role/Observateur";"ScoView";"GET";
|
||||
"group-set_etudiant";"/group/1/set_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"group-remove_etudiant";"/group/1/remove_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"partition-group-create";"/partition/1/group/create";"ScoSuperAdmin";"POST";"{""group_name"": ""NEW_GROUP""}"
|
||||
"group-edit";"/group/2/edit";"ScoSuperAdmin";"POST";"{""group_name"": ""NEW_GROUP2""}"
|
||||
"group-delete";"/group/2/delete";"ScoSuperAdmin";"POST";
|
||||
"formsemestre-partition-create";"/formsemestre/1/partition/create";"ScoSuperAdmin";"POST";"{""partition_name"": ""PART""} "
|
||||
"formsemestre-partitions-order";"/formsemestre/1/partitions/order";"ScoSuperAdmin";"POST";"[ 1 ]"
|
||||
"partition-edit";"/partition/1/edit";"ScoSuperAdmin";"POST";"{""partition_name"":""P2BIS"", ""numero"":3,""bul_show_rank"":true,""show_in_lists"":false, ""groups_editable"":true}"
|
||||
"partition-remove_etudiant";"/partition/2/remove_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"partition-groups-order";"/partition/1/groups/order";"ScoSuperAdmin";"POST";"[ 1 ]"
|
||||
"group-edit";"/group/2/edit";"ScoSuperAdmin";"POST";"{""group_name"": ""NEW_GROUP2""}"
|
||||
"group-etudiants-query";"/group/1/etudiants/query?etat=D";"ScoView";"GET";
|
||||
"group-etudiants";"/group/1/etudiants";"ScoView";"GET";
|
||||
"group-remove_etudiant";"/group/1/remove_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"group-set_etudiant";"/group/1/set_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"logo";"/logo/B";"ScoSuperAdmin";"GET";
|
||||
"logos";"/logos";"ScoSuperAdmin";"GET";
|
||||
"moduleimpl-evaluations";"/moduleimpl/1/evaluations";"ScoView";"GET";
|
||||
"moduleimpl";"/moduleimpl/1";"ScoView";"GET";
|
||||
"partition-delete";"/partition/2/delete";"ScoSuperAdmin";"POST";
|
||||
"partition-edit";"/partition/1/edit";"ScoSuperAdmin";"POST";"{""partition_name"":""P2BIS"", ""numero"":3,""bul_show_rank"":true,""show_in_lists"":false, ""groups_editable"":true}"
|
||||
"partition-group-create";"/partition/1/group/create";"ScoSuperAdmin";"POST";"{""group_name"": ""NEW_GROUP""}"
|
||||
"partition-groups-order";"/partition/1/groups/order";"ScoSuperAdmin";"POST";"[ 1 ]"
|
||||
"partition-remove_etudiant";"/partition/2/remove_etudiant/10";"ScoSuperAdmin";"POST";
|
||||
"partition";"/partition/1";"ScoView";"GET";
|
||||
"permissions";"/permissions";"ScoView";"GET";
|
||||
"role-add_permission";"/role/customRole/add_permission/ScoUsersView";"ScoSuperAdmin";"POST";
|
||||
"role-create";"/role/create/customRole";"ScoSuperAdmin";"POST";"{""permissions"": [""ScoView"", ""ScoUsersView""]}"
|
||||
"role-delete";"/role/customRole/delete";"ScoSuperAdmin";"POST";
|
||||
"role-edit";"/role/customRole/edit";"ScoSuperAdmin";"POST";"{ ""name"" : ""LaveurDeVitres"", ""permissions"" : [ ""ScoView"" ] }"
|
||||
"role-remove_permission";"/role/customRole/remove_permission/ScoUsersView";"ScoSuperAdmin";"POST";
|
||||
"role";"/role/Observateur";"ScoView";"GET";
|
||||
"roles";"/roles";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"user-create";"/user/create";"ScoSuperAdmin";"POST";"{""user_name"": ""alain"", ""dept"": null, ""nom"": ""alain"", ""prenom"": ""bruno"", ""active"": true }"
|
||||
"user-edit";"/user/10/edit";"ScoSuperAdmin";"POST";"{ ""dept"": ""TAPI"", ""nom"": ""alain2"", ""prenom"": ""bruno2"", ""active"": false }"
|
||||
"user-password";"/user/3/password";"ScoSuperAdmin";"POST";"{ ""password"": ""rePlaCemeNT456averylongandcomplicated"" }"
|
||||
"user-password";"/user/3/password";"ScoSuperAdmin";"POST";"{ ""password"": ""too_simple"" }"
|
||||
"user-role-add";"/user/10/role/Observateur/add";"ScoSuperAdmin";"POST";
|
||||
"user-role-remove";"/user/10/role/Observateur/remove";"ScoSuperAdmin";"POST";
|
||||
"role-create";"/role/create/customRole";"ScoSuperAdmin";"POST";"{""permissions"": [""ScoView"", ""ScoUsersView""]}"
|
||||
"role-remove_permission";"/role/customRole/remove_permission/ScoUsersView";"ScoSuperAdmin";"POST";
|
||||
"role-add_permission";"/role/customRole/add_permission/ScoUsersView";"ScoSuperAdmin";"POST";
|
||||
"role-edit";"/role/customRole/edit";"ScoSuperAdmin";"POST";"{ ""name"" : ""LaveurDeVitres"", ""permissions"" : [ ""ScoView"" ] }"
|
||||
"role-delete";"/role/customRole/delete";"ScoSuperAdmin";"POST";
|
||||
"logos";"/logos";"ScoSuperAdmin";"GET";
|
||||
"logo";"/logo/B";"ScoSuperAdmin";"GET";
|
||||
"departement-logos";"/departement/TAPI/logos";"ScoSuperAdmin";"GET";
|
||||
"departement-logos";"/departement/id/1/logos";"ScoSuperAdmin";"GET";
|
||||
"departement-logo";"/departement/TAPI/logo/D";"ScoSuperAdmin";"GET";
|
||||
"departement-logo";"/departement/id/1/logo/D";"ScoSuperAdmin";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/short/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/pdf";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin/short";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/etudid/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/ine/INE11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"test-pdf";"/etudiant/nip/11/formsemestre/1/bulletin";"ScoView";"GET";
|
||||
"user";"/user/1";"ScoView";"GET";
|
||||
"users-query";"/users/query?starts_with=u_";"ScoView";"GET";
|
||||
|
|
Can't render this file because it contains an unexpected character in line 41 and column 2.
|
|
@ -6,10 +6,9 @@ import app
|
|||
from app import db
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_but import ResultatsSemestreBUT
|
||||
from app.models import FormSemestre, ModuleImpl
|
||||
from app.models import Evaluation, FormSemestre, ModuleImpl
|
||||
from app.scodoc import (
|
||||
sco_bulletins,
|
||||
sco_evaluation_db,
|
||||
sco_formsemestre,
|
||||
sco_saisie_notes,
|
||||
)
|
||||
|
@ -131,7 +130,9 @@ def test_notes_rattrapage(test_client):
|
|||
# Note moyenne: reviens à 10/20
|
||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0)
|
||||
# Supprime l'évaluation de rattrapage:
|
||||
sco_evaluation_db.do_evaluation_delete(e_rat["id"])
|
||||
evaluation = db.session.get(Evaluation, e_rat["id"])
|
||||
assert evaluation
|
||||
evaluation.delete()
|
||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||
sem["formsemestre_id"], etud["etudid"]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue