forked from ScoDoc/ScoDoc
Merge remote-tracking branch 'origin/master' into clean
This commit is contained in:
commit
a4d0205cc7
@ -303,8 +303,9 @@ def clear_scodoc_cache():
|
|||||||
# --------- Logging
|
# --------- Logging
|
||||||
def log(msg: str, silent_test=True):
|
def log(msg: str, silent_test=True):
|
||||||
"""log a message.
|
"""log a message.
|
||||||
If Flask app, use configured logger, else stderr."""
|
If Flask app, use configured logger, else stderr.
|
||||||
if silent_test and current_app.config["TESTING"]:
|
"""
|
||||||
|
if silent_test and current_app and current_app.config["TESTING"]:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
dept = getattr(g, "scodoc_dept", "")
|
dept = getattr(g, "scodoc_dept", "")
|
||||||
|
@ -63,4 +63,4 @@ from app.models.notes import (
|
|||||||
NotesNotes,
|
NotesNotes,
|
||||||
NotesNotesLog,
|
NotesNotesLog,
|
||||||
)
|
)
|
||||||
from app.models.preferences import ScoPreference
|
from app.models.preferences import ScoPreference, ScoDocSiteConfig
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
"""Model : preferences
|
"""Model : preferences
|
||||||
"""
|
"""
|
||||||
from app import db
|
from app import db, log
|
||||||
|
from app.scodoc import bonus_sport
|
||||||
|
|
||||||
|
|
||||||
class ScoPreference(db.Model):
|
class ScoPreference(db.Model):
|
||||||
"""ScoDoc preferences"""
|
"""ScoDoc preferences (par département)"""
|
||||||
|
|
||||||
__tablename__ = "sco_prefs"
|
__tablename__ = "sco_prefs"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -17,3 +18,84 @@ class ScoPreference(db.Model):
|
|||||||
name = db.Column(db.String(128), nullable=False, index=True)
|
name = db.Column(db.String(128), nullable=False, index=True)
|
||||||
value = db.Column(db.Text())
|
value = db.Column(db.Text())
|
||||||
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))
|
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))
|
||||||
|
|
||||||
|
|
||||||
|
class ScoDocSiteConfig(db.Model):
|
||||||
|
"""Config. d'un site
|
||||||
|
Nouveau en ScoDoc 9: va regrouper les paramètres qui dans les versions
|
||||||
|
antérieures étaient dans scodoc_config.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "scodoc_site_config"
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.String(128), nullable=False, index=True)
|
||||||
|
value = db.Column(db.Text())
|
||||||
|
|
||||||
|
BONUS_SPORT = "bonus_sport_func_name"
|
||||||
|
|
||||||
|
def __init__(self, name, value):
|
||||||
|
self.name = name
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{self.__class__.__name__}('{self.name}', '{self.value}')>"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_bonus_sport_func(cls, func_name):
|
||||||
|
"""Record bonus_sport config.
|
||||||
|
If func_name not defined, raise NameError
|
||||||
|
"""
|
||||||
|
if func_name not in cls.get_bonus_sport_func_names():
|
||||||
|
raise NameError("invalid function name for bonus_sport")
|
||||||
|
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
|
||||||
|
if c:
|
||||||
|
log("setting to " + func_name)
|
||||||
|
c.value = func_name
|
||||||
|
else:
|
||||||
|
c = ScoDocSiteConfig(cls.BONUS_SPORT, func_name)
|
||||||
|
db.session.add(c)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_bonus_sport_func_name(cls):
|
||||||
|
"""Get configured bonus function name, or None if None."""
|
||||||
|
f = cls.get_bonus_sport_func_from_name()
|
||||||
|
if f is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return f.__name__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_bonus_sport_func(cls):
|
||||||
|
"""Get configured bonus function, or None if None."""
|
||||||
|
return cls.get_bonus_sport_func_from_name()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_bonus_sport_func_from_name(cls, func_name=None):
|
||||||
|
"""returns bonus func with specified name.
|
||||||
|
If name not specified, return the configured function.
|
||||||
|
None if no bonus function configured.
|
||||||
|
Raises NameError if func_name not found in module bonus_sport.
|
||||||
|
"""
|
||||||
|
if func_name is None:
|
||||||
|
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
|
||||||
|
if c is None:
|
||||||
|
return None
|
||||||
|
func_name = c.value
|
||||||
|
if func_name == "": # pas de bonus défini
|
||||||
|
return None
|
||||||
|
return getattr(bonus_sport, func_name)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_bonus_sport_func_names(cls):
|
||||||
|
"""List available functions names
|
||||||
|
(starting with empty string to represent "no bonus function").
|
||||||
|
"""
|
||||||
|
return [""] + sorted(
|
||||||
|
[
|
||||||
|
getattr(bonus_sport, name).__name__
|
||||||
|
for name in dir(bonus_sport)
|
||||||
|
if name.startswith("bonus_")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@ -35,6 +35,7 @@ from operator import itemgetter
|
|||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
|
|
||||||
|
from app.models import ScoDocSiteConfig
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
@ -922,9 +923,13 @@ class NotesTable(object):
|
|||||||
if len(coefs_bonus_gen) == 1:
|
if len(coefs_bonus_gen) == 1:
|
||||||
coefs_bonus_gen = [1.0] # irrelevant, may be zero
|
coefs_bonus_gen = [1.0] # irrelevant, may be zero
|
||||||
|
|
||||||
bonus = scu.CONFIG.compute_bonus(
|
bonus_func = ScoDocSiteConfig.get_bonus_sport_func()
|
||||||
notes_bonus_gen, coefs_bonus_gen, infos=infos
|
if bonus_func:
|
||||||
)
|
bonus = bonus_func(
|
||||||
|
notes_bonus_gen, coefs_bonus_gen, infos=infos
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
bonus = 0.0
|
||||||
self.bonus[etudid] = bonus
|
self.bonus[etudid] = bonus
|
||||||
infos["moy"] += bonus
|
infos["moy"] += bonus
|
||||||
infos["moy"] = min(infos["moy"], 20.0) # clip bogus bonus
|
infos["moy"] = min(infos["moy"], 20.0) # clip bogus bonus
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""Configuration de ScoDoc (version 2020)
|
"""Configuration de ScoDoc (version ScoDOc 9)
|
||||||
NE PAS MODIFIER localement ce fichier !
|
NE PAS MODIFIER localement ce fichier !
|
||||||
mais éditer /opt/scodoc/var/scodoc/config/scodoc_local.py
|
mais éditer /opt/scodoc-data/config/scodoc_local.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app.scodoc import bonus_sport
|
from app.scodoc import bonus_sport
|
||||||
@ -20,10 +20,6 @@ CONFIG = AttrDict()
|
|||||||
# set to 1 if you want to require INE:
|
# set to 1 if you want to require INE:
|
||||||
CONFIG.always_require_ine = 0
|
CONFIG.always_require_ine = 0
|
||||||
|
|
||||||
# The base URL, use only if you are behind a proxy
|
|
||||||
# eg "https://scodoc.example.net/ScoDoc"
|
|
||||||
CONFIG.ABSOLUTE_URL = ""
|
|
||||||
|
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
# -------------- Documents PDF
|
# -------------- Documents PDF
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
@ -52,12 +48,6 @@ CONFIG.LOGO_HEADER_HEIGHT = 28
|
|||||||
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir sco_version.py)
|
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir sco_version.py)
|
||||||
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
#
|
|
||||||
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
|
||||||
#
|
|
||||||
|
|
||||||
CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
|
||||||
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
|
||||||
|
|
||||||
# ------------- Capitalisation des UEs -------------
|
# ------------- Capitalisation des UEs -------------
|
||||||
# Deux écoles:
|
# Deux écoles:
|
||||||
|
@ -17,27 +17,26 @@ def load_local_configuration(scodoc_cfg_dir):
|
|||||||
"""Load local configuration file (if exists)
|
"""Load local configuration file (if exists)
|
||||||
and merge it with CONFIG.
|
and merge it with CONFIG.
|
||||||
"""
|
"""
|
||||||
# this path should be synced with upgrade.sh
|
local_config_filename = os.path.join(scodoc_cfg_dir, "scodoc_local.py")
|
||||||
LOCAL_CONFIG_FILENAME = os.path.join(scodoc_cfg_dir, "scodoc_local.py")
|
local_config = None
|
||||||
LOCAL_CONFIG = None
|
if os.path.exists(local_config_filename):
|
||||||
if os.path.exists(LOCAL_CONFIG_FILENAME):
|
|
||||||
if not scodoc_cfg_dir in sys.path:
|
if not scodoc_cfg_dir in sys.path:
|
||||||
sys.path.insert(1, scodoc_cfg_dir)
|
sys.path.insert(0, scodoc_cfg_dir)
|
||||||
try:
|
try:
|
||||||
from scodoc_local import CONFIG as LOCAL_CONFIG
|
from scodoc_local import CONFIG as local_config
|
||||||
|
|
||||||
log("imported %s" % LOCAL_CONFIG_FILENAME)
|
log("imported %s" % local_config_filename)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log("Error: can't import %s" % LOCAL_CONFIG_FILENAME)
|
log("Error: can't import %s" % local_config_filename)
|
||||||
del sys.path[1]
|
del sys.path[0]
|
||||||
if LOCAL_CONFIG is None:
|
if local_config is None:
|
||||||
return
|
return
|
||||||
# Now merges local config in our CONFIG
|
# Now merges local config in our CONFIG
|
||||||
for x in [x for x in dir(LOCAL_CONFIG) if x[0] != "_"]:
|
for x in [x for x in local_config if x[0] != "_"]:
|
||||||
v = getattr(LOCAL_CONFIG, x)
|
v = local_config.get(x)
|
||||||
if not v in sco_config.CONFIG:
|
if not x in sco_config.CONFIG:
|
||||||
log("Warning: local config setting unused parameter %s (skipped)" % x)
|
log(f"Warning: local config setting unused parameter {x} (skipped)")
|
||||||
else:
|
else:
|
||||||
if v != sco_config.CONFIG[x]:
|
if v != sco_config.CONFIG[x]:
|
||||||
log("Setting parameter %s from %s" % (x, LOCAL_CONFIG_FILENAME))
|
log(f"Setting parameter {x} from {local_config_filename}")
|
||||||
sco_config.CONFIG[x] = v
|
sco_config.CONFIG[x] = v
|
||||||
|
@ -1031,7 +1031,7 @@ def module_evaluation_renumber(moduleimpl_id, only_if_unumbered=False, redirect=
|
|||||||
|
|
||||||
|
|
||||||
# -------------- VIEWS
|
# -------------- VIEWS
|
||||||
def evaluation_describe(evaluation_id="", edit_in_place=True, REQUEST=None):
|
def evaluation_describe(evaluation_id="", edit_in_place=True):
|
||||||
"""HTML description of evaluation, for page headers
|
"""HTML description of evaluation, for page headers
|
||||||
edit_in_place: allow in-place editing when permitted (not implemented)
|
edit_in_place: allow in-place editing when permitted (not implemented)
|
||||||
"""
|
"""
|
||||||
@ -1046,7 +1046,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, REQUEST=None):
|
|||||||
resp = u["prenomnom"]
|
resp = u["prenomnom"]
|
||||||
nomcomplet = u["nomcomplet"]
|
nomcomplet = u["nomcomplet"]
|
||||||
can_edit = sco_permissions_check.can_edit_notes(
|
can_edit = sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, moduleimpl_id, allow_ens=False
|
current_user, moduleimpl_id, allow_ens=False
|
||||||
)
|
)
|
||||||
|
|
||||||
link = (
|
link = (
|
||||||
@ -1223,7 +1223,7 @@ def evaluation_create_form(
|
|||||||
if not readonly:
|
if not readonly:
|
||||||
H = ["<h3>%svaluation en %s</h3>" % (action, mod_descr)]
|
H = ["<h3>%svaluation en %s</h3>" % (action, mod_descr)]
|
||||||
else:
|
else:
|
||||||
return evaluation_describe(evaluation_id, REQUEST=REQUEST)
|
return evaluation_describe(evaluation_id)
|
||||||
|
|
||||||
heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)]
|
heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)]
|
||||||
#
|
#
|
||||||
|
@ -80,11 +80,7 @@ def do_evaluation_listenotes(REQUEST):
|
|||||||
E = evals[0] # il y a au moins une evaluation
|
E = evals[0] # il y a au moins une evaluation
|
||||||
# description de l'evaluation
|
# description de l'evaluation
|
||||||
if mode == "eval":
|
if mode == "eval":
|
||||||
H = [
|
H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)]
|
||||||
sco_evaluations.evaluation_describe(
|
|
||||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
H = []
|
H = []
|
||||||
# groupes
|
# groupes
|
||||||
@ -529,9 +525,7 @@ def _make_table_notes(
|
|||||||
eval_info = '<span class="eval_info eval_incomplete">Notes incomplètes, évaluation non prise en compte dans les moyennes</span>'
|
eval_info = '<span class="eval_info eval_incomplete">Notes incomplètes, évaluation non prise en compte dans les moyennes</span>'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
sco_evaluations.evaluation_describe(
|
sco_evaluations.evaluation_describe(evaluation_id=E["evaluation_id"])
|
||||||
evaluation_id=E["evaluation_id"], REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
+ eval_info
|
+ eval_info
|
||||||
+ html_form
|
+ html_form
|
||||||
+ t
|
+ t
|
||||||
@ -786,9 +780,7 @@ def evaluation_check_absences_html(
|
|||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST, "Vérification absences à l'évaluation"
|
REQUEST, "Vérification absences à l'évaluation"
|
||||||
),
|
),
|
||||||
sco_evaluations.evaluation_describe(
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
||||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""",
|
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""",
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
|
@ -186,9 +186,7 @@ def do_placement_selectetuds():
|
|||||||
# M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0]
|
# M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# description de l'evaluation
|
# description de l'evaluation
|
||||||
H = [
|
H = [
|
||||||
sco_evaluations.evaluation_describe(
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
||||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
"<h3>Placement et émargement des étudiants</h3>",
|
"<h3>Placement et émargement des étudiants</h3>",
|
||||||
]
|
]
|
||||||
#
|
#
|
||||||
|
@ -630,9 +630,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=[], REQUEST=None):
|
|||||||
cssstyles=sco_groups_view.CSSSTYLES,
|
cssstyles=sco_groups_view.CSSSTYLES,
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
),
|
),
|
||||||
sco_evaluations.evaluation_describe(
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
||||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
"""<span class="eval_title">Saisie des notes par fichier</span>""",
|
"""<span class="eval_title">Saisie des notes par fichier</span>""",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -909,9 +907,7 @@ def saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
|
|||||||
cssstyles=sco_groups_view.CSSSTYLES,
|
cssstyles=sco_groups_view.CSSSTYLES,
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
),
|
),
|
||||||
sco_evaluations.evaluation_describe(
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
||||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
'<div id="saisie_notes"><span class="eval_title">Saisie des notes</span>',
|
'<div id="saisie_notes"><span class="eval_title">Saisie des notes</span>',
|
||||||
]
|
]
|
||||||
H.append("""<div id="group-tabs"><table><tr><td>""")
|
H.append("""<div id="group-tabs"><table><tr><td>""")
|
||||||
|
@ -1062,6 +1062,14 @@ h2.formsemestre, .gtrcontent h2 {
|
|||||||
#formnotes td.tf-fieldlabel {
|
#formnotes td.tf-fieldlabel {
|
||||||
border-bottom: 1px dotted #fdcaca;
|
border-bottom: 1px dotted #fdcaca;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Formulaires ScoDoc 9 */
|
||||||
|
form.sco-form {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
div.sco-submit {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
.formsemestre_menubar {
|
.formsemestre_menubar {
|
||||||
border-top: 3px solid #67A7E3;
|
border-top: 3px solid #67A7E3;
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
<a class="navbar-brand" href="{{ url_for('scodoc.index') }}">ScoDoc</a>
|
<a class="navbar-brand" href="{{ url_for('scodoc.index') }}">ScoDoc</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
|
{% if current_user.is_administrator() %}
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li><a href="{{ url_for('scodoc.index') }}">Home</a></li>
|
<li><a href="{{ url_for('scodoc.configuration') }}">Configuration</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
{% if current_user.is_anonymous %}
|
{% if current_user.is_anonymous %}
|
||||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||||
|
33
app/templates/configuration.html
Normal file
33
app/templates/configuration.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% macro render_field(field) %}
|
||||||
|
<div>
|
||||||
|
<span class="wtf-field">{{ field.label }} :</span>
|
||||||
|
<span class="wtf-field">{{ field()|safe }}
|
||||||
|
{% if field.errors %}
|
||||||
|
<ul class=errors>
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Configuration générale</h1>
|
||||||
|
|
||||||
|
<p class="help">Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements).</p>
|
||||||
|
|
||||||
|
<form class="sco-form" action="" method="post" novalidate>
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.bonus_sport_func_name)}}
|
||||||
|
{# <p>
|
||||||
|
{{ form.bonus_sport_func_name.label }}<br>
|
||||||
|
{{ form.bonus_sport_func_name() }}
|
||||||
|
</p> #}
|
||||||
|
<div class="sco-submit">{{ form.submit() }}</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@ -15,7 +15,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept.acronym) else 'link_unauthorized'}}"
|
<a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept.acronym) else 'link_unauthorized'}}"
|
||||||
href="{{url_for('scolar.index_html', scodoc_dept=dept.acronym)}}">Département
|
href="{{url_for('scolar.index_html', scodoc_dept=dept.acronym)}}">Département
|
||||||
{{dept.acronym}}</a>
|
{{dept.preferences.filter_by(name="DeptName").first().value}}</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>
|
<li>
|
||||||
|
@ -31,13 +31,19 @@ Module main: page d'accueil, avec liste des départements
|
|||||||
Emmanuel Viennet, 2021
|
Emmanuel Viennet, 2021
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import render_template
|
from flask import flash, url_for, redirect, render_template
|
||||||
from flask import request
|
from flask import request
|
||||||
|
from flask.app import Flask
|
||||||
from flask_login.utils import login_required
|
from flask_login.utils import login_required
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import SelectField, SubmitField
|
||||||
|
|
||||||
from app.models import Departement
|
# from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
from app.models import Departement, ScoDocSiteConfig
|
||||||
import sco_version
|
import sco_version
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
|
from app.decorators import admin_required
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.views import scodoc_bp as bp
|
from app.views import scodoc_bp as bp
|
||||||
|
|
||||||
@ -66,6 +72,42 @@ def table_etud_in_accessible_depts():
|
|||||||
return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"])
|
return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"])
|
||||||
|
|
||||||
|
|
||||||
|
# ---- CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
class ScoDocConfigurationForm(FlaskForm):
|
||||||
|
"Panneau de configuration général"
|
||||||
|
# très préliminaire ;-)
|
||||||
|
# On veut y mettre la fonction bonus et ensuite les logos
|
||||||
|
bonus_sport_func_name = SelectField(
|
||||||
|
label="Fonction de calcul des bonus sport&culture",
|
||||||
|
choices=[
|
||||||
|
(x, x if x else "Aucune")
|
||||||
|
for x in ScoDocSiteConfig.get_bonus_sport_func_names()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
submit = SubmitField("Enregistrer")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/ScoDoc/configuration", methods=["GET", "POST"])
|
||||||
|
@admin_required
|
||||||
|
def configuration():
|
||||||
|
"Panneau de configuration général"
|
||||||
|
form = ScoDocConfigurationForm(
|
||||||
|
bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func_name()
|
||||||
|
)
|
||||||
|
if form.validate_on_submit():
|
||||||
|
ScoDocSiteConfig.set_bonus_sport_func(form.bonus_sport_func_name.data)
|
||||||
|
flash(f"Configuration enregistrée")
|
||||||
|
return redirect(url_for("scodoc.index"))
|
||||||
|
return render_template(
|
||||||
|
"configuration.html",
|
||||||
|
title="Configuration ScoDoc",
|
||||||
|
form=form,
|
||||||
|
# bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# essais
|
# essais
|
||||||
# @bp.route("/testlog")
|
# @bp.route("/testlog")
|
||||||
# def testlog():
|
# def testlog():
|
||||||
|
35
migrations/versions/f73251d1d825_table_configuration_site.py
Normal file
35
migrations/versions/f73251d1d825_table_configuration_site.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""Table configuration site
|
||||||
|
|
||||||
|
Revision ID: f73251d1d825
|
||||||
|
Revises: f6e7d2e01be1
|
||||||
|
Create Date: 2021-09-04 23:10:39.149965
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f73251d1d825'
|
||||||
|
down_revision = 'f6e7d2e01be1'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('scodoc_site_config',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=128), nullable=False),
|
||||||
|
sa.Column('value', sa.Text(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
op.create_index(op.f('ix_scodoc_site_config_name'), 'scodoc_site_config', ['name'], unique=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_index(op.f('ix_scodoc_site_config_name'), table_name='scodoc_site_config')
|
||||||
|
op.drop_table('scodoc_site_config')
|
||||||
|
# ### end Alembic commands ###
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.0.7"
|
SCOVERSION = "9.0.8"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -51,18 +51,17 @@ def import_scodoc7_user_db(scodoc7_db="dbname=SCOUSERS"):
|
|||||||
)
|
)
|
||||||
# Set roles:
|
# Set roles:
|
||||||
# ScoDoc7 roles are stored as 'AdminRT,EnsRT'
|
# ScoDoc7 roles are stored as 'AdminRT,EnsRT'
|
||||||
|
# ou, dans les rares cas où le dept est en minuscules
|
||||||
|
# "Ensgeii,Admingeii"
|
||||||
if u7["roles"]:
|
if u7["roles"]:
|
||||||
roles7 = u7["roles"].split(",")
|
roles7 = u7["roles"].split(",")
|
||||||
else:
|
else:
|
||||||
roles7 = []
|
roles7 = []
|
||||||
for role_dept in roles7:
|
for role_dept in roles7:
|
||||||
# Cas particulier RespPeRT
|
# Migre les rôles RespPeX, EnsX, AdminX, SecrX et ignore les autres
|
||||||
m = re.match(r"^(-?RespPe)([A-Z][A-Za-z0-9]*?)$", role_dept)
|
m = re.match(r"^(-?Ens|-?Secr|-?ResPe|-?Admin)(.*)$", role_dept)
|
||||||
if not m:
|
if not m:
|
||||||
# Cas général: eg EnsRT
|
msg = f"User {user_name}: role inconnu '{role_dept}' (ignoré)"
|
||||||
m = re.match(r"^(-?[A-Za-z0-9]+?)([A-Z][A-Za-z0-9]*?)$", role_dept)
|
|
||||||
if not m:
|
|
||||||
msg = f"User {user_name}: invalid role '{role_dept}' (ignoring)"
|
|
||||||
current_app.logger.warning(msg)
|
current_app.logger.warning(msg)
|
||||||
messages.append(msg)
|
messages.append(msg)
|
||||||
else:
|
else:
|
||||||
|
@ -125,6 +125,29 @@ migrate_local_files() {
|
|||||||
mkdir -p "$old_logs_dest" || die "erreur creation $old_logs_dest"
|
mkdir -p "$old_logs_dest" || die "erreur creation $old_logs_dest"
|
||||||
mv "${SCODOC7_HOME}"/log/* "$old_logs_dest" || die "erreur mv"
|
mv "${SCODOC7_HOME}"/log/* "$old_logs_dest" || die "erreur mv"
|
||||||
|
|
||||||
|
# Le fichier de customization local:
|
||||||
|
# peut être dans .../var/config/scodoc_local.py
|
||||||
|
# ou bien, sur les très anciennes installs, dans Products/ScoDoc/config/scodoc_config.py
|
||||||
|
# (si migration, copié dans SCODOC7_HOME/config/scodoc_config.py)
|
||||||
|
# en principe ScoDoc 9 est encore compatible avec cet ancien fichier.
|
||||||
|
# donc:
|
||||||
|
if [ ! -e "$SCODOC_VAR_DIR"/scodoc_local.py ]
|
||||||
|
then
|
||||||
|
echo "note: pas de fichier scodoc_local.py (ok)."
|
||||||
|
# if [ "$INPLACE" == 1 ]
|
||||||
|
# then
|
||||||
|
# scodoc_config_filename = "${SCODOC7_HOME}"/Products/ScoDoc/config/scodoc_config.py
|
||||||
|
# else
|
||||||
|
# scodoc_config_filename = "${SCODOC7_HOME}"/config/scodoc_config.py
|
||||||
|
# fi
|
||||||
|
# # Le fichier distribué avait-il été modifié ?
|
||||||
|
# if [ $(md5sum "$scodoc_config_filename" | cut -f1 -d ' ') == "378caca5cb2e3b2753f5989c0762b8cc" ]
|
||||||
|
# then
|
||||||
|
# echo "copying $scodoc_config_filename to $SCODOC_VAR_DIR/scodoc_local.py"
|
||||||
|
# cp "$scodoc_config_filename" "$SCODOC_VAR_DIR"/scodoc_local.py || die "erreur cp"
|
||||||
|
# fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Templates locaux poursuites etudes
|
# Templates locaux poursuites etudes
|
||||||
if [ -e "${SCODOC7_HOME}"/config/doc_poursuites_etudes/local ]
|
if [ -e "${SCODOC7_HOME}"/config/doc_poursuites_etudes/local ]
|
||||||
then
|
then
|
||||||
@ -170,8 +193,8 @@ su -c "(cd $SCODOC_DIR && source venv/bin/activate && flask import-scodoc7-users
|
|||||||
# (ils ne sont d'ailleurs plus utilisés par ScoDoc 9)
|
# (ils ne sont d'ailleurs plus utilisés par ScoDoc 9)
|
||||||
for f in "$SCODOC_VAR_DIR"/config/depts/*.cfg
|
for f in "$SCODOC_VAR_DIR"/config/depts/*.cfg
|
||||||
do
|
do
|
||||||
dept=$(basename "${f%.*}")
|
dept=$(basename "${f%.*}") # le nom du dept peut-être en minuscules et/ou majuscules (geii, GEII...)
|
||||||
db_name=$(echo "SCO$dept" | tr "[:lower:]" "[:upper:]")
|
db_name=$(echo "SCO$dept" | tr "[:lower:]" "[:upper:]") # nom de BD toujours en majuscule
|
||||||
echo
|
echo
|
||||||
echo "----------------------------------------------"
|
echo "----------------------------------------------"
|
||||||
echo "| MIGRATION DU DEPARTEMENT $dept"
|
echo "| MIGRATION DU DEPARTEMENT $dept"
|
||||||
@ -192,6 +215,18 @@ fi
|
|||||||
# Précaution a priori inutile (import-scodoc7-dept efface les caches)
|
# Précaution a priori inutile (import-scodoc7-dept efface les caches)
|
||||||
systemctl restart redis
|
systemctl restart redis
|
||||||
|
|
||||||
|
# --- THE END
|
||||||
|
echo
|
||||||
|
echo "Migration terminée."
|
||||||
|
echo "Vérifiez le fichier de log /opt/scodoc-data/log/migration79.log"
|
||||||
|
echo "et:"
|
||||||
|
echo "- prévenez les utilisateurs dont le login aurait changé."
|
||||||
|
echo "- dans ScodoC, en tant qu'admin, vérifier la configuration et"
|
||||||
|
echo " notamment la fonction de calcul du bonus sport, dont le réglage"
|
||||||
|
echo " est différent en ScoDoc 9 (plus de fichier de configuration python,"
|
||||||
|
echo " passer par le formulaire de configuration.)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
# Commande listant les nom des departement en DB:
|
# Commande listant les nom des departement en DB:
|
||||||
# Liste des bases de données de département:
|
# Liste des bases de données de département:
|
||||||
|
@ -70,14 +70,6 @@ CONFIG.LOGO_HEADER_HEIGHT = 28 # taille verticale dans le document en millimetr
|
|||||||
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
|
||||||
#
|
|
||||||
from bonus_sport import *
|
|
||||||
|
|
||||||
CONFIG.compute_bonus = bonus_iutv
|
|
||||||
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------------- Capitalisation des UEs -------------
|
# ------------- Capitalisation des UEs -------------
|
||||||
# Deux écoles:
|
# Deux écoles:
|
||||||
|
@ -58,13 +58,6 @@ CONFIG = CFG()
|
|||||||
# CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
# CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
|
||||||
#
|
|
||||||
|
|
||||||
# CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
|
||||||
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------------- Capitalisation des UEs -------------
|
# ------------- Capitalisation des UEs -------------
|
||||||
# Deux écoles:
|
# Deux écoles:
|
||||||
|
Loading…
Reference in New Issue
Block a user