Compare commits
72 Commits
Author | SHA1 | Date |
---|---|---|
Emmanuel Viennet | 2e88e6f7ce | |
Jean-Marie Place | 432831140c | |
Emmanuel Viennet | 7372a953fa | |
Emmanuel Viennet | 72d5904c4c | |
Jean-Marie Place | db717826c8 | |
Emmanuel Viennet | 40db439904 | |
Emmanuel Viennet | fbdcf63c70 | |
Emmanuel Viennet | 6287376efb | |
Jean-Marie Place | e8e1d2f2bb | |
Emmanuel Viennet | 09d131a85d | |
Jean-Marie Place | 48ad4f3877 | |
Emmanuel Viennet | b2b325dda9 | |
Jean-Marie Place | 0d60da2675 | |
Jean-Marie Place | b6036c940b | |
Jean-Marie Place | 3d9f362daf | |
Emmanuel Viennet | 3d99b8c087 | |
Emmanuel Viennet | 76a6270740 | |
Emmanuel Viennet | bf0b2c66bd | |
Emmanuel Viennet | 06f66e6976 | |
IDK | 383fdb0e53 | |
IDK | 35d5d43eeb | |
Emmanuel Viennet | 27b8fee9b7 | |
Emmanuel Viennet | b7e5c12aa1 | |
Emmanuel Viennet | 0cb9d18344 | |
Emmanuel Viennet | 2c4ff46a3a | |
Jean-Marie Place | 845aeaba5f | |
Emmanuel Viennet | 6cd868b7a3 | |
Emmanuel Viennet | 80dd25ba02 | |
Emmanuel Viennet | 5db32a80ee | |
Emmanuel Viennet | 704bb2c170 | |
Emmanuel Viennet | f5dbbaa207 | |
Emmanuel Viennet | 56f935b2a8 | |
Emmanuel Viennet | 37e7667eeb | |
Emmanuel Viennet | 6a42846d2e | |
Emmanuel Viennet | 540623d3b9 | |
Emmanuel Viennet | c153c11606 | |
Emmanuel Viennet | 2306b48b53 | |
Emmanuel Viennet | 7012a3ff58 | |
Emmanuel Viennet | fc59018688 | |
Emmanuel Viennet | c0f5292db8 | |
Emmanuel Viennet | b0a77fba66 | |
Emmanuel Viennet | 31288efb73 | |
Emmanuel Viennet | 4b3ac58bc0 | |
Emmanuel Viennet | 8fedde52e7 | |
Emmanuel Viennet | 243a9b6fd9 | |
Emmanuel Viennet | 8c02c6ef7e | |
Emmanuel Viennet | eff9ae59bc | |
Emmanuel Viennet | 748caf8ada | |
Emmanuel Viennet | 9646452457 | |
Emmanuel Viennet | f435885315 | |
Emmanuel Viennet | 18b802130a | |
Emmanuel Viennet | f00a18aeb7 | |
Emmanuel Viennet | b8efe15c0a | |
Emmanuel Viennet | 40d98eae16 | |
Emmanuel Viennet | 2449d65957 | |
Emmanuel Viennet | 3b5b449a8a | |
Emmanuel Viennet | da4cea0316 | |
Emmanuel Viennet | 7e3ac9884c | |
Emmanuel Viennet | b17d664652 | |
Emmanuel Viennet | 79e43adbc3 | |
Emmanuel Viennet | 0252bf4df4 | |
Emmanuel Viennet | c3e3f45370 | |
Emmanuel Viennet | 97446272af | |
Emmanuel Viennet | 2b967ba34e | |
Emmanuel Viennet | 4aa073beb3 | |
Emmanuel Viennet | 84c72fcb50 | |
Emmanuel Viennet | d45f9e25cc | |
Emmanuel Viennet | a07571494c | |
Emmanuel Viennet | 294bc8f205 | |
Emmanuel Viennet | 424852c312 | |
Emmanuel Viennet | d93b5688ae | |
Emmanuel Viennet | 30f88dfd4f |
116
README.md
116
README.md
|
@ -21,19 +21,18 @@ ne soit visible des utilisateurs Web.
|
|||
**Work in Progress (WIP)**: développement en cours, certaines pages fonctionnent, d'autres pas:
|
||||
merci de signaler les erreurs.
|
||||
|
||||
### État actuel (23 juillet 21)
|
||||
### État actuel (30 juillet 21)
|
||||
|
||||
- serveur de développement fonctionnel (pas testé en mode "production" sous gunicorn+nginx).
|
||||
|
||||
- logs à revoir
|
||||
- logs à revoir (tropverbeux), dans `/opt/scodoc-data/log`
|
||||
|
||||
- pas d'import/export excel.
|
||||
|
||||
- pas de pages gestion utilisateurs.
|
||||
|
||||
**En cours:**
|
||||
|
||||
- tests, formulaires utilisateurs, logging.
|
||||
- nettoyage du code, finalisation tests et intégration.
|
||||
|
||||
|
||||
## Installation (sur Debian 10 / python3.7)
|
||||
|
@ -47,20 +46,20 @@ On peut installer à partir de zéro, ou sur une machine ayant déjà un ScoDoc
|
|||
|
||||
1. S'assurer que l'installation ScoDoc 7 est à jour
|
||||
|
||||
sudo su
|
||||
cd /opt/scodoc/Products/ScoDoc/config
|
||||
./upgrade.sh
|
||||
sudo su
|
||||
cd /opt/scodoc/Products/ScoDoc/config
|
||||
./upgrade.sh
|
||||
|
||||
2. Arrêter le service ScoDoc 7
|
||||
|
||||
systemctl stop scodoc7
|
||||
systemctl stop scodoc
|
||||
|
||||
S'assurer qu'il est bien stoppé (`ps auxw`, ...), sans qui la migration va échouer.
|
||||
|
||||
3. Renommer le répertoire de ScoDoc 7:
|
||||
|
||||
sudo su
|
||||
mv /opt/scodoc /opt/scodoc7
|
||||
sudo su
|
||||
mv /opt/scodoc /opt/scodoc7
|
||||
|
||||
Les données pourront être migrées après installation la nouvelle evrsion, voir plus loin.
|
||||
|
||||
|
@ -69,15 +68,15 @@ Sur un système Linux Debian 10, en tant que `root`:
|
|||
|
||||
- Charger la dernière release depuis https://scodoc.org/git/viennet/ScoDoc/releases
|
||||
|
||||
- Déplacer ou copier le fichier `scodoc-x.y.z.tgz` dans `/opt` et le décomprimer:
|
||||
- Déplacer ou copier le fichier `ScoDoc-x.y.z.tgz` dans `/opt` et le décomprimer:
|
||||
|
||||
sudo su
|
||||
cd /opt; tar xf - scodoc-x.y.z.tgz # remplacer x.y.z par votre version
|
||||
sudo su
|
||||
cd /opt; tar xf - ScoDoc-x.y.z.tgz # remplacer x.y.z par votre version
|
||||
|
||||
- Lancer le script d'installation:
|
||||
|
||||
cd /opt/scodoc/tools
|
||||
./install_debian10.sh
|
||||
cd /opt/scodoc/tools
|
||||
./install_debian10.sh
|
||||
|
||||
ce script crée un compte utilisateur "scodoc".
|
||||
|
||||
|
@ -93,18 +92,39 @@ via `sqlalchemy`.
|
|||
|
||||
Lancer le script:
|
||||
|
||||
su postgres
|
||||
sudo su
|
||||
cd /opt/scodoc/tools
|
||||
./create_database.sh
|
||||
./create_users_database.sh
|
||||
|
||||
Ce script crée une base nommée `SCO8USERS`, appartenant à l'utilisateur (role) postgres `scodoc`.
|
||||
Cet utilisateur est automatiquement créé si nécessaire.
|
||||
|
||||
### variables d'environnement
|
||||
Le serveur utilise des variables d'environnement donnant la configuration de base.
|
||||
Le plus simple est de les grouper dans un fichier `.env` (dans `/opt/scodoc/.env`)
|
||||
qui est lu automatiquement au démarrage:
|
||||
|
||||
# .env for ScoDoc _development_
|
||||
|
||||
FLASK_APP=scodoc.py
|
||||
FLASK_ENV=development
|
||||
|
||||
MAIL_SERVER=votre.serveur.de.mail.net # ou vide si pas de mail
|
||||
MAIL_PORT=25
|
||||
|
||||
SCODOC_ADMIN_MAIL="adresse.admin@toto.fr" # important: le mail de admin
|
||||
USERS_DATABASE_URI="postgresql://scodoc:le_mot_de_passe@localhost:5432/SCO8USERS"
|
||||
SECRET_KEY="CGGAJAKlh6789JJK?KNAb=" # une chaine aléatoire
|
||||
# comment out to use CDN:
|
||||
BOOTSTRAP_SERVE_LOCAL=1
|
||||
|
||||
### Initialisation de la base utilisateur par Flask
|
||||
|
||||
En tant qu'utilisateur `scodoc`:
|
||||
|
||||
su scodoc # si besoin
|
||||
cd /opt/scodoc
|
||||
source venv/bin/activate
|
||||
flask db init
|
||||
flask db migrate -m "users and roles tables"
|
||||
flask db upgrade
|
||||
|
@ -126,7 +146,8 @@ ou mieux, importer les utilisateurs de ScoDoc7 avec:
|
|||
|
||||
flask user-db-import-scodoc7
|
||||
|
||||
(la base `SCOUSERS` de ScoDoc7 n'est pas affectée, ScoDoc8 utilise une base séparée, nommée `SCO8USERS`).
|
||||
(on peut le faire plus tard avec le script de migration décrit plus bas)
|
||||
(Note: la base `SCOUSERS` de ScoDoc7 n'est pas affectée, ScoDoc8 utilise une base séparée, nommée `SCO8USERS`).
|
||||
|
||||
Pour créer un utilisateur "super admin", c'est à dire admin dans tous les départements:
|
||||
|
||||
|
@ -141,20 +162,31 @@ de votre installation ScoDoc 7 pour passer à ScoDoc 8 (*ne pas utiliser en prod
|
|||
1. Lancer le script de migration
|
||||
ScoDoc 8 doit avoir été installé comme expliqué plus haut.
|
||||
|
||||
sudo su
|
||||
cd /opt/scodoc/tools
|
||||
./migrate_from_scodoc7.sh
|
||||
sudo su
|
||||
cd /opt/scodoc/tools
|
||||
./migrate_from_scodoc7.sh
|
||||
|
||||
## Création d'un département
|
||||
|
||||
su scodoc # si besoin
|
||||
cd /opt/scodoc
|
||||
source venv/bin/activate
|
||||
flask sco-create-dept DEPT
|
||||
|
||||
où `DEPT` est le nom du département (un acronyme en majuscule, comme "RT", "GEA", ...).
|
||||
|
||||
### Suppression d'un département
|
||||
|
||||
su scodoc # si besoin
|
||||
cd /opt/scodoc
|
||||
source venv/bin/activate
|
||||
flask sco-delete-dept DEPT
|
||||
|
||||
## Lancement serveur (développement, sur VM Linux)
|
||||
|
||||
En tant qu'utilisateur `scodoc` (pour avoir accès aux bases départements de ScoDoc7):
|
||||
|
||||
1. Lancer memcached:
|
||||
|
||||
memcached
|
||||
|
||||
2. Dans un autre terminal, lancer le serveur:
|
||||
Dans un terminal, lancer le serveur:
|
||||
|
||||
export FLASK_APP=scodoc.py
|
||||
export FLASK_ENV=development
|
||||
|
@ -181,15 +213,39 @@ Principaux contenus:
|
|||
/opt/scodoc-data/photos # Photos des étudiants
|
||||
/opt/scodoc-data/archives # Archives: PV de jury, maquettes Apogée, fichiers étudiants
|
||||
|
||||
## Pour les développeurs
|
||||
|
||||
## Tests unitaires
|
||||
### Installation du code
|
||||
|
||||
Procéder comme indiquer au début, mais au lieu de técharger une *release*,
|
||||
partir d'un clone git et se placer sur la branche *ScoDoc8*:
|
||||
|
||||
sudo su
|
||||
cd /opt
|
||||
git clone https://scodoc.org/git/viennet/ScoDoc.git
|
||||
# (ou bien utiliser votre clone gitea so vous l'avez déjà créé !)
|
||||
mv ScoDoc scodoc # important !
|
||||
cd /opt/scodoc
|
||||
git checkout ScoDoc8
|
||||
|
||||
### Tests unitaires
|
||||
|
||||
Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
|
||||
scripts de tests:
|
||||
Lancer au préalable:
|
||||
|
||||
flask sco-delete-dept TEST00 && flask sco-create-dept TEST00
|
||||
|
||||
Puis dérouler les tests unitaires:
|
||||
|
||||
pytest tests/unit
|
||||
|
||||
# TODO
|
||||
Ou avec couverture (`pip install pytest-cov`)
|
||||
|
||||
pytest --cov=app --cov-report=term-missing --cov-branch tests/unit/*
|
||||
|
||||
## TODO
|
||||
|
||||
- page d'erreur ScoValueError
|
||||
- redirection pour authentification
|
||||
- import/export Excel
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -11,6 +12,7 @@ from flask import request
|
|||
from flask import Flask
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import render_template
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_login import LoginManager
|
||||
|
@ -33,7 +35,16 @@ mail = Mail()
|
|||
bootstrap = Bootstrap()
|
||||
moment = Moment()
|
||||
|
||||
cache = Cache(config={"CACHE_TYPE": "MemcachedCache"}) # XXX TODO: configuration file
|
||||
cache = Cache( # XXX TODO: configuration file
|
||||
config={
|
||||
# "CACHE_TYPE": "MemcachedCache"
|
||||
"CACHE_TYPE": "RedisCache"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def handle_sco_value_error(exc):
|
||||
return render_template("sco_value_error.html", exc=exc), 404
|
||||
|
||||
|
||||
def create_app(config_class=Config):
|
||||
|
@ -50,6 +61,8 @@ def create_app(config_class=Config):
|
|||
cache.init_app(app)
|
||||
sco_cache.CACHE = cache
|
||||
|
||||
app.register_error_handler(ScoValueError, handle_sco_value_error)
|
||||
|
||||
from app.auth import bp as auth_bp
|
||||
|
||||
app.register_blueprint(auth_bp, url_prefix="/auth")
|
||||
|
|
|
@ -66,17 +66,17 @@ class User(UserMixin, db.Model):
|
|||
assert admin_role
|
||||
self.add_role(admin_role, None)
|
||||
db.session.commit()
|
||||
current_app.logger.info("creating user with roles={}".format(self.roles))
|
||||
# current_app.logger.info("creating user with roles={}".format(self.roles))
|
||||
|
||||
def __repr__(self):
|
||||
return "<User {u.user_name} id={u.id} dept={u.dept}>".format(u=self)
|
||||
return f"<User {self.user_name} id={self.id} dept={self.dept}{' (inactive)' if not self.active else ''}>"
|
||||
|
||||
def __str__(self):
|
||||
return self.user_name
|
||||
|
||||
def set_password(self, password):
|
||||
"Set password"
|
||||
current_app.logger.info("set_password({})".format(self))
|
||||
current_app.logger.info(f"set_password({self})")
|
||||
if password:
|
||||
self.password_hash = generate_password_hash(password)
|
||||
else:
|
||||
|
@ -92,7 +92,7 @@ class User(UserMixin, db.Model):
|
|||
# Special case: user freshly migrated from ScoDoc7
|
||||
if scu.check_scodoc7_password(self.password_scodoc7, password):
|
||||
current_app.logger.warning(
|
||||
"migrating legacy ScoDoc7 password for {}".format(self)
|
||||
f"migrating legacy ScoDoc7 password for {self}"
|
||||
)
|
||||
self.set_password(password)
|
||||
self.password_scodoc7 = None
|
||||
|
@ -132,15 +132,15 @@ class User(UserMixin, db.Model):
|
|||
"date_created": self.date_created.isoformat() + "Z"
|
||||
if self.date_created
|
||||
else "",
|
||||
"dept": (self.dept or "").encode("utf-8"), # sco8
|
||||
"dept": (self.dept or ""), # sco8
|
||||
"id": self.id,
|
||||
"active": self.active,
|
||||
"status_txt": "actif" if self.active else "fermé",
|
||||
"last_seen": self.last_seen.isoformat() + "Z",
|
||||
"nom": (self.nom or "").encode("utf-8"), # sco8
|
||||
"prenom": (self.prenom or "").encode("utf-8"), # sco8
|
||||
"nom": (self.nom or ""), # sco8
|
||||
"prenom": (self.prenom or ""), # sco8
|
||||
"roles_string": self.get_roles_string(), # eg "Ens_RT, Ens_Info"
|
||||
"user_name": self.user_name.encode("utf-8"), # sco8
|
||||
"user_name": self.user_name, # sco8
|
||||
# Les champs calculés:
|
||||
"nom_fmt": self.get_nom_fmt(),
|
||||
"prenom_fmt": self.get_prenom_fmt(),
|
||||
|
@ -155,9 +155,9 @@ class User(UserMixin, db.Model):
|
|||
|
||||
def from_dict(self, data, new_user=False):
|
||||
"""Set users' attributes from given dict values.
|
||||
Roles must be encodes as "roles_string", like "Ens_RT, Secr_CJ"
|
||||
Roles must be encoded as "roles_string", like "Ens_RT, Secr_CJ"
|
||||
"""
|
||||
for field in ["nom", "prenom", "dept", "status", "email"]:
|
||||
for field in ["nom", "prenom", "dept", "active", "email", "date_expiration"]:
|
||||
if field in data:
|
||||
setattr(self, field, data[field])
|
||||
if new_user:
|
||||
|
|
|
@ -4,6 +4,7 @@ auth.routes.py
|
|||
"""
|
||||
|
||||
from flask import render_template, redirect, url_for, current_app, flash, request
|
||||
from flask_login.utils import login_required
|
||||
from werkzeug.urls import url_parse
|
||||
from flask_login import login_user, logout_user, current_user
|
||||
|
||||
|
|
|
@ -64,12 +64,12 @@ class ZRequest(object):
|
|||
elif request.method == "GET":
|
||||
self.form = {}
|
||||
for k in request.args:
|
||||
current_app.logger.debug("%s\t%s" % (k, request.args.getlist(k)))
|
||||
# current_app.logger.debug("%s\t%s" % (k, request.args.getlist(k)))
|
||||
if k.endswith(":list"):
|
||||
self.form[k[:-5]] = request.args.getlist(k)
|
||||
else:
|
||||
self.form[k] = request.args[k]
|
||||
current_app.logger.info("ZRequest.form=%s" % str(self.form))
|
||||
# current_app.logger.info("ZRequest.form=%s" % str(self.form))
|
||||
self.RESPONSE = ZResponse()
|
||||
|
||||
def __str__(self):
|
||||
|
@ -91,7 +91,7 @@ class ZResponse(object):
|
|||
self.headers = {}
|
||||
|
||||
def redirect(self, url):
|
||||
current_app.logger.debug("ZResponse redirect to:" + str(url))
|
||||
# current_app.logger.debug("ZResponse redirect to:" + str(url))
|
||||
return flask.redirect(url) # http 302
|
||||
|
||||
def setHeader(self, header, value):
|
||||
|
@ -108,11 +108,12 @@ def permission_required(permission):
|
|||
# current_app.logger.info(
|
||||
# "permission_required: %s in %s" % (permission, g.scodoc_dept)
|
||||
# )
|
||||
if not current_user.has_permission(permission, g.scodoc_dept):
|
||||
scodoc_dept = getattr(g, "scodoc_dept", None)
|
||||
if not current_user.has_permission(permission, scodoc_dept):
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
return login_required(decorated_function)
|
||||
|
||||
return decorator
|
||||
|
||||
|
@ -163,9 +164,8 @@ def scodoc7func(context):
|
|||
req_args = REQUEST.form # args from query string (get) or form (post)
|
||||
# --- Add positional arguments
|
||||
pos_arg_values = []
|
||||
# PY3 à remplacer par inspect.getfullargspec en py3: TODO
|
||||
argspec = inspect.getargspec(func)
|
||||
current_app.logger.info("argspec=%s" % str(argspec))
|
||||
argspec = inspect.getfullargspec(func)
|
||||
# current_app.logger.info("argspec=%s" % str(argspec))
|
||||
nb_default_args = len(argspec.defaults) if argspec.defaults else 0
|
||||
if nb_default_args:
|
||||
arg_names = argspec.args[:-nb_default_args]
|
||||
|
@ -178,8 +178,8 @@ def scodoc7func(context):
|
|||
pos_arg_values.append(context)
|
||||
else:
|
||||
pos_arg_values.append(req_args[arg_name])
|
||||
current_app.logger.info("pos_arg_values=%s" % pos_arg_values)
|
||||
current_app.logger.info("req_args=%s" % req_args)
|
||||
# current_app.logger.info("pos_arg_values=%s" % pos_arg_values)
|
||||
# current_app.logger.info("req_args=%s" % req_args)
|
||||
# Add keyword arguments
|
||||
if nb_default_args:
|
||||
for arg_name in argspec.args[-nb_default_args:]:
|
||||
|
@ -188,10 +188,10 @@ def scodoc7func(context):
|
|||
elif arg_name in req_args:
|
||||
# set argument kw optionnel
|
||||
kwargs[arg_name] = req_args[arg_name]
|
||||
current_app.logger.info(
|
||||
"scodoc7func_decorator: top_level=%s, pos_arg_values=%s, kwargs=%s"
|
||||
% (top_level, pos_arg_values, kwargs)
|
||||
)
|
||||
# current_app.logger.info(
|
||||
# "scodoc7func_decorator: top_level=%s, pos_arg_values=%s, kwargs=%s"
|
||||
# % (top_level, pos_arg_values, kwargs)
|
||||
# )
|
||||
value = func(*pos_arg_values, **kwargs)
|
||||
|
||||
if not top_level:
|
||||
|
|
|
@ -757,6 +757,6 @@ def tf_error_message(msg):
|
|||
if isinstance(msg, str):
|
||||
msg = [msg]
|
||||
return (
|
||||
'<ul class="tf-msg"><li class="tf-msg">%s</li></ul>'
|
||||
% '</li><li class="tf-msg">'.join(msg)
|
||||
'<ul class="tf-msg"><li class="tf-msg error-message">%s</li></ul>'
|
||||
% '</li><li class="tf-msg tf-msg error-message">'.join(msg)
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "8.0.0"
|
||||
SCOVERSION = "8.0.1"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
@ -18,7 +18,7 @@ SCONEWS = """
|
|||
<h4>Année 2020</h4>
|
||||
<ul>
|
||||
<li>Corrections d'erreurs, améliorations saisie absences et affichage bulletins</li>
|
||||
<li>Nouveau site <a href="https://scodoc.org">scodoc.org</a> pour la documentation</li>
|
||||
<li>Nouveau site <a href="https://scodoc.org" target="_blank" rel="noopener noreferrer">scodoc.org</a> pour la documentation</li>
|
||||
<li>Enregistrement de semestres extérieurs</li>
|
||||
<li>Améliorations PV de Jury</li>
|
||||
<li>Contributions J.-M. Place: aide au diagnostic problèmes export Apogée
|
||||
|
@ -128,7 +128,6 @@ SCONEWS = """
|
|||
|
||||
<h4>Janvier 2010</h4>
|
||||
<ul>
|
||||
<li>Suivez l'actualité du développement sur Twitter: <a href="https://twitter.com/ScoDoc">@ScoDoc</a></li>
|
||||
<li>Nouveau menu "Groupes" pour faciliter la prise en main</li>
|
||||
<li>Possibilité de définir des règles ad hoc de calcul des moyennes de modules (formules)</li>
|
||||
<li>Possibilité d'inclure des images (logos) dans les bulletins PDF</li>
|
||||
|
|
|
@ -78,6 +78,7 @@ class DEFAULT_TABLE_PREFERENCES(object):
|
|||
"SCOLAR_FONT": "Helvetica", # used for PDF, overriden by preferences argument
|
||||
"SCOLAR_FONT_SIZE": 10,
|
||||
"SCOLAR_FONT_SIZE_FOOT": 6,
|
||||
"bul_pdf_with_background": False,
|
||||
}
|
||||
|
||||
def __getitem__(self, k):
|
||||
|
@ -278,7 +279,7 @@ class GenTable(object):
|
|||
"""
|
||||
if format == "html":
|
||||
return self.html()
|
||||
elif format == "xls":
|
||||
elif format == "xls" or format == "xlsx":
|
||||
return self.excel()
|
||||
elif format == "text" or format == "csv":
|
||||
return self.text()
|
||||
|
@ -464,22 +465,24 @@ class GenTable(object):
|
|||
return "\n".join(H)
|
||||
|
||||
def excel(self, wb=None):
|
||||
"Simple Excel representation of the table"
|
||||
L = sco_excel.ScoExcelSheet(sheet_name=self.xls_sheet_name)
|
||||
style_bold = sco_excel.Excel_MakeStyle(bold=True)
|
||||
|
||||
L.cells += self.xls_before_table
|
||||
L.set_style(style_bold, li=len(L.cells))
|
||||
L.append(self.get_titles_list())
|
||||
L.cells += [[x for x in line] for line in self.get_data_list()]
|
||||
"""Simple Excel representation of the table"""
|
||||
ses = sco_excel.ScoExcelSheet(sheet_name=self.xls_sheet_name, wb=wb)
|
||||
ses.rows += self.xls_before_table
|
||||
style_bold = sco_excel.excel_make_style(bold=True)
|
||||
style_base = sco_excel.excel_make_style()
|
||||
ses.append_row(ses.make_row(self.get_titles_list(), style_bold))
|
||||
for line in self.get_data_list():
|
||||
ses.append_row(ses.make_row(line, style_base))
|
||||
if self.caption:
|
||||
L.append([]) # empty line
|
||||
L.append([self.caption])
|
||||
ses.append_blank_row() # empty line
|
||||
ses.append_single_cell_row(self.caption, style_base)
|
||||
if self.origin:
|
||||
L.append([]) # empty line
|
||||
L.append([self.origin])
|
||||
|
||||
return L.gen_workbook(wb=wb)
|
||||
ses.append_blank_row() # empty line
|
||||
ses.append_single_cell_row(self.origin, style_base)
|
||||
if wb is None:
|
||||
return ses.generate_standalone()
|
||||
else:
|
||||
ses.generate_embeded()
|
||||
|
||||
def text(self):
|
||||
"raw text representation of the table"
|
||||
|
@ -597,7 +600,7 @@ class GenTable(object):
|
|||
v = str(v)
|
||||
r[cid] = v
|
||||
d.append(r)
|
||||
return json.dumps(d, encoding=scu.SCO_ENCODING)
|
||||
return json.dumps(d)
|
||||
|
||||
def make_page(
|
||||
self,
|
||||
|
@ -627,8 +630,6 @@ class GenTable(object):
|
|||
H.append(
|
||||
self.html_header
|
||||
or html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=page_title,
|
||||
javascripts=javascripts,
|
||||
init_qtip=init_qtip,
|
||||
|
@ -638,7 +639,7 @@ class GenTable(object):
|
|||
H.append(html_title)
|
||||
H.append(self.html())
|
||||
if with_html_headers:
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
elif format == "pdf":
|
||||
objects = self.pdf()
|
||||
|
@ -649,10 +650,12 @@ class GenTable(object):
|
|||
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
||||
else:
|
||||
return doc
|
||||
elif format == "xls":
|
||||
elif format == "xls" or format == "xlsx":
|
||||
xls = self.excel()
|
||||
if publish:
|
||||
return sco_excel.sendExcelFile(REQUEST, xls, filename + ".xls")
|
||||
return sco_excel.send_excel_file(
|
||||
REQUEST, xls, filename + scu.XLSX_SUFFIX
|
||||
)
|
||||
else:
|
||||
return xls
|
||||
elif format == "text":
|
||||
|
@ -700,7 +703,7 @@ class SeqGenTable(object):
|
|||
# ----- Exemple d'utilisation minimal.
|
||||
if __name__ == "__main__":
|
||||
T = GenTable(
|
||||
rows=[{"nom": "Toto", "age": 26}, {"nom": "Titi", "age": 21}],
|
||||
rows=[{"nom": "Hélène", "age": 26}, {"nom": "Titi&çà§", "age": 21}],
|
||||
columns_ids=("nom", "age"),
|
||||
)
|
||||
print("--- HTML:")
|
||||
|
@ -709,3 +712,24 @@ if __name__ == "__main__":
|
|||
print(T.gen(format="xml"))
|
||||
print("\n--- JSON:")
|
||||
print(T.gen(format="json"))
|
||||
# Test pdf:
|
||||
import io
|
||||
from reportlab.platypus import KeepInFrame
|
||||
from app.scodoc import sco_preferences, sco_pdf
|
||||
|
||||
preferences = sco_preferences.SemPreferences()
|
||||
T.preferences = preferences
|
||||
objects = T.gen(format="pdf")
|
||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||
doc = io.BytesIO()
|
||||
document = sco_pdf.BaseDocTemplate(doc)
|
||||
document.addPageTemplates(
|
||||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
data = doc.getvalue()
|
||||
open("/tmp/gen_table.pdf", "wb").write(data)
|
||||
p = T.make_page(None, format="pdf", REQUEST=None)
|
||||
open("toto.pdf", "wb").write(p)
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
"""HTML Header/Footer for ScoDoc pages
|
||||
"""
|
||||
|
||||
import cgi
|
||||
import html
|
||||
|
||||
from flask import g
|
||||
from flask import request
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -124,9 +126,9 @@ _HTML_BEGIN = """<?xml version="1.0" encoding="%(encoding)s"?>
|
|||
"""
|
||||
|
||||
|
||||
def scodoc_top_html_header(context, REQUEST, page_title="ScoDoc"):
|
||||
def scodoc_top_html_header(page_title="ScoDoc: bienvenue"):
|
||||
H = [
|
||||
_HTML_BEGIN % {"page_title": "ScoDoc: bienvenue", "encoding": scu.SCO_ENCODING},
|
||||
_HTML_BEGIN % {"page_title": page_title, "encoding": scu.SCO_ENCODING},
|
||||
_TOP_LEVEL_CSS,
|
||||
"""</head><body class="gtrcontent" id="gtrcontent">""",
|
||||
scu.CUSTOM_HTML_HEADER_CNX,
|
||||
|
@ -136,10 +138,7 @@ def scodoc_top_html_header(context, REQUEST, page_title="ScoDoc"):
|
|||
|
||||
# Header:
|
||||
def sco_header(
|
||||
context,
|
||||
REQUEST=None,
|
||||
# optional args
|
||||
container=None, # objet qui a lancé la demande
|
||||
page_title="", # page title
|
||||
no_side_bar=False, # hide sidebar
|
||||
cssstyles=[], # additionals CSS sheets
|
||||
|
@ -158,17 +157,14 @@ def sco_header(
|
|||
"Main HTML page header for ScoDoc"
|
||||
from app.scodoc.sco_formsemestre_status import formsemestre_page_title
|
||||
|
||||
# context est une instance de ZScolar. container est une instance qui "acquiert" ZScolar
|
||||
if container:
|
||||
context = container # je pense que cela suffit pour ce qu'on veut.
|
||||
context = None # XXX TODO à enlever #context
|
||||
|
||||
# Add a HTTP header (can be used by Apache to log requests)
|
||||
if REQUEST.AUTHENTICATED_USER:
|
||||
REQUEST.RESPONSE.setHeader("X-ScoDoc-User", str(REQUEST.AUTHENTICATED_USER))
|
||||
|
||||
# Get more parameters from REQUEST
|
||||
if not head_message and "head_message" in REQUEST.form:
|
||||
head_message = REQUEST.form["head_message"]
|
||||
# Get head message from http request:
|
||||
if not head_message:
|
||||
if request.method == "POST":
|
||||
head_message = request.form.get("head_message", "")
|
||||
elif request.method == "GET":
|
||||
head_message = request.args.get("head_message", "")
|
||||
|
||||
params = {
|
||||
"page_title": page_title or VERSION.SCONAME,
|
||||
|
@ -176,7 +172,7 @@ def sco_header(
|
|||
"ScoURL": scu.ScoURL(),
|
||||
"encoding": scu.SCO_ENCODING,
|
||||
"titrebandeau_mkup": "<td>" + titrebandeau + "</td>",
|
||||
"authuser": str(REQUEST.AUTHENTICATED_USER),
|
||||
"authuser": current_user.user_name,
|
||||
}
|
||||
if bodyOnLoad:
|
||||
params["bodyOnLoad_mkup"] = """onload="%s" """ % bodyOnLoad
|
||||
|
@ -308,11 +304,11 @@ def sco_header(
|
|||
H.append(scu.CUSTOM_HTML_HEADER)
|
||||
#
|
||||
if not no_side_bar:
|
||||
H.append(html_sidebar.sidebar(context, REQUEST))
|
||||
H.append(html_sidebar.sidebar())
|
||||
H.append("""<div class="gtrcontent" id="gtrcontent">""")
|
||||
#
|
||||
# Barre menu semestre:
|
||||
H.append(formsemestre_page_title(context, REQUEST))
|
||||
H.append(formsemestre_page_title(context))
|
||||
|
||||
# Avertissement si mot de passe à changer
|
||||
if user_check:
|
||||
|
@ -327,7 +323,7 @@ def sco_header(
|
|||
)
|
||||
#
|
||||
if head_message:
|
||||
H.append('<div class="head_message">' + cgi.escape(head_message) + "</div>")
|
||||
H.append('<div class="head_message">' + html.escape(head_message) + "</div>")
|
||||
#
|
||||
# div pour affichage messages temporaires
|
||||
H.append('<div id="sco_msg" class="head_message"></div>')
|
||||
|
@ -335,7 +331,7 @@ def sco_header(
|
|||
return "".join(H)
|
||||
|
||||
|
||||
def sco_footer(context, REQUEST=None):
|
||||
def sco_footer():
|
||||
"""Main HTMl pages footer"""
|
||||
return (
|
||||
"""</div><!-- /gtrcontent -->""" + scu.CUSTOM_HTML_FOOTER + """</body></html>"""
|
||||
|
@ -355,9 +351,7 @@ def html_sem_header(
|
|||
"Titre d'une page semestre avec lien vers tableau de bord"
|
||||
# sem now unused and thus optional...
|
||||
if with_page_header:
|
||||
h = sco_header(
|
||||
context, REQUEST, page_title="%s" % (page_title or title), **args
|
||||
)
|
||||
h = sco_header(page_title="%s" % (page_title or title), **args)
|
||||
else:
|
||||
h = ""
|
||||
if with_h2:
|
||||
|
|
|
@ -28,54 +28,56 @@
|
|||
"""
|
||||
Génération de la "sidebar" (marge gauche des pages HTML)
|
||||
"""
|
||||
from flask import url_for, g
|
||||
from flask import url_for
|
||||
from flask import g
|
||||
from flask import request
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
|
||||
|
||||
def sidebar_common(context, REQUEST=None):
|
||||
def sidebar_common():
|
||||
"partie commune à toutes les sidebar"
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
params = {
|
||||
"ScoURL": scu.ScoURL(),
|
||||
"UsersURL": scu.UsersURL(),
|
||||
"NotesURL": scu.NotesURL(),
|
||||
"AbsencesURL": scu.AbsencesURL(),
|
||||
"LogoutURL": url_for("auth.logout"),
|
||||
"authuser": str(authuser),
|
||||
"authuser": current_user.user_name,
|
||||
}
|
||||
H = [
|
||||
'<a class="scodoc_title" href="about">ScoDoc 8</a>',
|
||||
'<div id="authuser"><a id="authuserlink" href="%(ScoURL)s/Users/user_info_page">%(authuser)s</a><br/><a id="deconnectlink" href="%(LogoutURL)s">déconnexion</a></div>'
|
||||
% params,
|
||||
sidebar_dept(context, REQUEST),
|
||||
"""<h2 class="insidebar">Scolarité</h2>
|
||||
<a href="%(ScoURL)s" class="sidebar">Semestres</a> <br/>
|
||||
<a href="%(NotesURL)s" class="sidebar">Programmes</a> <br/>
|
||||
<a href="%(AbsencesURL)s" class="sidebar">Absences</a> <br/>
|
||||
"""
|
||||
% params,
|
||||
f"""<a class="scodoc_title" href="about">ScoDoc 8</a>
|
||||
<div id="authuser"><a id="authuserlink" href="{
|
||||
url_for("users.user_info_page", scodoc_dept=g.scodoc_dept, user_name=current_user.user_name)
|
||||
}">{current_user.user_name}</a>
|
||||
<br/><a id="deconnectlink" href="{url_for("auth.logout")}">déconnexion</a>
|
||||
</div>
|
||||
{sidebar_dept()}
|
||||
<h2 class="insidebar">Scolarité</h2>
|
||||
<a href="{scu.ScoURL()}" class="sidebar">Semestres</a> <br/>
|
||||
<a href="{scu.NotesURL()}" class="sidebar">Programmes</a> <br/>
|
||||
<a href="{scu.AbsencesURL()}" class="sidebar">Absences</a> <br/>
|
||||
"""
|
||||
]
|
||||
|
||||
if authuser.has_permission(Permission.ScoUsersAdmin) or authuser.has_permission(
|
||||
Permission.ScoUsersView
|
||||
):
|
||||
if current_user.has_permission(
|
||||
Permission.ScoUsersAdmin
|
||||
) or current_user.has_permission(Permission.ScoUsersView):
|
||||
H.append(
|
||||
"""<a href="%(UsersURL)s" class="sidebar">Utilisateurs</a> <br/>""" % params
|
||||
f"""<a href="{scu.UsersURL()}" class="sidebar">Utilisateurs</a> <br/>"""
|
||||
)
|
||||
|
||||
if authuser.has_permission(Permission.ScoChangePreferences):
|
||||
if current_user.has_permission(Permission.ScoChangePreferences):
|
||||
H.append(
|
||||
"""<a href="%(ScoURL)s/edit_preferences" class="sidebar">Paramétrage</a> <br/>"""
|
||||
% params
|
||||
f"""<a href="{url_for("scolar.edit_preferences", scodoc_dept=g.scodoc_dept)}" class="sidebar">Paramétrage</a> <br/>"""
|
||||
)
|
||||
|
||||
return "".join(H)
|
||||
|
||||
|
||||
def sidebar(context, REQUEST=None):
|
||||
def sidebar():
|
||||
"Main HTML page sidebar"
|
||||
# rewritten from legacy DTML code
|
||||
from app.scodoc import sco_abs
|
||||
|
@ -86,7 +88,7 @@ def sidebar(context, REQUEST=None):
|
|||
"SCO_USER_MANUAL": scu.SCO_USER_MANUAL,
|
||||
}
|
||||
|
||||
H = ['<div class="sidebar">', sidebar_common(context, REQUEST)]
|
||||
H = ['<div class="sidebar">', sidebar_common()]
|
||||
|
||||
H.append(
|
||||
"""<div class="box-chercheetud">Chercher étudiant:<br/>
|
||||
|
@ -97,9 +99,14 @@ def sidebar(context, REQUEST=None):
|
|||
"""
|
||||
% params
|
||||
)
|
||||
# ---- s'il y a un etudiant selectionné:
|
||||
if "etudid" in REQUEST.form:
|
||||
etudid = REQUEST.form["etudid"]
|
||||
# ---- Il y-a-t-il un etudiant selectionné ?
|
||||
etudid = None
|
||||
if request.method == "GET":
|
||||
etudid = request.args.get("etudid", None)
|
||||
elif request.method == "POST":
|
||||
etudid = request.form.get("etudid", None)
|
||||
|
||||
if etudid:
|
||||
etud = sco_etud.get_etud_info(filled=1, etudid=etudid)[0]
|
||||
params.update(etud)
|
||||
params["fiche_url"] = url_for(
|
||||
|
@ -126,7 +133,7 @@ def sidebar(context, REQUEST=None):
|
|||
)
|
||||
|
||||
H.append("<ul>")
|
||||
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoAbsChange):
|
||||
if current_user.has_permission(Permission.ScoAbsChange):
|
||||
H.append(
|
||||
"""
|
||||
<li> <a href="%(ScoURL)s/Absences/SignaleAbsenceEtud?etudid=%(etudid)s">Ajouter</a></li>
|
||||
|
@ -135,7 +142,7 @@ def sidebar(context, REQUEST=None):
|
|||
"""
|
||||
% params
|
||||
)
|
||||
if sco_preferences.get_preference(context, "handle_billets_abs"):
|
||||
if sco_preferences.get_preference("handle_billets_abs"):
|
||||
H.append(
|
||||
"""<li> <a href="%(ScoURL)s/Absences/listeBilletsEtud?etudid=%(etudid)s">Billets</a></li>"""
|
||||
% params
|
||||
|
@ -168,27 +175,17 @@ def sidebar(context, REQUEST=None):
|
|||
return "".join(H)
|
||||
|
||||
|
||||
def sidebar_dept(context, REQUEST=None):
|
||||
def sidebar_dept():
|
||||
"""Partie supérieure de la marge de gauche"""
|
||||
infos = {
|
||||
"BASE0": REQUEST.BASE0,
|
||||
"DeptIntranetTitle": sco_preferences.get_preference(
|
||||
context, "DeptIntranetTitle"
|
||||
),
|
||||
"DeptIntranetURL": sco_preferences.get_preference(context, "DeptIntranetURL"),
|
||||
"DeptName": sco_preferences.get_preference(context, "DeptName"),
|
||||
"ScoURL": scu.ScoURL(),
|
||||
}
|
||||
|
||||
H = [
|
||||
"""<h2 class="insidebar">Dépt. %(DeptName)s</h2>
|
||||
<a href="%(BASE0)s" class="sidebar">Accueil</a> <br/> """
|
||||
% infos
|
||||
f"""<h2 class="insidebar">Dépt. {sco_preferences.get_preference("DeptName")}</h2>
|
||||
<a href="{url_for("scodoc.index")}" class="sidebar">Accueil</a> <br/> """
|
||||
]
|
||||
if infos["DeptIntranetURL"]:
|
||||
dept_intranet_url = sco_preferences.get_preference("DeptIntranetURL")
|
||||
if dept_intranet_url:
|
||||
H.append(
|
||||
'<a href="%(DeptIntranetURL)s" class="sidebar">%(DeptIntranetTitle)s</a> <br/>'
|
||||
% infos
|
||||
f"""<a href="{dept_intranet_url}" class="sidebar">{
|
||||
sco_preferences.get_preference("DeptIntranetTitle")}</a> <br/>"""
|
||||
)
|
||||
# Entreprises pas encore supporté en ScoDoc8
|
||||
# H.append(
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import re
|
||||
import inspect
|
||||
import time
|
||||
import traceback
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
from flask import current_app
|
||||
|
||||
from flask import g, current_app
|
||||
|
||||
"""Simple & stupid file logguer, used only to debug
|
||||
(logging to SQL is done in scolog)
|
||||
|
@ -18,7 +17,7 @@ from flask import current_app
|
|||
LOG_FILENAME = "notes.log" # empty to disable logging
|
||||
DEFAULT_LOG_DIR = "/tmp" # clients should call set_log_directory to change this
|
||||
|
||||
ALARM_DESTINATION = "emmanuel.viennet@univ-paris13.fr" # XXX a mettre en preference
|
||||
ALARM_DESTINATION = "emmanuel.viennet@gmail.com" # XXX a mettre en preference
|
||||
|
||||
|
||||
class _logguer(object):
|
||||
|
@ -46,7 +45,11 @@ class _logguer(object):
|
|||
if not self.file:
|
||||
self._open()
|
||||
if self.file:
|
||||
dept = retreive_dept()
|
||||
try:
|
||||
dept = getattr(g, "scodoc_dept", "")
|
||||
except RuntimeError:
|
||||
# Flask Working outside of application context.
|
||||
dept = ""
|
||||
if dept:
|
||||
dept = " (%s)" % dept
|
||||
msg = dept + " " + msg
|
||||
|
@ -60,42 +63,6 @@ class _logguer(object):
|
|||
log = _logguer()
|
||||
|
||||
|
||||
def retreive_request(skip=0):
|
||||
"""Try to retreive a REQUEST variable in caller stack.
|
||||
This is a hack, used only in log functions.
|
||||
"""
|
||||
|
||||
def search(frame):
|
||||
if "REQUEST" in frame.f_locals:
|
||||
return frame.f_locals["REQUEST"]
|
||||
if frame.f_back:
|
||||
return search(frame.f_back)
|
||||
else:
|
||||
return None
|
||||
|
||||
frame = inspect.currentframe()
|
||||
if frame: # not supported by all pythons
|
||||
startframe = frame
|
||||
while skip and startframe.f_back:
|
||||
startframe = startframe.f_back
|
||||
return search(startframe)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def retreive_dept():
|
||||
"""Try to retreive departement (from REQUEST URL)"""
|
||||
REQUEST = retreive_request()
|
||||
if not REQUEST:
|
||||
return ""
|
||||
try:
|
||||
url = REQUEST.URL
|
||||
m = re.match(r"^.*ScoDoc/(\w+).*$", url)
|
||||
return m.group(1)
|
||||
except:
|
||||
return ""
|
||||
|
||||
|
||||
# Alarms by email:
|
||||
def sendAlarm(context, subj, txt):
|
||||
from . import sco_utils
|
||||
|
@ -105,7 +72,7 @@ def sendAlarm(context, subj, txt):
|
|||
msg = MIMEMultipart()
|
||||
subj = Header(subj, sco_utils.SCO_ENCODING)
|
||||
msg["Subject"] = subj
|
||||
msg["From"] = sco_preferences.get_preference(context, "email_from_addr")
|
||||
msg["From"] = sco_preferences.get_preference("email_from_addr")
|
||||
msg["To"] = ALARM_DESTINATION
|
||||
msg.epilogue = ""
|
||||
txt = MIMEText(txt, "plain", sco_utils.SCO_ENCODING)
|
||||
|
|
|
@ -131,7 +131,6 @@ def comp_etud_sum_coef_modules_ue(context, formsemestre_id, etudid, ue_id):
|
|||
(nécessaire pour éviter appels récursifs de nt, qui peuvent boucler)
|
||||
"""
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT mod.coefficient
|
||||
FROM notes_modules mod, notes_moduleimpl mi, notes_moduleimpl_inscription ins
|
||||
WHERE mod.module_id = mi.module_id
|
||||
|
@ -188,7 +187,7 @@ class NotesTable(object):
|
|||
self._uecoef = {} # { ue_id : coef } cache coef manuels ue cap
|
||||
self._evaluations_etats = None # liste des evaluations avec état
|
||||
self.use_ue_coefs = sco_preferences.get_preference(
|
||||
context, "use_ue_coefs", formsemestre_id
|
||||
"use_ue_coefs", formsemestre_id
|
||||
)
|
||||
# Infos sur les etudiants
|
||||
self.inscrlist = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||
|
@ -1303,7 +1302,7 @@ class NotesTable(object):
|
|||
"""[ {...evaluation et son etat...} ]"""
|
||||
if self._evaluations_etats is None:
|
||||
self._evaluations_etats = sco_evaluations.do_evaluation_list_in_sem(
|
||||
self.context, self.formsemestre_id
|
||||
self.formsemestre_id
|
||||
)
|
||||
|
||||
return self._evaluations_etats
|
||||
|
|
|
@ -33,10 +33,11 @@ def unquote(s):
|
|||
return s.replace("&", "&")
|
||||
|
||||
|
||||
def open_dept_connection():
|
||||
"""Open a connection to the current dept db"""
|
||||
# log("open_dept_connection to " + scu.get_db_cnx_string())
|
||||
return psycopg2.connect(scu.get_db_cnx_string())
|
||||
def open_dept_connection(scodoc_dept=None):
|
||||
"""Open a connection to the current dept db (g.scodoc_dept)
|
||||
or to the argument scodoc_dept
|
||||
"""
|
||||
return psycopg2.connect(scu.get_db_cnx_string(scodoc_dept))
|
||||
|
||||
|
||||
def close_dept_connection():
|
||||
|
@ -46,7 +47,16 @@ def close_dept_connection():
|
|||
g.db_conn.close()
|
||||
|
||||
|
||||
# Essai bien plus simple pour Flask:
|
||||
def set_sco_dept(scodoc_dept):
|
||||
"""Set "context" to given dept
|
||||
open db connection
|
||||
"""
|
||||
g.scodoc_dept = scodoc_dept
|
||||
if hasattr(g, "db_conn"):
|
||||
close_dept_connection()
|
||||
g.db_conn = open_dept_connection()
|
||||
|
||||
|
||||
def GetDBConnexion(autocommit=True): # on n'utilise plus autocommit
|
||||
return g.db_conn
|
||||
|
||||
|
@ -68,7 +78,7 @@ class ScoDocCursor(psycopg2.extensions.cursor):
|
|||
return {}
|
||||
|
||||
|
||||
def SimpleQuery(context, query, args, cursor=None):
|
||||
def SimpleQuery(query, args, cursor=None):
|
||||
if not cursor:
|
||||
cnx = GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
|
@ -77,8 +87,8 @@ def SimpleQuery(context, query, args, cursor=None):
|
|||
return cursor
|
||||
|
||||
|
||||
def SimpleDictFetch(context, query, args, cursor=None):
|
||||
cursor = SimpleQuery(context, query, args, cursor=cursor)
|
||||
def SimpleDictFetch(query, args, cursor=None):
|
||||
cursor = SimpleQuery(query, args, cursor=cursor)
|
||||
return cursor.dictfetchall()
|
||||
|
||||
|
||||
|
@ -110,7 +120,7 @@ def DBInsertDict(cnx, table, vals, commit=0, convert_empty_to_nulls=1):
|
|||
cnx.commit() # get rid of this transaction
|
||||
raise # and re-raise exception
|
||||
if commit:
|
||||
log("DBInsertDict: commit (requested)")
|
||||
# log("DBInsertDict: commit (requested)")
|
||||
cnx.commit()
|
||||
return oid
|
||||
|
||||
|
@ -202,7 +212,6 @@ def DBSelectArgs(
|
|||
+ limit
|
||||
+ offset
|
||||
)
|
||||
# open('/tmp/select.log','a').write( req % vals + '\n' )
|
||||
try:
|
||||
cursor.execute(req, vals)
|
||||
except:
|
||||
|
@ -249,9 +258,6 @@ def DBDelete(cnx, table, colid, val, commit=False):
|
|||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# REQLOG = open('/tmp/req.log', 'w') # DEBUG
|
||||
# REQN = 0
|
||||
|
||||
|
||||
class EditableTable(object):
|
||||
"""--- generic class: SQL table with create/edit/list/delete"""
|
||||
|
@ -266,7 +272,6 @@ class EditableTable(object):
|
|||
input_formators={},
|
||||
aux_tables=[],
|
||||
convert_null_outputs_to_empty=True,
|
||||
callback_on_write=None,
|
||||
allow_set_id=False,
|
||||
html_quote=True,
|
||||
fields_creators={}, # { field : [ sql_command_to_create_it ] }
|
||||
|
@ -280,16 +285,13 @@ class EditableTable(object):
|
|||
self.output_formators = output_formators
|
||||
self.input_formators = input_formators
|
||||
self.convert_null_outputs_to_empty = convert_null_outputs_to_empty
|
||||
self.callback_on_write = (
|
||||
callback_on_write # called after each modification (USELESS and unused)
|
||||
)
|
||||
self.allow_set_id = allow_set_id
|
||||
self.html_quote = html_quote
|
||||
self.fields_creators = fields_creators
|
||||
self.filter_nulls = filter_nulls
|
||||
self.sql_default_values = None
|
||||
|
||||
def create(self, cnx, args, has_uniq_values=False):
|
||||
def create(self, cnx, args):
|
||||
"create object in table"
|
||||
vals = dictfilter(args, self.dbfields, self.filter_nulls)
|
||||
if self.id_name in vals and not self.allow_set_id:
|
||||
|
@ -297,7 +299,7 @@ class EditableTable(object):
|
|||
if self.html_quote:
|
||||
quote_dict(vals) # quote all HTML markup
|
||||
# format value
|
||||
for title in vals.keys():
|
||||
for title in vals:
|
||||
if title in self.input_formators:
|
||||
vals[title] = self.input_formators[title](vals[title])
|
||||
# insert
|
||||
|
@ -309,23 +311,11 @@ class EditableTable(object):
|
|||
% {"id_name": self.id_name, "table_name": self.table_name, "oid": oid}
|
||||
)
|
||||
new_id = cursor.fetchone()[0]
|
||||
if has_uniq_values: # XXX probably obsolete
|
||||
# check all tuples (without id_name) are UNIQUE !
|
||||
res = DBSelectArgs(cnx, self.table_name, vals, what=[self.id_name])
|
||||
if len(res) != 1:
|
||||
# BUG !
|
||||
log("create: BUG table_name=%s args=%s" % (self.table_name, str(args)))
|
||||
assert len(res) == 1, "len(res) = %d != 1 !" % len(res)
|
||||
if self.callback_on_write:
|
||||
self.callback_on_write()
|
||||
|
||||
return new_id
|
||||
|
||||
def delete(self, cnx, oid, commit=True):
|
||||
"delete tuple"
|
||||
DBDelete(cnx, self.table_name, self.id_name, oid, commit=commit)
|
||||
if self.callback_on_write:
|
||||
self.callback_on_write()
|
||||
|
||||
def list(
|
||||
self,
|
||||
|
@ -339,10 +329,6 @@ class EditableTable(object):
|
|||
offset="",
|
||||
):
|
||||
"returns list of dicts"
|
||||
# REQLOG.write('%s: %s by %s (%s) %d\n'%(self.table_name,args,sys._getframe(1).f_code.co_name, sys._getframe(2).f_code.co_name, REQN))
|
||||
# REQLOG.flush()
|
||||
# global REQN
|
||||
# REQN = REQN + 1
|
||||
vals = dictfilter(args, self.dbfields, self.filter_nulls)
|
||||
if not sortkey:
|
||||
sortkey = self.sortkey
|
||||
|
@ -398,60 +384,10 @@ class EditableTable(object):
|
|||
where="%s=%%(%s)s" % (self.id_name, self.id_name),
|
||||
commit=True,
|
||||
)
|
||||
if self.callback_on_write:
|
||||
self.callback_on_write()
|
||||
|
||||
def get_sql_default_values(self, cnx):
|
||||
"return dict with SQL default values for each field"
|
||||
if self.sql_default_values is None: # not cached
|
||||
# We insert a new tuple, get the values and delete it
|
||||
# XXX non, car certaines tables ne peuvent creer de tuples
|
||||
# a default, a cause des references ou contraintes d'intégrité.
|
||||
# oid = self.create(cnx, {})
|
||||
# vals = self.list(cnx, args= {self.id_name : oid})[0]
|
||||
# self.delete(cnx, oid)
|
||||
# self.sql_default_values = vals
|
||||
#
|
||||
# Méthode spécifique à postgresql (>= 7.4)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor.execute(
|
||||
"SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_name = '%s'"
|
||||
% self.table_name
|
||||
)
|
||||
d = {}
|
||||
for info in cursor.dictfetchall():
|
||||
v = info["column_default"]
|
||||
# strip type information if present (eg 'hello'::text)
|
||||
if v:
|
||||
v = v.split("::")[0]
|
||||
# convert type to Python type
|
||||
if v:
|
||||
if info["data_type"] == "text":
|
||||
log('get: v="%s"' % v)
|
||||
if v[0] == v[-1] == "'":
|
||||
v = v[1:-1] # strip quotes
|
||||
elif v[:2] == "E'" and v[-1] == "'":
|
||||
v = v[2:-1] # postgresql string with escapes
|
||||
v = v.replace(
|
||||
"\\012", "\n"
|
||||
) # fix (je ne comprend pas bien pourquoi les valeurs sont ici quotées, ce n'est pas le cas dans les tables ordinaires)
|
||||
v = v.replace("''", "'") # idem
|
||||
log('--> v="%s"' % v)
|
||||
elif info["data_type"] == "real":
|
||||
v = float(v)
|
||||
elif info["data_type"] == "integer":
|
||||
v = int(v)
|
||||
# elif info['data_type'] == 'date':
|
||||
# pass # XXX todo
|
||||
else:
|
||||
log("Warning: unhandled SQL type in get_sql_default_values")
|
||||
d[info["column_name"]] = v
|
||||
self.sql_default_values = d
|
||||
return self.sql_default_values
|
||||
|
||||
|
||||
def dictfilter(d, fields, filter_nulls=True):
|
||||
# returns a copy of d with only keys listed in "fields" and non null values
|
||||
"""returns a copy of d with only keys listed in "fields" and non null values"""
|
||||
r = {}
|
||||
for f in fields:
|
||||
if f in d and (d[f] != None or not filter_nulls):
|
||||
|
@ -459,7 +395,6 @@ def dictfilter(d, fields, filter_nulls=True):
|
|||
val = d[f].strip()
|
||||
except:
|
||||
val = d[f]
|
||||
# if val != '': not a good idea: how to suppress a field ?
|
||||
r[f] = val
|
||||
return r
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ def get_code_latex_from_scodoc_preference(
|
|||
Extrait le template (ou le tag d'annotation au regard du champ fourni) des préférences LaTeX
|
||||
et s'assure qu'il est renvoyé au format unicode
|
||||
"""
|
||||
template_latex = sco_preferences.get_preference(context, champ, formsemestre_id)
|
||||
template_latex = sco_preferences.get_preference(champ, formsemestre_id)
|
||||
|
||||
return template_latex or ""
|
||||
|
||||
|
|
|
@ -44,10 +44,7 @@ Created on Fri Sep 9 09:15:05 2016
|
|||
|
||||
import os
|
||||
|
||||
try:
|
||||
from io import StringIO ## for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO ## for Python 2
|
||||
from io import StringIO
|
||||
|
||||
from zipfile import ZipFile, BadZipfile
|
||||
import pprint
|
||||
|
@ -197,7 +194,7 @@ class JuryPE(object):
|
|||
# self.add_file_to_zip(filename, self.xls.excel())
|
||||
|
||||
# Fabrique 1 fichier excel résultat avec 1 seule feuille => trop gros
|
||||
filename = self.NOM_EXPORT_ZIP + "_jurySyntheseDict" + ".xls"
|
||||
filename = self.NOM_EXPORT_ZIP + "_jurySyntheseDict" + scu.XLSX_SUFFIX
|
||||
self.xlsV2 = self.table_syntheseJury(mode="multiplesheet")
|
||||
if self.xlsV2:
|
||||
self.add_file_to_zip(filename, self.xlsV2.excel())
|
||||
|
@ -498,7 +495,7 @@ class JuryPE(object):
|
|||
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
|
||||
|
||||
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
|
||||
semestresDeScoDoc = sco_formsemestre.formsemestre_list(self.context)
|
||||
semestresDeScoDoc = sco_formsemestre.do_formsemestre_list(self.context)
|
||||
semestresSuperieurs = [
|
||||
sem for sem in semestresDeScoDoc if sem["semestre_id"] > sonDernierSidValide
|
||||
] # Semestre de rang plus élevé que son dernier sem valide
|
||||
|
@ -1243,9 +1240,9 @@ def get_cosemestres_diplomants(context, semBase, avec_meme_formation=False):
|
|||
> dont la formation est la même (optionnel)
|
||||
> ne prenant en compte que les etudiants sans redoublement
|
||||
"""
|
||||
tousLesSems = sco_formsemestre.formsemestre_list(
|
||||
tousLesSems = sco_formsemestre.do_formsemestre_list(
|
||||
context
|
||||
) # tous les semestres memorises dans scodoc
|
||||
) # tous les semestres memorisés dans scodoc
|
||||
diplome = get_annee_diplome_semestre(semBase)
|
||||
|
||||
if avec_meme_formation: # si une formation est imposee
|
||||
|
|
|
@ -48,15 +48,13 @@ from app.scodoc import pe_avislatex
|
|||
|
||||
def _pe_view_sem_recap_form(context, formsemestre_id, REQUEST=None):
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Avis de poursuite d'études"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Avis de poursuite d'études"),
|
||||
"""<h2 class="formsemestre">Génération des avis de poursuites d'études</h2>
|
||||
<p class="help">
|
||||
Cette fonction génère un ensemble de fichiers permettant d'éditer des avis de poursuites d'études.
|
||||
<br/>
|
||||
De nombreux aspects sont paramétrables:
|
||||
<a href="https://scodoc.org/AvisPoursuiteEtudes">
|
||||
<a href="https://scodoc.org/AvisPoursuiteEtudes" target="_blank" rel="noopener noreferrer">
|
||||
voir la documentation</a>.
|
||||
</p>
|
||||
<form method="post" action="pe_view_sem_recap" id="pe_view_sem_recap_form" enctype="multipart/form-data">
|
||||
|
@ -73,7 +71,7 @@ def _pe_view_sem_recap_form(context, formsemestre_id, REQUEST=None):
|
|||
formsemestre_id=formsemestre_id
|
||||
),
|
||||
]
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def pe_view_sem_recap(
|
||||
|
@ -91,7 +89,7 @@ def pe_view_sem_recap(
|
|||
"""
|
||||
if REQUEST and REQUEST.REQUEST_METHOD == "GET":
|
||||
return _pe_view_sem_recap_form(context, formsemestre_id, REQUEST=REQUEST)
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id=formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
|
||||
|
||||
semBase = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
||||
|
@ -144,7 +142,9 @@ def pe_view_sem_recap(
|
|||
context, jury.syntheseJury, tag_annotation_pe
|
||||
)
|
||||
if sT:
|
||||
jury.add_file_to_zip(jury.NOM_EXPORT_ZIP + "_annotationsPE.xls", sT.excel())
|
||||
jury.add_file_to_zip(
|
||||
jury.NOM_EXPORT_ZIP + "_annotationsPE" + scu.XLSX_SUFFIX, sT.excel()
|
||||
)
|
||||
|
||||
latex_pages = {} # Dictionnaire de la forme nom_fichier => contenu_latex
|
||||
for etudid in etudids:
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
alembic==1.6.5
|
||||
astroid==2.6.2
|
||||
Babel==2.9.1
|
||||
blinker==1.4
|
||||
certifi==2021.5.30
|
||||
chardet==4.0.0
|
||||
click==8.0.1
|
||||
cracklib==2.9.3
|
||||
dnspython==2.1.0
|
||||
dominate==2.6.0
|
||||
email-validator==1.1.3
|
||||
Flask==2.0.1
|
||||
Flask-Babel==2.0.0
|
||||
Flask-Bootstrap==3.3.7.1
|
||||
Flask-Login==0.5.0
|
||||
Flask-Mail==0.9.1
|
||||
Flask-Migrate==3.0.1
|
||||
Flask-Moment==1.0.1
|
||||
Flask-SQLAlchemy==2.5.1
|
||||
Flask-WTF==0.15.1
|
||||
greenlet==1.1.0
|
||||
html2text==2020.1.16
|
||||
icalendar==4.0.7
|
||||
idna==2.10
|
||||
importlib-metadata==4.6.1
|
||||
isort==5.9.2
|
||||
itsdangerous==2.0.1
|
||||
Jinja2==3.0.1
|
||||
lazy-object-proxy==1.6.0
|
||||
Mako==1.1.4
|
||||
MarkupSafe==2.0.1
|
||||
mccabe==0.6.1
|
||||
Pillow==8.3.1
|
||||
pkg-resources==0.0.0
|
||||
psycopg2==2.9.1
|
||||
PyJWT==2.1.0
|
||||
pylint==2.9.3
|
||||
pylint-flask-sqlalchemy==0.2.0
|
||||
PyRSS2Gen==1.1
|
||||
python-dateutil==2.8.1
|
||||
python-dotenv==0.18.0
|
||||
python-editor==1.0.4
|
||||
pytz==2021.1
|
||||
reportlab==3.5.68
|
||||
requests==2.25.1
|
||||
six==1.16.0
|
||||
SQLAlchemy==1.4.20
|
||||
toml==0.10.2
|
||||
typed-ast==1.4.3
|
||||
typing-extensions==3.10.0.0
|
||||
urllib3==1.26.6
|
||||
visitor==0.1.3
|
||||
Werkzeug==2.0.1
|
||||
wrapt==1.12.1
|
||||
WTForms==2.3.3
|
||||
zipp==3.5.0
|
|
@ -68,7 +68,7 @@ def _toboolean(x):
|
|||
|
||||
def is_work_saturday(context):
|
||||
"Vrai si le samedi est travaillé"
|
||||
return int(sco_preferences.get_preference(context, "work_saturday"))
|
||||
return int(sco_preferences.get_preference("work_saturday"))
|
||||
|
||||
|
||||
def MonthNbDays(month, year):
|
||||
|
@ -306,11 +306,14 @@ def list_abs_in_range(etudid, debut, fin, matin=None, moduleimpl_id=None, cursor
|
|||
"""Liste des absences entre deux dates.
|
||||
|
||||
Args:
|
||||
etudid
|
||||
debut string iso date ("2020-03-12")
|
||||
end string iso date ("2020-03-12")
|
||||
matin None, True, False
|
||||
moduleimpl_id
|
||||
etudid:
|
||||
debut: string iso date ("2020-03-12")
|
||||
end: string iso date ("2020-03-12")
|
||||
matin: None, True, False
|
||||
moduleimpl_id: restreint le comptage aux absences dans ce module
|
||||
|
||||
Returns:
|
||||
List of absences
|
||||
"""
|
||||
if matin != None:
|
||||
matin = _toboolean(matin)
|
||||
|
@ -347,9 +350,15 @@ WHERE A.ETUDID = %(etudid)s
|
|||
return res
|
||||
|
||||
|
||||
def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None):
|
||||
"""CountAbs
|
||||
matin= 1 ou 0.
|
||||
def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None) -> int:
|
||||
"""compte le nombre d'absences
|
||||
|
||||
Args:
|
||||
etudid: l'étudiant considéré
|
||||
debut: date, chaîne iso, eg "2021-06-15"
|
||||
fin: date de fin, incluse
|
||||
matin: True (compte les matinées), False (les après-midi), None (les deux)
|
||||
moduleimpl_id: restreint le comptage aux absences dans ce module.
|
||||
|
||||
Returns:
|
||||
An integer.
|
||||
|
@ -359,8 +368,19 @@ def count_abs(etudid, debut, fin, matin=None, moduleimpl_id=None):
|
|||
)
|
||||
|
||||
|
||||
def count_abs_just(etudid, debut, fin, matin=None, moduleimpl_id=None):
|
||||
"Count just. abs"
|
||||
def count_abs_just(etudid, debut, fin, matin=None, moduleimpl_id=None) -> int:
|
||||
"""compte le nombre d'absences justifiées
|
||||
|
||||
Args:
|
||||
etudid: l'étudiant considéré
|
||||
debut: date, chaîne iso, eg "2021-06-15"
|
||||
fin: date de fin, incluse
|
||||
matin: True (compte les matinées), False (les après-midi), None (les deux)
|
||||
moduleimpl_id: restreint le comptage aux absences dans ce module.
|
||||
|
||||
Returns:
|
||||
An integer.
|
||||
"""
|
||||
if matin != None:
|
||||
matin = _toboolean(matin)
|
||||
ismatin = " AND A.MATIN = %(matin)s "
|
||||
|
@ -569,9 +589,20 @@ ORDER BY A.JOUR
|
|||
|
||||
|
||||
def list_abs_justifs(etudid, datedebut, datefin=None, only_no_abs=False):
|
||||
"""Liste des justificatifs (sans absence relevée) à partir d'une date,
|
||||
"""Liste des justificatifs (avec ou sans absence relevée) à partir d'une date,
|
||||
ou, si datefin spécifié, entre deux dates.
|
||||
Si only_no_abs: seulement les justificatifs correspondant aux jours sans absences relevées.
|
||||
|
||||
Args:
|
||||
etudid:
|
||||
datedebut: date de début, iso, eg "2002-03-15"
|
||||
datefin: date de fin, incluse, eg "2002-03-15"
|
||||
only_no_abs: si vrai, seulement les justificatifs correspondant
|
||||
aux jours sans absences relevées.
|
||||
Returns:
|
||||
Liste de dict absences
|
||||
{'etudid': 'EID214', 'jour': datetime.date(2021, 1, 15),
|
||||
'matin': True, 'description': ''
|
||||
}
|
||||
"""
|
||||
cnx = ndb.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
|
@ -617,7 +648,6 @@ def add_absence(
|
|||
vars(),
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
"AddAbsence",
|
||||
etudid=etudid,
|
||||
|
@ -642,7 +672,6 @@ def add_justif(context, etudid, jour, matin, REQUEST, description=None):
|
|||
vars(),
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
"AddJustif",
|
||||
etudid=etudid,
|
||||
|
@ -666,9 +695,16 @@ def _add_abslist(context, abslist, REQUEST, moduleimpl_id=None):
|
|||
add_absence(context, etudid, jour, matin, 0, REQUEST, "", moduleimpl_id)
|
||||
|
||||
|
||||
def annule_absence(context, etudid, jour, matin, moduleimpl_id=None, REQUEST=None):
|
||||
"""Annule une absence ds base
|
||||
Si moduleimpl_id, n'annule que pour ce module
|
||||
def annule_absence(context, etudid, jour, matin, moduleimpl_id=None):
|
||||
"""Annule une absence dans la base. N'efface pas l'éventuel justificatif.
|
||||
Args:
|
||||
etudid:
|
||||
jour: date, chaîne iso, eg "1999-12-31"
|
||||
matin:
|
||||
moduleimpl_id: si spécifié, n'annule que pour ce module.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# unpublished
|
||||
matin = _toboolean(matin)
|
||||
|
@ -679,7 +715,6 @@ def annule_absence(context, etudid, jour, matin, moduleimpl_id=None, REQUEST=Non
|
|||
req += " and moduleimpl_id=%(moduleimpl_id)s"
|
||||
cursor.execute(req, vars())
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
"AnnuleAbsence",
|
||||
etudid=etudid,
|
||||
|
@ -704,7 +739,6 @@ def annule_justif(context, etudid, jour, matin, REQUEST=None):
|
|||
vars(),
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
"AnnuleJustif",
|
||||
etudid=etudid,
|
||||
|
@ -867,7 +901,9 @@ def MonthTableBody(
|
|||
if pad_width != None:
|
||||
n = pad_width - len(legend) # pad to 8 cars
|
||||
if n > 0:
|
||||
legend = " " * (n / 2) + legend + " " * ((n + 1) / 2)
|
||||
legend = (
|
||||
" " * (n // 2) + legend + " " * ((n + 1) // 2)
|
||||
)
|
||||
else:
|
||||
legend = " " # empty cell
|
||||
cc.append(legend)
|
||||
|
@ -974,7 +1010,7 @@ def MonthTableBody(
|
|||
#
|
||||
# Cache absences
|
||||
#
|
||||
# On cache (via memcached ou autre, voir sco_cache.py) les _nombres_ d'absences
|
||||
# On cache (via REDIS ou autre, voir sco_cache.py) les _nombres_ d'absences
|
||||
# (justifiées et non justifiées) de chaque etudiant dans un semestre donné.
|
||||
# Le cache peut être invalidé soit par étudiant/semestre, soit pour tous
|
||||
# les étudiant d'un semestre.
|
||||
|
|
|
@ -73,9 +73,7 @@ def do_abs_notify(context, sem, etudid, date, nbabs, nbabsjust):
|
|||
formsemestre_id = sem["formsemestre_id"]
|
||||
else:
|
||||
formsemestre_id = None
|
||||
prefs = sco_preferences.SemPreferences(
|
||||
context, formsemestre_id=sem["formsemestre_id"]
|
||||
)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id=sem["formsemestre_id"])
|
||||
|
||||
destinations = abs_notify_get_destinations(
|
||||
context, sem, prefs, etudid, date, nbabs, nbabsjust
|
||||
|
@ -85,7 +83,7 @@ def do_abs_notify(context, sem, etudid, date, nbabs, nbabsjust):
|
|||
return # abort
|
||||
|
||||
# Vérification fréquence (pour ne pas envoyer de mails trop souvent)
|
||||
abs_notify_max_freq = sco_preferences.get_preference(context, "abs_notify_max_freq")
|
||||
abs_notify_max_freq = sco_preferences.get_preference("abs_notify_max_freq")
|
||||
destinations_filtered = []
|
||||
for email_addr in destinations:
|
||||
nbdays_since_last_notif = user_nbdays_since_last_notif(
|
||||
|
@ -120,7 +118,6 @@ def abs_notify_send(
|
|||
msg["To"] = email
|
||||
sco_emails.sendEmail(context, msg)
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",
|
||||
vars(),
|
||||
cursor=cursor,
|
||||
|
@ -184,10 +181,10 @@ def abs_notify_is_above_threshold(context, etudid, nbabs, nbabsjust, formsemestr
|
|||
(nbabs - nbabs_last_notified) > abs_notify_abs_increment
|
||||
"""
|
||||
abs_notify_abs_threshold = sco_preferences.get_preference(
|
||||
context, "abs_notify_abs_threshold", formsemestre_id
|
||||
"abs_notify_abs_threshold", formsemestre_id
|
||||
)
|
||||
abs_notify_abs_increment = sco_preferences.get_preference(
|
||||
context, "abs_notify_abs_increment", formsemestre_id
|
||||
"abs_notify_abs_increment", formsemestre_id
|
||||
)
|
||||
nbabs_last_notified = etud_nbabs_last_notified(context, etudid, formsemestre_id)
|
||||
|
||||
|
@ -278,7 +275,7 @@ def retreive_current_formsemestre(context, etudid, cur_date):
|
|||
WHERE sem.formsemestre_id = i.formsemestre_id AND i.etudid=%(etudid)s
|
||||
AND (%(cur_date)s >= sem.date_debut) AND (%(cur_date)s <= sem.date_fin)"""
|
||||
|
||||
r = ndb.SimpleDictFetch(context, req, {"etudid": etudid, "cur_date": cur_date})
|
||||
r = ndb.SimpleDictFetch(req, {"etudid": etudid, "cur_date": cur_date})
|
||||
if not r:
|
||||
return None
|
||||
# s'il y a plusieurs semestres, prend le premier (rarissime et non significatif):
|
||||
|
@ -291,5 +288,5 @@ def mod_with_evals_at_date(context, date_abs, etudid):
|
|||
req = """SELECT m.* FROM notes_moduleimpl m, notes_evaluation e, notes_moduleimpl_inscription i
|
||||
WHERE m.moduleimpl_id = e.moduleimpl_id AND e.moduleimpl_id = i.moduleimpl_id
|
||||
AND i.etudid = %(etudid)s AND e.jour = %(date_abs)s"""
|
||||
r = ndb.SimpleDictFetch(context, req, {"etudid": etudid, "date_abs": date_abs})
|
||||
r = ndb.SimpleDictFetch(req, {"etudid": etudid, "date_abs": date_abs})
|
||||
return r
|
||||
|
|
|
@ -132,8 +132,6 @@ def doSignaleAbsence(
|
|||
M = "dans le module %s" % modimpl["module"]["code"]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Signalement d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<h2>Signalement d'absences</h2>""",
|
||||
|
@ -157,7 +155,7 @@ def doSignaleAbsence(
|
|||
% etud
|
||||
)
|
||||
H.append(sco_find_etud.form_search_etud(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -169,7 +167,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
disabled = False
|
||||
if not etud["cursem"]:
|
||||
require_module = sco_preferences.get_preference(
|
||||
context, "abs_require_module"
|
||||
"abs_require_module"
|
||||
) # on utilise la pref globale car pas de sem courant
|
||||
if require_module:
|
||||
menu_module = """<div class="ue_warning">Pas inscrit dans un semestre courant,
|
||||
|
@ -180,7 +178,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
else:
|
||||
formsemestre_id = etud["cursem"]["formsemestre_id"]
|
||||
require_module = sco_preferences.get_preference(
|
||||
context, "abs_require_module", formsemestre_id
|
||||
"abs_require_module", formsemestre_id
|
||||
)
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||
ues = nt.get_ues(etudid=etudid)
|
||||
|
@ -221,8 +219,6 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Signalement d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<table><tr><td>
|
||||
|
@ -278,7 +274,7 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||
"menu_module": menu_module,
|
||||
"disabled": "disabled" if disabled else "",
|
||||
},
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -340,8 +336,6 @@ def doJustifAbsence(
|
|||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Justification d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<h2>Justification d'absences</h2>""",
|
||||
|
@ -367,7 +361,7 @@ def doJustifAbsence(
|
|||
% etud
|
||||
)
|
||||
H.append(sco_find_etud.form_search_etud(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -378,8 +372,6 @@ def JustifAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
etudid = etud["etudid"]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Justification d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<table><tr><td>
|
||||
|
@ -424,7 +416,7 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||
|
||||
</form> """
|
||||
% etud,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -441,17 +433,15 @@ def doAnnuleAbsence(
|
|||
demijournee = int(demijournee)
|
||||
for jour in dates:
|
||||
if demijournee == 2:
|
||||
sco_abs.annule_absence(context, etudid, jour, False, REQUEST=REQUEST)
|
||||
sco_abs.annule_absence(context, etudid, jour, True, REQUEST=REQUEST)
|
||||
sco_abs.annule_absence(context, etudid, jour, False)
|
||||
sco_abs.annule_absence(context, etudid, jour, True)
|
||||
nbadded += 2
|
||||
else:
|
||||
sco_abs.annule_absence(context, etudid, jour, demijournee, REQUEST=REQUEST)
|
||||
sco_abs.annule_absence(context, etudid, jour, demijournee)
|
||||
nbadded += 1
|
||||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Annulation d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<h2>Annulation d'absences pour %(nomprenom)s</h2>""" % etud,
|
||||
|
@ -477,7 +467,7 @@ autre absence pour <b>%(nomprenom)s</b></a></li>
|
|||
% etud
|
||||
)
|
||||
H.append(sco_find_etud.form_search_etud(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -489,8 +479,6 @@ def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Annulation d'une absence pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<table><tr><td>
|
||||
|
@ -565,7 +553,7 @@ def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||
</form>
|
||||
</td></tr></table>"""
|
||||
% etud,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -591,8 +579,6 @@ def doAnnuleJustif(
|
|||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Annulation d'une justification pour %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<h2>Annulation de justifications pour %(nomprenom)s</h2>""" % etud,
|
||||
|
@ -618,13 +604,20 @@ autre absence pour <b>%(nomprenom)s</b></a></li>
|
|||
% etud
|
||||
)
|
||||
H.append(sco_find_etud.form_search_etud(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None, REQUEST=None):
|
||||
"""Supprime les absences aux dates indiquées
|
||||
mais ne supprime pas les justificatifs.
|
||||
def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None):
|
||||
"""Supprime les absences non justifiées aux dates indiquées
|
||||
Ne supprime pas les justificatifs éventuels.
|
||||
Args:
|
||||
etudid: l'étudiant
|
||||
dates: liste de dates iso, eg [ "2000-01-15", "2000-01-16" ]
|
||||
moduleimpl_id: si spécifié, n'affecte que les absences de ce module
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# log('AnnuleAbsencesDatesNoJust: moduleimpl_id=%s' % moduleimpl_id)
|
||||
if not dates:
|
||||
|
@ -640,7 +633,7 @@ def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None, REQUES
|
|||
matin = 0
|
||||
else:
|
||||
raise ValueError("invalid ampm !")
|
||||
sco_abs.annule_absence(context, etudid, jour, matin, moduleimpl_id, REQUEST)
|
||||
sco_abs.annule_absence(context, etudid, jour, matin, moduleimpl_id)
|
||||
return
|
||||
cnx = ndb.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
|
@ -666,7 +659,6 @@ def AnnuleAbsencesDatesNoJust(context, etudid, dates, moduleimpl_id=None, REQUES
|
|||
else:
|
||||
date1 = None
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
"AnnuleAbsencesDatesNoJust",
|
||||
etudid=etudid,
|
||||
|
@ -679,7 +671,7 @@ def EtatAbsences(context, REQUEST=None):
|
|||
"""Etat des absences: choix du groupe"""
|
||||
# crude portage from 1999 DTML
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title="Etat des absences"),
|
||||
html_sco_header.sco_header(page_title="Etat des absences"),
|
||||
"""<h2>Etat des absences pour un groupe</h2>
|
||||
<form action="EtatAbsencesGr" method="GET">""",
|
||||
formChoixSemestreGroupe(context),
|
||||
|
@ -695,8 +687,8 @@ def EtatAbsences(context, REQUEST=None):
|
|||
|
||||
</td></tr></table>
|
||||
</form>"""
|
||||
% (scu.AnneeScolaire(REQUEST), datetime.datetime.now().strftime("%d/%m/%Y")),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
% (scu.AnneeScolaire(), datetime.datetime.now().strftime("%d/%m/%Y")),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -729,12 +721,13 @@ def formChoixSemestreGroupe(context, all=False):
|
|||
return "\n".join(H)
|
||||
|
||||
|
||||
def CalAbs(context, REQUEST=None): # etud implied
|
||||
def CalAbs(context, etudid, sco_year=None):
|
||||
"""Calendrier des absences d'un etudiant"""
|
||||
# crude portage from 1999 DTML
|
||||
REQUEST = None # XXX
|
||||
etud = sco_etud.get_etud_info(filled=1, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
anneescolaire = int(scu.AnneeScolaire(REQUEST))
|
||||
anneescolaire = int(scu.AnneeScolaire(sco_year))
|
||||
datedebut = str(anneescolaire) + "-08-31"
|
||||
datefin = str(anneescolaire + 1) + "-07-31"
|
||||
nbabs = sco_abs.count_abs(etudid=etudid, debut=datedebut, fin=datefin)
|
||||
|
@ -760,8 +753,6 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Calendrier des absences de %(nomprenom)s" % etud,
|
||||
cssstyles=["css/calabs.css"],
|
||||
),
|
||||
|
@ -799,25 +790,32 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||
H.append("selected")
|
||||
H.append(""">%s</option>""" % y)
|
||||
H.append("""</select></form>""")
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def ListeAbsEtud(
|
||||
context,
|
||||
etudid,
|
||||
with_evals=True, # indique les evaluations aux dates d'absences
|
||||
with_evals=True,
|
||||
format="html",
|
||||
absjust_only=0, # si vrai, renvoie table absences justifiées
|
||||
absjust_only=0,
|
||||
sco_year=None,
|
||||
REQUEST=None,
|
||||
):
|
||||
"""Liste des absences d'un étudiant sur l'année en cours
|
||||
En format 'html': page avec deux tableaux (non justifiées et justifiées).
|
||||
En format json, xml, xls ou pdf: l'un ou l'autre des table, suivant absjust_only.
|
||||
En format 'text': texte avec liste d'absences (pour mails).
|
||||
|
||||
Args:
|
||||
etudid:
|
||||
with_evals: indique les evaluations aux dates d'absences
|
||||
absjust_only: si vrai, renvoie table absences justifiées
|
||||
sco_year: année scolaire à utiliser. Si non spécifier, utilie l'année en cours. e.g. "2005"
|
||||
"""
|
||||
absjust_only = int(absjust_only) # si vrai, table absjust seule (export xls ou pdf)
|
||||
datedebut = "%s-08-31" % scu.AnneeScolaire(REQUEST)
|
||||
datedebut = "%s-08-31" % scu.AnneeScolaire(sco_year=sco_year)
|
||||
|
||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||
|
||||
|
@ -839,9 +837,7 @@ def ListeAbsEtud(
|
|||
base_url=base_url_nj,
|
||||
filename="abs_" + scu.make_filename(etud["nomprenom"]),
|
||||
caption="Absences non justifiées de %(nomprenom)s" % etud,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
tab_absjust = GenTable(
|
||||
titles=titles,
|
||||
|
@ -852,9 +848,7 @@ def ListeAbsEtud(
|
|||
base_url=base_url_j,
|
||||
filename="absjust_" + scu.make_filename(etud["nomprenom"]),
|
||||
caption="Absences justifiées de %(nomprenom)s" % etud,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
|
||||
# Formats non HTML et demande d'une seule table:
|
||||
|
@ -868,9 +862,7 @@ def ListeAbsEtud(
|
|||
# Mise en forme HTML:
|
||||
H = []
|
||||
H.append(
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Absences de %s" % etud["nomprenom"]
|
||||
)
|
||||
html_sco_header.sco_header(page_title="Absences de %s" % etud["nomprenom"])
|
||||
)
|
||||
H.append(
|
||||
"""<h2>Absences de %s (à partir du %s)</h2>"""
|
||||
|
@ -888,7 +880,7 @@ def ListeAbsEtud(
|
|||
H.append(tab_absjust.html())
|
||||
else:
|
||||
H.append("""<h3>Pas d'absences justifiées</h3>""")
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
elif format == "text":
|
||||
T = []
|
||||
|
|
|
@ -64,9 +64,7 @@ _help_txt = """
|
|||
def apo_compare_csv_form(context, REQUEST=None):
|
||||
"""Form: submit 2 CSV files to compare them."""
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Comparaison de fichiers Apogée"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Comparaison de fichiers Apogée"),
|
||||
"""<h2>Comparaison de fichiers Apogée</h2>
|
||||
<form id="apo_csv_add" action="apo_compare_csv" method="post" enctype="multipart/form-data">
|
||||
""",
|
||||
|
@ -85,7 +83,7 @@ def apo_compare_csv_form(context, REQUEST=None):
|
|||
<input type="submit" value="Comparer ces fichiers"/>
|
||||
</div>
|
||||
</form>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -96,16 +94,14 @@ def apo_compare_csv(context, A_file, B_file, autodetect=True, REQUEST=None):
|
|||
B = _load_apo_data(B_file, autodetect=autodetect)
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Comparaison de fichiers Apogée"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Comparaison de fichiers Apogée"),
|
||||
"<h2>Comparaison de fichiers Apogée</h2>",
|
||||
_help_txt,
|
||||
'<div class="apo_compare_csv">',
|
||||
_apo_compare_csv(context, A, B, REQUEST=None),
|
||||
"</div>",
|
||||
"""<p><a href="apo_compare_csv_form" class="stdlink">Autre comparaison</a></p>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -266,9 +262,7 @@ def apo_table_compare_etud_results(context, A, B, REQUEST=None):
|
|||
columns_ids=("nip", "nom", "prenom", "elt_code", "type_res", "val_A", "val_B"),
|
||||
html_class="table_leftalign",
|
||||
html_with_td_classes=True,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return T
|
||||
|
||||
|
|
|
@ -1266,8 +1266,8 @@ def export_csv_to_apogee(
|
|||
nf += 1
|
||||
|
||||
log_filename = "scodoc-" + basename + ".log.txt"
|
||||
nar_filename = basename + "-nar.xls"
|
||||
cr_filename = basename + "-decisions.xls"
|
||||
nar_filename = basename + "-nar" + scu.XLSX_SUFFIX
|
||||
cr_filename = basename + "-decisions" + scu.XLSX_SUFFIX
|
||||
|
||||
logf = StringIO()
|
||||
logf.write("export_to_apogee du %s\n\n" % time.ctime())
|
||||
|
|
|
@ -52,6 +52,8 @@ import re
|
|||
import shutil
|
||||
import glob
|
||||
|
||||
import flask
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from config import Config
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -235,7 +237,13 @@ class BaseArchiver(object):
|
|||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
return data
|
||||
elif ext == ".xls":
|
||||
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
||||
return sco_excel.send_excel_file(
|
||||
REQUEST, data, filename, mime=scu.XLS_MIMETYPE
|
||||
)
|
||||
elif ext == ".xlsx":
|
||||
return sco_excel.send_excel_file(
|
||||
REQUEST, data, filename, mime=scu.XLSX_MIMETYPE
|
||||
)
|
||||
elif ext == ".csv":
|
||||
return scu.sendCSVFile(REQUEST, data, filename)
|
||||
elif ext == ".pdf":
|
||||
|
@ -283,7 +291,7 @@ def do_formsemestre_archive(
|
|||
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(context, formsemestre_id)]
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
|
@ -295,7 +303,7 @@ def do_formsemestre_archive(
|
|||
context, REQUEST, formsemestre_id, format="xls"
|
||||
)
|
||||
if data:
|
||||
PVArchive.store(archive_id, "Tableau_moyennes.xls", data)
|
||||
PVArchive.store(archive_id, "Tableau_moyennes" + scu.XLSX_SUFFIX, data)
|
||||
# Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _, _ = make_formsemestre_recapcomplet(
|
||||
context, REQUEST, formsemestre_id, format="html", disable_etudlink=True
|
||||
|
@ -304,8 +312,6 @@ def do_formsemestre_archive(
|
|||
data = "\n".join(
|
||||
[
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Moyennes archivées le %s" % date,
|
||||
head_message="Moyennes archivées le %s" % date,
|
||||
no_side_bar=True,
|
||||
|
@ -313,7 +319,7 @@ def do_formsemestre_archive(
|
|||
'<h2 class="fontorange">Valeurs archivées le %s</h2>' % date,
|
||||
'<style type="text/css">table.notes_recapcomplet tr { color: rgb(185,70,0); }</style>',
|
||||
data,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
)
|
||||
PVArchive.store(archive_id, "Tableau_moyennes.html", data)
|
||||
|
@ -329,7 +335,7 @@ def do_formsemestre_archive(
|
|||
context, formsemestre_id, format="xls", REQUEST=REQUEST, publish=False
|
||||
)
|
||||
if data:
|
||||
PVArchive.store(archive_id, "Decisions_Jury.xls", data)
|
||||
PVArchive.store(archive_id, "Decisions_Jury" + scu.XLSX_SUFFIX, data)
|
||||
# Classeur bulletins (PDF)
|
||||
data, _ = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
||||
context, formsemestre_id, REQUEST, version=bulVersion
|
||||
|
@ -372,7 +378,7 @@ def formsemestre_archive(context, REQUEST, formsemestre_id, group_ids=[]):
|
|||
"""Make and store new archive for this formsemestre.
|
||||
(all students or only selected groups)
|
||||
"""
|
||||
if not sco_permissions_check.can_edit_pv(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
||||
raise AccessDenied(
|
||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
||||
)
|
||||
|
@ -380,7 +386,7 @@ def formsemestre_archive(context, REQUEST, formsemestre_id, group_ids=[]):
|
|||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(context, formsemestre_id)]
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
|
@ -406,7 +412,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
|||
F = [
|
||||
"""<p><em>Note: les documents sont aussi affectés par les réglages sur la page "<a href="edit_preferences">Paramétrage</a>" (accessible à l'administrateur du département).</em>
|
||||
</p>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
|
||||
descr = [
|
||||
|
@ -490,7 +496,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
|||
msg = "Nouvelle%20archive%20créée"
|
||||
|
||||
# submitted or cancelled:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_list_archives?formsemestre_id=%s&head_message=%s"
|
||||
% (formsemestre_id, msg)
|
||||
)
|
||||
|
@ -539,7 +545,7 @@ def formsemestre_list_archives(context, REQUEST, formsemestre_id):
|
|||
H.append("</ul></li>")
|
||||
H.append("</ul>")
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def formsemestre_get_archived_file(
|
||||
|
@ -555,7 +561,7 @@ def formsemestre_delete_archive(
|
|||
context, REQUEST, formsemestre_id, archive_name, dialog_confirmed=False
|
||||
):
|
||||
"""Delete an archive"""
|
||||
if not sco_permissions_check.can_edit_pv(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
||||
raise AccessDenied(
|
||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
||||
)
|
||||
|
@ -568,12 +574,10 @@ def formsemestre_delete_archive(
|
|||
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Confirmer la suppression de l'archive du %s ?</h2>
|
||||
<p>La suppression sera définitive.</p>"""
|
||||
% PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y %H:%M"),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url=dest_url,
|
||||
parameters={
|
||||
"formsemestre_id": formsemestre_id,
|
||||
|
@ -582,4 +586,4 @@ def formsemestre_delete_archive(
|
|||
)
|
||||
|
||||
PVArchive.delete_archive(archive_id)
|
||||
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||
return flask.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
Il s'agit de fichiers quelconques, généralement utilisés pour conserver
|
||||
les dossiers d'admission et autres pièces utiles.
|
||||
"""
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -133,8 +134,6 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||
etud = sco_etud.get_etud_info(filled=1, REQUEST=REQUEST)[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Chargement d'un document associé à %(nomprenom)s" % etud,
|
||||
),
|
||||
"""<h2>Chargement d'un document associé à %(nomprenom)s</h2>
|
||||
|
@ -164,9 +163,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||
cancelbutton="Annuler",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
)
|
||||
else:
|
||||
|
@ -176,7 +175,7 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||
_store_etud_file_to_new_archive(
|
||||
context, REQUEST, etudid, data, filename, description=descr
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
)
|
||||
|
||||
|
@ -203,7 +202,6 @@ def etud_delete_archive(context, REQUEST, etudid, archive_name, dialog_confirmed
|
|||
archive_id = EtudsArchive.get_id_from_name(context, etudid, archive_name)
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Confirmer la suppression des fichiers ?</h2>
|
||||
<p>Fichier associé le %s à l'étudiant %s</p>
|
||||
<p>La suppression sera définitive.</p>"""
|
||||
|
@ -212,7 +210,6 @@ def etud_delete_archive(context, REQUEST, etudid, archive_name, dialog_confirmed
|
|||
etud["nomprenom"],
|
||||
),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url=url_for(
|
||||
"scolar.ficheEtud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
|
@ -223,7 +220,7 @@ def etud_delete_archive(context, REQUEST, etudid, archive_name, dialog_confirmed
|
|||
)
|
||||
|
||||
EtudsArchive.delete_archive(archive_id)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"scolar.ficheEtud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
|
@ -259,14 +256,16 @@ def etudarchive_generate_excel_sample(context, group_id=None, REQUEST=None):
|
|||
extra_cols=["fichier_a_charger"],
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
return sco_excel.sendExcelFile(REQUEST, data, "ImportFichiersEtudiants.xls")
|
||||
return sco_excel.send_excel_file(
|
||||
REQUEST, data, "ImportFichiersEtudiants" + scu.XLSX_SUFFIX
|
||||
)
|
||||
|
||||
|
||||
def etudarchive_import_files_form(context, group_id, REQUEST=None):
|
||||
"""Formulaire pour importation fichiers d'un groupe"""
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Import de fichiers associés aux étudiants"
|
||||
page_title="Import de fichiers associés aux étudiants"
|
||||
),
|
||||
"""<h2 class="formsemestre">Téléchargement de fichier associés aux étudiants</h2>
|
||||
<p>Les fichiers associés (dossiers d'admission, certificats, ...), de types quelconques (pdf, doc, images)
|
||||
|
@ -289,7 +288,7 @@ def etudarchive_import_files_form(context, group_id, REQUEST=None):
|
|||
"""
|
||||
% group_id,
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
REQUEST.form,
|
||||
|
@ -313,9 +312,13 @@ def etudarchive_import_files_form(context, group_id, REQUEST=None):
|
|||
return "\n".join(H) + tf[1] + "</li></ol>" + F
|
||||
elif tf[0] == -1:
|
||||
# retrouve le semestre à partir du groupe:
|
||||
g = sco_groups.get_group(context, group_id)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_status?formsemestre_id=" + g["formsemestre_id"]
|
||||
group = sco_groups.get_group(context, group_id)
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=group["formsemestre_id"],
|
||||
)
|
||||
)
|
||||
else:
|
||||
return etudarchive_import_files(
|
||||
|
@ -342,4 +345,4 @@ def etudarchive_import_files(
|
|||
r = sco_trombino.zip_excel_import_files(
|
||||
context, xlsfile, zipfile, REQUEST, callback, filename_title, page_title
|
||||
)
|
||||
return r + html_sco_header.sco_footer(context, REQUEST)
|
||||
return r + html_sco_header.sco_footer()
|
||||
|
|
|
@ -38,7 +38,10 @@ from email.header import Header
|
|||
|
||||
from reportlab.lib.colors import Color
|
||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
from flask import g, url_for
|
||||
|
||||
from flask import g
|
||||
from flask import url_for
|
||||
from flask_login import current_user
|
||||
|
||||
from app.scodoc import sco_emails
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -99,8 +102,8 @@ def make_context_dict(context, sem, etud):
|
|||
C.update(etud)
|
||||
# copie preferences
|
||||
# XXX devrait acceder directement à un dict de preferences, à revoir
|
||||
for name in sco_preferences.get_base_preferences(context).prefs_name:
|
||||
C[name] = sco_preferences.get_preference(context, name, sem["formsemestre_id"])
|
||||
for name in sco_preferences.get_base_preferences().prefs_name:
|
||||
C[name] = sco_preferences.get_preference(name, sem["formsemestre_id"])
|
||||
|
||||
# ajoute groupes et group_0, group_1, ...
|
||||
sco_groups.etud_add_group_infos(context, etud, sem)
|
||||
|
@ -133,7 +136,7 @@ def formsemestre_bulletinetud_dict(
|
|||
if not version in scu.BULLETINS_VERSIONS:
|
||||
raise ValueError("invalid version code !")
|
||||
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes
|
||||
|
||||
I = scu.DictDefault(defaultvalue="")
|
||||
|
@ -417,10 +420,10 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||
Result: liste de modules de l'UE avec les infos dans chacun (seulement ceux où l'étudiant est inscrit).
|
||||
"""
|
||||
bul_show_mod_rangs = sco_preferences.get_preference(
|
||||
context, "bul_show_mod_rangs", formsemestre_id
|
||||
"bul_show_mod_rangs", formsemestre_id
|
||||
)
|
||||
bul_show_abs_modules = sco_preferences.get_preference(
|
||||
context, "bul_show_abs_modules", formsemestre_id
|
||||
"bul_show_abs_modules", formsemestre_id
|
||||
)
|
||||
if bul_show_abs_modules:
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
@ -481,9 +484,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||
'<a class="bull_link" href="moduleimpl_status?moduleimpl_id=%s" title="%s">'
|
||||
% (modimpl["moduleimpl_id"], mod["mod_descr_txt"])
|
||||
)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_codemodules", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
||||
mod["code"] = modimpl["module"]["code"]
|
||||
mod["code_html"] = link_mod + mod["code"] + "</a>"
|
||||
else:
|
||||
|
@ -502,9 +503,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||
'<a class="bull_link" href="moduleimpl_status?moduleimpl_id=%s" title="%s">'
|
||||
% (modimpl["moduleimpl_id"], mod_descr)
|
||||
)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_codemodules", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
||||
mod["code_txt"] = modimpl["module"]["code"]
|
||||
mod["code_html"] = link_mod + mod["code_txt"] + "</a>"
|
||||
else:
|
||||
|
@ -565,12 +564,10 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||
|
||||
# Evaluations incomplètes ou futures:
|
||||
mod["evaluations_incompletes"] = []
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_all_evals", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_all_evals", formsemestre_id):
|
||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
||||
all_evals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
)
|
||||
all_evals.reverse() # plus ancienne d'abord
|
||||
for e in all_evals:
|
||||
|
@ -784,7 +781,7 @@ def formsemestre_bulletinetud(
|
|||
etud = sco_etud.get_etud_info(filled=1, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
except:
|
||||
return scu.log_unknown_etud(context, REQUEST, format=format)
|
||||
return scu.log_unknown_etud(REQUEST, format=format)
|
||||
|
||||
bulletin = do_formsemestre_bulletinetud(
|
||||
context,
|
||||
|
@ -838,21 +835,18 @@ def formsemestre_bulletinetud(
|
|||
H.append('<div id="radar_bulletin"></div>')
|
||||
|
||||
# --- Pied de page
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
|
||||
return "".join(H)
|
||||
|
||||
|
||||
def can_send_bulletin_by_mail(context, formsemestre_id, REQUEST):
|
||||
def can_send_bulletin_by_mail(context, formsemestre_id):
|
||||
"""True if current user is allowed to send a bulletin by mail"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
return (
|
||||
sco_preferences.get_preference(
|
||||
context, "bul_mail_allowed_for_all", formsemestre_id
|
||||
)
|
||||
or authuser.has_permission(Permission.ScoImplement)
|
||||
or str(authuser) in sem["responsables"]
|
||||
sco_preferences.get_preference("bul_mail_allowed_for_all", formsemestre_id)
|
||||
or current_user.has_permission(Permission.ScoImplement)
|
||||
or current_user.user_name in sem["responsables"]
|
||||
)
|
||||
|
||||
|
||||
|
@ -929,7 +923,7 @@ def do_formsemestre_bulletinetud(
|
|||
elif format == "pdfmail":
|
||||
# format pdfmail: envoie le pdf par mail a l'etud, et affiche le html
|
||||
# check permission
|
||||
if not can_send_bulletin_by_mail(context, formsemestre_id, REQUEST):
|
||||
if not can_send_bulletin_by_mail(context, formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
|
||||
if nohtml:
|
||||
|
@ -978,18 +972,12 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||
If bul_mail_list_abs pref is true, put list of absences in mail body (text).
|
||||
"""
|
||||
etud = I["etud"]
|
||||
webmaster = sco_preferences.get_preference(
|
||||
context, "bul_mail_contact_addr", formsemestre_id
|
||||
)
|
||||
webmaster = sco_preferences.get_preference("bul_mail_contact_addr", formsemestre_id)
|
||||
dept = scu.unescape_html(
|
||||
sco_preferences.get_preference(context, "DeptName", formsemestre_id)
|
||||
)
|
||||
copy_addr = sco_preferences.get_preference(
|
||||
context, "email_copy_bulletins", formsemestre_id
|
||||
)
|
||||
intro_mail = sco_preferences.get_preference(
|
||||
context, "bul_intro_mail", formsemestre_id
|
||||
sco_preferences.get_preference("DeptName", formsemestre_id)
|
||||
)
|
||||
copy_addr = sco_preferences.get_preference("email_copy_bulletins", formsemestre_id)
|
||||
intro_mail = sco_preferences.get_preference("bul_intro_mail", formsemestre_id)
|
||||
|
||||
if intro_mail:
|
||||
hea = intro_mail % {
|
||||
|
@ -1000,7 +988,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||
else:
|
||||
hea = ""
|
||||
|
||||
if sco_preferences.get_preference(context, "bul_mail_list_abs"):
|
||||
if sco_preferences.get_preference("bul_mail_list_abs"):
|
||||
hea += "\n\n" + sco_abs_views.ListeAbsEtud(
|
||||
context, etud["etudid"], with_evals=False, format="text"
|
||||
)
|
||||
|
@ -1009,9 +997,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||
subj = Header("Relevé de notes de %s" % etud["nomprenom"], scu.SCO_ENCODING)
|
||||
recipients = [recipient_addr]
|
||||
msg["Subject"] = subj
|
||||
msg["From"] = sco_preferences.get_preference(
|
||||
context, "email_from_addr", formsemestre_id
|
||||
)
|
||||
msg["From"] = sco_preferences.get_preference("email_from_addr", formsemestre_id)
|
||||
msg["To"] = " ,".join(recipients)
|
||||
if copy_addr:
|
||||
msg["Bcc"] = copy_addr.strip()
|
||||
|
@ -1045,9 +1031,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
uid = str(authuser)
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
page_title="Bulletin de %(nomprenom)s" % etud,
|
||||
REQUEST=REQUEST,
|
||||
javascripts=[
|
||||
"js/bulletin.js",
|
||||
"libjs/d3.v3.min.js",
|
||||
|
@ -1128,7 +1112,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
},
|
||||
"enabled": etud["email"]
|
||||
and can_send_bulletin_by_mail(
|
||||
context, formsemestre_id, REQUEST
|
||||
context, formsemestre_id
|
||||
), # possible slt si on a un mail...
|
||||
},
|
||||
{
|
||||
|
@ -1143,7 +1127,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
},
|
||||
"enabled": etud["emailperso"]
|
||||
and can_send_bulletin_by_mail(
|
||||
context, formsemestre_id, REQUEST
|
||||
context, formsemestre_id
|
||||
), # possible slt si on a un mail...
|
||||
},
|
||||
{
|
||||
|
@ -1184,9 +1168,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
"formsemestre_id": formsemestre_id,
|
||||
"etudid": etudid,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_validate_sem(
|
||||
context, REQUEST, formsemestre_id
|
||||
),
|
||||
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
|
||||
},
|
||||
{
|
||||
"title": "Enregistrer note d'une UE externe",
|
||||
|
@ -1195,9 +1177,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
"formsemestre_id": formsemestre_id,
|
||||
"etudid": etudid,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_validate_sem(
|
||||
context, REQUEST, formsemestre_id
|
||||
),
|
||||
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
|
||||
},
|
||||
{
|
||||
"title": "Entrer décisions jury",
|
||||
|
@ -1206,9 +1186,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||
"formsemestre_id": formsemestre_id,
|
||||
"etudid": etudid,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_validate_sem(
|
||||
context, REQUEST, formsemestre_id
|
||||
),
|
||||
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
|
||||
},
|
||||
{
|
||||
"title": "Editer PV jury",
|
||||
|
|
|
@ -89,9 +89,7 @@ def bulletin_get_class_name_displayed(context, formsemestre_id):
|
|||
"""Le nom du générateur utilisé, en clair"""
|
||||
from app.scodoc import sco_preferences
|
||||
|
||||
bul_class_name = sco_preferences.get_preference(
|
||||
context, "bul_class_name", formsemestre_id
|
||||
)
|
||||
bul_class_name = sco_preferences.get_preference("bul_class_name", formsemestre_id)
|
||||
try:
|
||||
gen_class = bulletin_get_class(bul_class_name)
|
||||
return gen_class.description
|
||||
|
@ -127,7 +125,7 @@ class BulletinGenerator(object):
|
|||
self.server_name = server_name
|
||||
# Store preferences for convenience:
|
||||
formsemestre_id = self.infos["formsemestre_id"]
|
||||
self.preferences = sco_preferences.SemPreferences(context, formsemestre_id)
|
||||
self.preferences = sco_preferences.SemPreferences(formsemestre_id)
|
||||
self.diagnostic = None # error message if any problem
|
||||
# Common PDF styles:
|
||||
# - Pour tous les champs du bulletin sauf les cellules de table:
|
||||
|
@ -231,9 +229,7 @@ class BulletinGenerator(object):
|
|||
margins=self.margins,
|
||||
server_name=self.server_name,
|
||||
filigranne=self.filigranne,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
self.context, formsemestre_id
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
@ -285,9 +281,7 @@ def make_formsemestre_bulletinetud(
|
|||
raise ValueError("invalid version code !")
|
||||
|
||||
formsemestre_id = infos["formsemestre_id"]
|
||||
bul_class_name = sco_preferences.get_preference(
|
||||
context, "bul_class_name", formsemestre_id
|
||||
)
|
||||
bul_class_name = sco_preferences.get_preference("bul_class_name", formsemestre_id)
|
||||
try:
|
||||
gen_class = bulletin_get_class(bul_class_name)
|
||||
except:
|
||||
|
|
|
@ -70,7 +70,7 @@ def make_json_formsemestre_bulletinetud(
|
|||
if REQUEST:
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
||||
|
||||
return json.dumps(d, cls=scu.ScoDocJSONEncoder, encoding=scu.SCO_ENCODING)
|
||||
return json.dumps(d, cls=scu.ScoDocJSONEncoder)
|
||||
|
||||
|
||||
# (fonction séparée: n'utilise pas formsemestre_bulletinetud_dict()
|
||||
|
@ -158,8 +158,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
if (
|
||||
nt.get_moduleimpls_attente()
|
||||
or sco_preferences.get_preference(context, "bul_show_rangs", formsemestre_id)
|
||||
== 0
|
||||
or sco_preferences.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||
):
|
||||
# n'affiche pas le rang sur le bulletin s'il y a des
|
||||
# notes en attente dans ce semestre
|
||||
|
@ -254,9 +253,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||
m["note"][k] = scu.fmt_note(m["note"][k])
|
||||
|
||||
u["module"].append(m)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_mod_rangs", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||
m["rang"] = dict(
|
||||
value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]
|
||||
)
|
||||
|
@ -293,10 +290,10 @@ def formsemestre_bulletinetud_published_dict(
|
|||
# Evaluations incomplètes ou futures:
|
||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_all_evals", formsemestre_id
|
||||
"bul_show_all_evals", formsemestre_id
|
||||
):
|
||||
all_evals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
)
|
||||
all_evals.reverse() # plus ancienne d'abord
|
||||
for e in all_evals:
|
||||
|
@ -338,13 +335,13 @@ def formsemestre_bulletinetud_published_dict(
|
|||
)
|
||||
|
||||
# --- Absences
|
||||
if sco_preferences.get_preference(context, "bul_show_abs", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust)
|
||||
|
||||
# --- Decision Jury
|
||||
if (
|
||||
sco_preferences.get_preference(context, "bul_show_decision", formsemestre_id)
|
||||
sco_preferences.get_preference("bul_show_decision", formsemestre_id)
|
||||
or xml_with_decisions
|
||||
):
|
||||
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
|
||||
|
@ -353,7 +350,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||
formsemestre_id,
|
||||
format="xml",
|
||||
show_uevalid=sco_preferences.get_preference(
|
||||
context, "bul_show_uevalid", formsemestre_id
|
||||
"bul_show_uevalid", formsemestre_id
|
||||
),
|
||||
)
|
||||
d["situation"] = scu.quote_xml_attr(infos["situation"])
|
||||
|
@ -377,7 +374,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||
d["decision_ue"] = []
|
||||
if decision[
|
||||
"decisions_ue"
|
||||
]: # and sco_preferences.get_preference(context, 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||
for ue_id in decision["decisions_ue"].keys():
|
||||
ue = sco_edit_ue.do_ue_list(context, {"ue_id": ue_id})[0]
|
||||
d["decision_ue"].append(
|
||||
|
|
|
@ -88,7 +88,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||
context = self.context
|
||||
|
||||
bul_show_abs_modules = sco_preferences.get_preference(
|
||||
context, "bul_show_abs_modules", formsemestre_id
|
||||
"bul_show_abs_modules", formsemestre_id
|
||||
)
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
@ -103,7 +103,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||
|
||||
H = ['<table class="notes_bulletin" style="background-color: %s;">' % bgcolor]
|
||||
|
||||
if sco_preferences.get_preference(context, "bul_show_minmax", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
|
||||
minmax = (
|
||||
'<span class="bul_minmax" title="[min, max] promo">[%s, %s]</span>'
|
||||
% (I["moy_min"], I["moy_max"])
|
||||
|
@ -129,7 +129,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||
continue # saute les modules où on n'est pas inscrit
|
||||
H.append('<tr class="notes_bulletin_row_mod%s">' % rowstyle)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_minmax_mod", formsemestre_id
|
||||
"bul_show_minmax_mod", formsemestre_id
|
||||
):
|
||||
rang_minmax = '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>' % (
|
||||
mod["mod_rang_txt"],
|
||||
|
@ -178,7 +178,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||
plusminus = minuslink #
|
||||
if ue["ue_status"]["is_capitalized"]:
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_ue_cap_details", formsemestre_id
|
||||
"bul_show_ue_cap_details", formsemestre_id
|
||||
):
|
||||
plusminus = minuslink
|
||||
hide = ""
|
||||
|
@ -209,9 +209,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||
)
|
||||
|
||||
H.append('<tr class="notes_bulletin_row_ue">')
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_minmax", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
|
||||
moy_txt = (
|
||||
'%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
|
||||
% (
|
||||
|
@ -448,10 +446,10 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||
P = [] # elems pour gen. pdf
|
||||
formsemestre_id = I["formsemestre_id"]
|
||||
bul_show_abs_modules = sco_preferences.get_preference(
|
||||
context, "bul_show_abs_modules", formsemestre_id
|
||||
"bul_show_abs_modules", formsemestre_id
|
||||
)
|
||||
|
||||
if sco_preferences.get_preference(context, "bul_show_minmax", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
|
||||
minmax = ' <font size="8">[%s, %s]</font>' % (I["moy_min"], I["moy_max"])
|
||||
else:
|
||||
minmax = ""
|
||||
|
@ -473,9 +471,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||
if mod["mod_moy_txt"] == "NI":
|
||||
continue # saute les modules où on n'est pas inscrit
|
||||
S.modline(ue_type=ue_type)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_minmax_mod", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_minmax_mod", formsemestre_id):
|
||||
rang_minmax = '%s <font size="8">[%s, %s]</font>' % (
|
||||
mod["mod_rang_txt"],
|
||||
scu.fmt_note(mod["stats"]["min"]),
|
||||
|
@ -516,12 +512,12 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||
ue_descr = "(en cours, non prise en compte)"
|
||||
S.ueline()
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_ue_cap_details", formsemestre_id
|
||||
"bul_show_ue_cap_details", formsemestre_id
|
||||
):
|
||||
list_modules(ue["modules_capitalized"])
|
||||
ue_type = "cur"
|
||||
|
||||
if sco_preferences.get_preference(context, "bul_show_minmax", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
|
||||
moy_txt = '%s <font size="8">[%s, %s]</font>' % (
|
||||
ue["cur_moy_ue_txt"],
|
||||
ue["min"],
|
||||
|
|
|
@ -86,10 +86,10 @@ def pdfassemblebulletins(
|
|||
return ""
|
||||
# Paramètres de mise en page
|
||||
margins = (
|
||||
sco_preferences.get_preference(context, "left_margin", formsemestre_id),
|
||||
sco_preferences.get_preference(context, "top_margin", formsemestre_id),
|
||||
sco_preferences.get_preference(context, "right_margin", formsemestre_id),
|
||||
sco_preferences.get_preference(context, "bottom_margin", formsemestre_id),
|
||||
sco_preferences.get_preference("left_margin", formsemestre_id),
|
||||
sco_preferences.get_preference("top_margin", formsemestre_id),
|
||||
sco_preferences.get_preference("right_margin", formsemestre_id),
|
||||
sco_preferences.get_preference("bottom_margin", formsemestre_id),
|
||||
)
|
||||
|
||||
report = StringIO.StringIO() # in-memory document, no disk file
|
||||
|
@ -105,7 +105,7 @@ def pdfassemblebulletins(
|
|||
margins=margins,
|
||||
pagesbookmarks=pagesbookmarks,
|
||||
filigranne=filigranne,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
@ -194,9 +194,7 @@ def get_formsemestre_bulletins_pdf(
|
|||
bookmarks[i] = scu.suppress_accents(nt.get_sexnom(etudid))
|
||||
i = i + 1
|
||||
#
|
||||
infos = {
|
||||
"DeptName": sco_preferences.get_preference(context, "DeptName", formsemestre_id)
|
||||
}
|
||||
infos = {"DeptName": sco_preferences.get_preference("DeptName", formsemestre_id)}
|
||||
if REQUEST:
|
||||
server_name = REQUEST.BASE0
|
||||
else:
|
||||
|
@ -248,7 +246,7 @@ def get_etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
|
|||
filigrannes[i] = filigranne
|
||||
bookmarks[i] = sem["session_id"] # eg RT-DUT-FI-S1-2015
|
||||
i = i + 1
|
||||
infos = {"DeptName": sco_preferences.get_preference(context, "DeptName")}
|
||||
infos = {"DeptName": sco_preferences.get_preference("DeptName")}
|
||||
if REQUEST:
|
||||
server_name = REQUEST.BASE0
|
||||
else:
|
||||
|
|
|
@ -97,7 +97,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||
columns_ids=colkeys,
|
||||
pdf_table_style=pdf_style,
|
||||
pdf_col_widths=[colWidths[k] for k in colkeys],
|
||||
preferences=sco_preferences.SemPreferences(self.context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
html_class="notes_bulletin",
|
||||
html_class_ignore_default=True,
|
||||
html_with_td_classes=True,
|
||||
|
@ -278,7 +278,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||
context = self.context
|
||||
P = [] # elems pour générer table avec gen_table (liste de dicts)
|
||||
formsemestre_id = I["formsemestre_id"]
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||
|
||||
# Colonnes à afficher:
|
||||
with_col_abs = prefs["bul_show_abs_modules"]
|
||||
|
@ -667,9 +667,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||
else:
|
||||
t["_module_colspan"] = 2
|
||||
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
|
||||
etat = sco_evaluations.do_evaluation_etat(
|
||||
self.context, e["evaluation_id"]
|
||||
)
|
||||
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||
if prefs["bul_show_minmax_eval"]:
|
||||
t["min"] = scu.fmt_note(etat["mini"])
|
||||
t["max"] = scu.fmt_note(etat["maxi"])
|
||||
|
|
|
@ -72,7 +72,7 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
|||
I = self.infos
|
||||
context = self.context
|
||||
formsemestre_id = I["formsemestre_id"]
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||
|
||||
P = [] # elems pour générer table avec gen_table (liste de dicts)
|
||||
|
||||
|
@ -192,7 +192,7 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
|||
# --- UE capitalisée:
|
||||
if ue["ue_status"]["is_capitalized"]:
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_ue_cap_details", formsemestre_id
|
||||
"bul_show_ue_cap_details", formsemestre_id
|
||||
):
|
||||
nb_modules = len(ue["modules_capitalized"])
|
||||
hidden = False
|
||||
|
|
|
@ -151,8 +151,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
if (
|
||||
nt.get_moduleimpls_attente()
|
||||
or sco_preferences.get_preference(context, "bul_show_rangs", formsemestre_id)
|
||||
== 0
|
||||
or sco_preferences.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||
):
|
||||
# n'affiche pas le rang sur le bulletin s'il y a des
|
||||
# notes en attente dans ce semestre
|
||||
|
@ -255,9 +254,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||
moy=scu.fmt_note(modstat["moy"]),
|
||||
)
|
||||
)
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_mod_rangs", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||
x_mod.append(
|
||||
Element(
|
||||
"rang",
|
||||
|
@ -298,10 +295,10 @@ def make_xml_formsemestre_bulletinetud(
|
|||
# Evaluations incomplètes ou futures:
|
||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_show_all_evals", formsemestre_id
|
||||
"bul_show_all_evals", formsemestre_id
|
||||
):
|
||||
all_evals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||
)
|
||||
all_evals.reverse() # plus ancienne d'abord
|
||||
for e in all_evals:
|
||||
|
@ -349,12 +346,12 @@ def make_xml_formsemestre_bulletinetud(
|
|||
)
|
||||
|
||||
# --- Absences
|
||||
if sco_preferences.get_preference(context, "bul_show_abs", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
doc.append(Element("absences", nbabs=nbabs, nbabsjust=nbabsjust))
|
||||
# --- Decision Jury
|
||||
if (
|
||||
sco_preferences.get_preference(context, "bul_show_decision", formsemestre_id)
|
||||
sco_preferences.get_preference("bul_show_decision", formsemestre_id)
|
||||
or xml_with_decisions
|
||||
):
|
||||
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
|
||||
|
@ -363,7 +360,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||
formsemestre_id,
|
||||
format="xml",
|
||||
show_uevalid=sco_preferences.get_preference(
|
||||
context, "bul_show_uevalid", formsemestre_id
|
||||
"bul_show_uevalid", formsemestre_id
|
||||
),
|
||||
)
|
||||
x_situation = Element("situation")
|
||||
|
@ -395,7 +392,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||
|
||||
if decision[
|
||||
"decisions_ue"
|
||||
]: # and sco_preferences.get_preference(context, 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||
for ue_id in decision["decisions_ue"].keys():
|
||||
ue = sco_edit_ue.do_ue_list(context, {"ue_id": ue_id})[0]
|
||||
doc.append(
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
"""Gestion des caches
|
||||
|
||||
Ré-écrite pour ScoDoc8, utilise flask_caching et memcached
|
||||
Ré-écrite pour ScoDoc8, utilise flask_caching et REDIS
|
||||
|
||||
ScoDoc est maintenant multiprocessus / mono-thread, avec un cache en mémoire partagé.
|
||||
"""
|
||||
|
@ -55,6 +55,7 @@
|
|||
#
|
||||
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from flask import g
|
||||
|
||||
|
@ -80,16 +81,25 @@ class ScoDocCache:
|
|||
@classmethod
|
||||
def get(cls, oid):
|
||||
"""Returns cached evaluation, or None"""
|
||||
return CACHE.get(cls._get_key(oid))
|
||||
try:
|
||||
return CACHE.get(cls._get_key(oid))
|
||||
except:
|
||||
log("XXX CACHE Warning: error in get")
|
||||
log(traceback.format_exc())
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def set(cls, oid, value):
|
||||
"""Store value"""
|
||||
key = cls._get_key(oid)
|
||||
# log(f"CACHE key={key}, timeout={cls.timeout}")
|
||||
status = CACHE.set(key, value, timeout=cls.timeout)
|
||||
if not status:
|
||||
log("Error: cache set failed !")
|
||||
# log(f"CACHE key={key}, type={type(value)}, timeout={cls.timeout}")
|
||||
try:
|
||||
status = CACHE.set(key, value, timeout=cls.timeout)
|
||||
if not status:
|
||||
log("Error: cache set failed !")
|
||||
except:
|
||||
log("XXX CACHE Warning: error in set !!!")
|
||||
|
||||
return status
|
||||
|
||||
@classmethod
|
||||
|
@ -122,8 +132,7 @@ class EvaluationCache(ScoDocCache):
|
|||
WHERE s.formsemestre_id = %(formsemestre_id)s and s.formsemestre_id=m.formsemestre_id and e.moduleimpl_id=m.moduleimpl_id;
|
||||
"""
|
||||
evaluation_ids = [
|
||||
x[0]
|
||||
for x in ndb.SimpleQuery(None, req, {"formsemestre_id": formsemestre_id})
|
||||
x[0] for x in ndb.SimpleQuery(req, {"formsemestre_id": formsemestre_id})
|
||||
]
|
||||
cls.delete_many(evaluation_ids)
|
||||
|
||||
|
@ -132,9 +141,7 @@ class EvaluationCache(ScoDocCache):
|
|||
"delete all evaluations from cache"
|
||||
evaluation_ids = [
|
||||
x[0]
|
||||
for x in ndb.SimpleQuery(
|
||||
None, "SELECT evaluation_id FROM notes_evaluation", ""
|
||||
)
|
||||
for x in ndb.SimpleQuery("SELECT evaluation_id FROM notes_evaluation", "")
|
||||
]
|
||||
cls.delete_many(evaluation_ids)
|
||||
|
||||
|
@ -196,19 +203,30 @@ class NotesTableCache(ScoDocCache):
|
|||
@classmethod
|
||||
def get(cls, formsemestre_id, compute=True):
|
||||
"""Returns NotesTable for this formsemestre
|
||||
Search in local cache (g.nt_cache) or global app cache (eg REDIS)
|
||||
If not in cache and compute is True, build it and cache it.
|
||||
"""
|
||||
# try local cache (same request)
|
||||
if not hasattr(g, "nt_cache"):
|
||||
g.nt_cache = {}
|
||||
else:
|
||||
if formsemestre_id in g.nt_cache:
|
||||
return g.nt_cache[formsemestre_id]
|
||||
# try REDIS
|
||||
key = cls._get_key(formsemestre_id)
|
||||
nt = CACHE.get(key)
|
||||
if nt or not compute:
|
||||
return nt
|
||||
# Recompute asked table:
|
||||
from app.scodoc import notes_table
|
||||
|
||||
t0 = time.time()
|
||||
nt = notes_table.NotesTable(None, formsemestre_id)
|
||||
context = None # XXX TO REMOVE #context
|
||||
nt = notes_table.NotesTable(context, formsemestre_id)
|
||||
dt = time.time() - t0
|
||||
log("caching formsemestre_id=%s (%gs)" % (formsemestre_id, dt))
|
||||
_ = cls.set(formsemestre_id, nt)
|
||||
g.nt_cache[formsemestre_id] = nt
|
||||
return nt
|
||||
|
||||
|
||||
|
@ -227,7 +245,7 @@ def invalidate_formsemestre( # was inval_cache( context, formsemestre_id=None,
|
|||
formsemestre_ids = [
|
||||
x[0]
|
||||
for x in ndb.SimpleQuery(
|
||||
None, "SELECT formsemestre_id FROM notes_formsemestre", ""
|
||||
"SELECT formsemestre_id FROM notes_formsemestre", ""
|
||||
)
|
||||
]
|
||||
else:
|
||||
|
@ -240,11 +258,15 @@ def invalidate_formsemestre( # was inval_cache( context, formsemestre_id=None,
|
|||
# Delete cached notes and evaluations
|
||||
NotesTableCache.delete_many(formsemestre_ids)
|
||||
if formsemestre_id:
|
||||
for formsemestre_id in formsemestre_ids:
|
||||
EvaluationCache.invalidate_sem(formsemestre_id)
|
||||
for fid in formsemestre_ids:
|
||||
EvaluationCache.invalidate_sem(fid)
|
||||
if hasattr(g, "nt_cache") and fid in g.nt_cache:
|
||||
del g.nt_cache[fid]
|
||||
else:
|
||||
# optimization when we invalidate all evaluations:
|
||||
EvaluationCache.invalidate_all_sems()
|
||||
if hasattr(g, "nt_cache"):
|
||||
del g.nt_cache
|
||||
SemInscriptionsCache.delete_many(formsemestre_ids)
|
||||
|
||||
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
|
||||
|
|
|
@ -228,7 +228,7 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||
for e in evals:
|
||||
e["nb_inscrits"] = e["etat"]["nb_inscrits"]
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, e["evaluation_id"]
|
||||
e["evaluation_id"]
|
||||
) # toutes, y compris demissions
|
||||
# restreint aux étudiants encore inscrits à ce module
|
||||
notes = [
|
||||
|
|
|
@ -58,7 +58,7 @@ def formsemestre_table_estim_cost(
|
|||
(dans ce cas, retoucher le tableau excel exporté).
|
||||
"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
sco_formsemestre_status.fill_formsemestre(context, sem, REQUEST=REQUEST)
|
||||
sco_formsemestre_status.fill_formsemestre(sem)
|
||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||
context, formsemestre_id=formsemestre_id
|
||||
)
|
||||
|
@ -121,7 +121,7 @@ def formsemestre_table_estim_cost(
|
|||
),
|
||||
rows=T,
|
||||
html_sortable=True,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
html_class="table_leftalign table_listegroupe",
|
||||
xls_before_table=[
|
||||
["%(titre)s %(num_sem)s %(modalitestr)s" % sem],
|
||||
|
|
|
@ -82,7 +82,7 @@ def get_etudids_with_debouche(context, start_year):
|
|||
start_date = str(start_year) + "-01-01"
|
||||
# Recupere tous les etudid avec un debouché renseigné et une inscription dans un semestre
|
||||
# posterieur à la date de depart:
|
||||
# r = ndb.SimpleDictFetch(context,
|
||||
# r = ndb.SimpleDictFetch(
|
||||
# """SELECT DISTINCT i.etudid
|
||||
# FROM notes_formsemestre_inscription i, admissions adm, notes_formsemestre s
|
||||
# WHERE adm.debouche is not NULL
|
||||
|
@ -92,7 +92,6 @@ def get_etudids_with_debouche(context, start_year):
|
|||
# {'start_date' : start_date })
|
||||
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT DISTINCT i.etudid
|
||||
FROM notes_formsemestre_inscription i, notes_formsemestre s, itemsuivi it
|
||||
WHERE i.etudid = it.etudid
|
||||
|
@ -189,9 +188,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||
# html_col_width='4em',
|
||||
html_sortable=True,
|
||||
html_class="table_leftalign table_listegroupe",
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return tab
|
||||
|
||||
|
@ -199,11 +196,11 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||
def report_debouche_ask_date(context, REQUEST=None):
|
||||
"""Formulaire demande date départ"""
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ """<form method="GET">
|
||||
Date de départ de la recherche: <input type="text" name="start_year" value="" size=10/>
|
||||
</form>"""
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
|
||||
|
@ -213,22 +210,6 @@ def report_debouche_ask_date(context, REQUEST=None):
|
|||
#
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# OBSOLETE (this field has been copied to itemsuivi)
|
||||
# def debouche_set(context, object, value, REQUEST=None):
|
||||
# """Set debouche (field in admission table, may be deprecated ?)
|
||||
# """
|
||||
# if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
# raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
# adm_id = object
|
||||
# debouche = value.strip('-_ \t')
|
||||
# cnx = ndb.GetDBConnexion()
|
||||
# adms = sco_etud.admission_list(cnx, {'etudid' : etudid})
|
||||
# if not adms:
|
||||
# raise ValueError('no admission info for %s !' % etudid)
|
||||
# adm = adms[0]
|
||||
# adm['debouche'] = debouche
|
||||
# admission_edit(cnx, adm)
|
||||
|
||||
|
||||
_itemsuiviEditor = ndb.EditableTable(
|
||||
"itemsuivi",
|
||||
|
@ -269,13 +250,13 @@ def itemsuivi_get(cnx, itemsuivi_id, ignore_errors=False):
|
|||
|
||||
def itemsuivi_suppress(context, itemsuivi_id, REQUEST=None):
|
||||
"""Suppression d'un item"""
|
||||
if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if not sco_permissions_check.can_edit_suivi():
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
cnx = ndb.GetDBConnexion()
|
||||
item = itemsuivi_get(cnx, itemsuivi_id, ignore_errors=True)
|
||||
if item:
|
||||
_itemsuivi_delete(cnx, itemsuivi_id)
|
||||
logdb(REQUEST, cnx, method="itemsuivi_suppress", etudid=item["etudid"])
|
||||
logdb(cnx, method="itemsuivi_suppress", etudid=item["etudid"])
|
||||
log("suppressed itemsuivi %s" % (itemsuivi_id,))
|
||||
|
||||
|
||||
|
@ -283,13 +264,13 @@ def itemsuivi_create(
|
|||
context, etudid, item_date=None, situation="", REQUEST=None, format=None
|
||||
):
|
||||
"""Creation d'un item"""
|
||||
if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if not sco_permissions_check.can_edit_suivi():
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
cnx = ndb.GetDBConnexion()
|
||||
itemsuivi_id = _itemsuivi_create(
|
||||
cnx, args={"etudid": etudid, "item_date": item_date, "situation": situation}
|
||||
)
|
||||
logdb(REQUEST, cnx, method="itemsuivi_create", etudid=etudid)
|
||||
logdb(cnx, method="itemsuivi_create", etudid=etudid)
|
||||
log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
|
||||
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||
if format == "json":
|
||||
|
@ -301,7 +282,7 @@ def itemsuivi_set_date(context, itemsuivi_id, item_date, REQUEST=None):
|
|||
"""set item date
|
||||
item_date is a string dd/mm/yyyy
|
||||
"""
|
||||
if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if not sco_permissions_check.can_edit_suivi():
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
# log('itemsuivi_set_date %s : %s' % (itemsuivi_id, item_date))
|
||||
cnx = ndb.GetDBConnexion()
|
||||
|
@ -312,7 +293,7 @@ def itemsuivi_set_date(context, itemsuivi_id, item_date, REQUEST=None):
|
|||
|
||||
def itemsuivi_set_situation(context, object, value, REQUEST=None):
|
||||
"""set situation"""
|
||||
if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if not sco_permissions_check.can_edit_suivi():
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
itemsuivi_id = object
|
||||
situation = value.strip("-_ \t")
|
||||
|
@ -338,7 +319,6 @@ def itemsuivi_list_etud(context, etudid, format=None, REQUEST=None):
|
|||
def itemsuivi_tag_list(context, itemsuivi_id):
|
||||
"""les noms de tags associés à cet item"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT t.title
|
||||
FROM itemsuivi_tags_assoc a, itemsuivi_tags t
|
||||
WHERE a.tag_id = t.tag_id
|
||||
|
@ -356,7 +336,6 @@ def itemsuivi_tag_search(context, term, REQUEST=None):
|
|||
data = []
|
||||
else:
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT title FROM itemsuivi_tags WHERE title LIKE %(term)s",
|
||||
{"term": term + "%"},
|
||||
)
|
||||
|
@ -370,7 +349,7 @@ def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None):
|
|||
a string with tag names separated by commas ("un;deux")
|
||||
or a list of strings (["un", "deux"])
|
||||
"""
|
||||
if not sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if not sco_permissions_check.can_edit_suivi():
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
if not taglist:
|
||||
taglist = []
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"""
|
||||
|
||||
from flask import g
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
|
@ -49,9 +50,7 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
|||
H = []
|
||||
|
||||
# News:
|
||||
# 2020-12-30: abandonne l'icon rss
|
||||
# rssicon = scu.icontag("rssscodoc_img", title="Flux RSS", border="0")
|
||||
H.append(sco_news.scolar_news_summary_html(context)) # , rssicon=rssicon))
|
||||
H.append(sco_news.scolar_news_summary_html(context))
|
||||
|
||||
# Avertissement de mise à jour:
|
||||
H.append(sco_up_to_date.html_up_to_date_box(context))
|
||||
|
@ -112,7 +111,7 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
|||
# aucun semestre courant: affiche aide
|
||||
H.append(
|
||||
"""<h2 class="listesems">Aucune session en cours !</h2>
|
||||
<p>Pour ajouter une session, aller dans <a href="Notes">Programmes</a>,
|
||||
<p>Pour ajouter une session, aller dans <a href="Notes" id="link-programmes">Programmes</a>,
|
||||
choisissez une formation, puis suivez le lien "<em>UE, modules, semestres</em>".
|
||||
</p><p>
|
||||
Là, en bas de page, suivez le lien
|
||||
|
@ -125,7 +124,7 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
|||
"""<hr/>
|
||||
<h2>Semestres de %s</h2>
|
||||
"""
|
||||
% sco_preferences.get_preference(context, "DeptName")
|
||||
% sco_preferences.get_preference("DeptName")
|
||||
)
|
||||
H.append(_sem_table_gt(context, sems).html())
|
||||
H.append("</table>")
|
||||
|
@ -144,8 +143,7 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8" spellchec
|
|||
% scu.NotesURL()
|
||||
)
|
||||
#
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
if authuser.has_permission(Permission.ScoEtudInscrit):
|
||||
if current_user.has_permission(Permission.ScoEtudInscrit):
|
||||
H.append(
|
||||
"""<hr>
|
||||
<h3>Gestion des étudiants</h3>
|
||||
|
@ -158,7 +156,7 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8" spellchec
|
|||
"""
|
||||
)
|
||||
#
|
||||
if authuser.has_permission(Permission.ScoEditApo):
|
||||
if current_user.has_permission(Permission.ScoEditApo):
|
||||
H.append(
|
||||
"""<hr>
|
||||
<h3>Exports Apogée</h3>
|
||||
|
@ -178,11 +176,7 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8" spellchec
|
|||
"""
|
||||
)
|
||||
#
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
+ "\n".join(H)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def _sem_table(context, sems):
|
||||
|
@ -250,9 +244,7 @@ def _sem_table_gt(context, sems, showcodes=False):
|
|||
html_sortable=True,
|
||||
# base_url = '%s?formsemestre_id=%s' % (REQUEST.URL0, formsemestre_id),
|
||||
# caption='Maquettes enregistrées',
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
|
||||
return tab
|
||||
|
|
|
@ -66,11 +66,9 @@ SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
|||
|
||||
def sco_dump_and_send_db(context, REQUEST=None):
|
||||
"""Dump base de données du département courant et l'envoie anonymisée pour debug"""
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title="Assistance technique")
|
||||
]
|
||||
H = [html_sco_header.sco_header(page_title="Assistance technique")]
|
||||
# get currect (dept) DB name:
|
||||
cursor = ndb.SimpleQuery(context, "SELECT current_database()", {})
|
||||
cursor = ndb.SimpleQuery("SELECT current_database()", {})
|
||||
db_name = cursor.fetchone()[0]
|
||||
ano_db_name = "ANO" + db_name
|
||||
# Lock
|
||||
|
@ -125,7 +123,7 @@ def sco_dump_and_send_db(context, REQUEST=None):
|
|||
fcntl.flock(x, fcntl.LOCK_UN)
|
||||
|
||||
log("sco_dump_and_send_db: done.")
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def _duplicate_db(db_name, ano_db_name):
|
||||
|
@ -190,7 +188,7 @@ def _send_db(context, REQUEST, ano_db_name):
|
|||
scu.SCO_DUMP_UP_URL,
|
||||
files=files,
|
||||
data={
|
||||
"dept_name": sco_preferences.get_preference(context, "DeptName"),
|
||||
"dept_name": sco_preferences.get_preference("DeptName"),
|
||||
"serial": _get_scodoc_serial(context),
|
||||
"sco_user": str(REQUEST.AUTHENTICATED_USER),
|
||||
"sent_by": sco_users.user_info(str(REQUEST.AUTHENTICATED_USER))[
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
"""Ajout/Modification/Supression formations
|
||||
(portage from DTML)
|
||||
"""
|
||||
import flask
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -52,9 +54,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
|||
F = F[0]
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Suppression d'une formation"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Suppression d'une formation"),
|
||||
"""<h2>Suppression de la formation %(titre)s (%(acronyme)s)</h2>""" % F,
|
||||
]
|
||||
|
||||
|
@ -75,30 +75,28 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
|||
else:
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Confirmer la suppression de la formation %(titre)s (%(acronyme)s) ?</h2>
|
||||
<p><b>Attention:</b> la suppression d'une formation est <b>irréversible</b> et implique la supression de toutes les UE, matières et modules de la formation !
|
||||
</p>
|
||||
"""
|
||||
% F,
|
||||
REQUEST=REQUEST,
|
||||
OK="Supprimer cette formation",
|
||||
cancel_url=scu.NotesURL(),
|
||||
parameters={"formation_id": formation_id},
|
||||
)
|
||||
else:
|
||||
do_formation_delete(context, F["formation_id"], REQUEST)
|
||||
do_formation_delete(context, F["formation_id"])
|
||||
H.append(
|
||||
"""<p>OK, formation supprimée.</p>
|
||||
<p><a class="stdlink" href="%s">continuer</a></p>"""
|
||||
% scu.NotesURL()
|
||||
)
|
||||
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def do_formation_delete(context, oid, REQUEST):
|
||||
def do_formation_delete(context, oid):
|
||||
"""delete a formation (and all its UE, matieres, modules)
|
||||
XXX delete all ues, will break if there are validations ! USE WITH CARE !
|
||||
"""
|
||||
|
@ -109,17 +107,16 @@ def do_formation_delete(context, oid, REQUEST):
|
|||
# delete all UE in this formation
|
||||
ues = sco_edit_ue.do_ue_list(context, {"formation_id": oid})
|
||||
for ue in ues:
|
||||
sco_edit_ue.do_ue_delete(context, ue["ue_id"], REQUEST=REQUEST, force=True)
|
||||
sco_edit_ue.do_ue_delete(context, ue["ue_id"], force=True)
|
||||
|
||||
sco_formations._formationEditor.delete(cnx, oid)
|
||||
|
||||
# news
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=oid,
|
||||
text="Suppression de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
|
||||
|
||||
|
@ -132,9 +129,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
|||
"""Edit or create a formation"""
|
||||
if create:
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Création d'une formation"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Création d'une formation"),
|
||||
"""<h2>Création d'une formation</h2>
|
||||
|
||||
<p class="help">Une "formation" décrit une filière, comme un DUT ou une Licence. La formation se subdivise en unités pédagogiques (UE, matières, modules). Elle peut se diviser en plusieurs semestres (ou sessions), qui seront mis en place séparément.
|
||||
|
@ -156,9 +151,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
|||
is_locked = sco_formations.formation_has_locked_sems(context, formation_id)
|
||||
submitlabel = "Modifier les valeurs"
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Modification d'une formation"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Modification d'une formation"),
|
||||
"""<h2>Modification de la formation %(acronyme)s</h2>""" % initvalues,
|
||||
]
|
||||
if is_locked:
|
||||
|
@ -228,9 +221,9 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
|||
submitlabel=submitlabel,
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(scu.NotesURL())
|
||||
return flask.redirect(scu.NotesURL())
|
||||
else:
|
||||
# check unicity : constraint UNIQUE(acronyme,titre,version)
|
||||
if create:
|
||||
|
@ -251,17 +244,17 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
|||
"Valeurs incorrectes: il existe déjà une formation avec même titre, acronyme et version."
|
||||
)
|
||||
+ tf[1]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
#
|
||||
if create:
|
||||
formation_id = do_formation_create(context, tf[2], REQUEST)
|
||||
formation_id = do_formation_create(context, tf[2])
|
||||
else:
|
||||
do_formation_edit(context, tf[2])
|
||||
return REQUEST.RESPONSE.redirect("ue_list?formation_id=%s" % formation_id)
|
||||
return flask.redirect("ue_list?formation_id=%s" % formation_id)
|
||||
|
||||
|
||||
def do_formation_create(context, args, REQUEST):
|
||||
def do_formation_create(context, args):
|
||||
"create a formation"
|
||||
cnx = ndb.GetDBConnexion()
|
||||
# check unique acronyme/titre/version
|
||||
|
@ -279,10 +272,9 @@ def do_formation_create(context, args, REQUEST):
|
|||
r = sco_formations._formationEditor.create(cnx, args)
|
||||
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
text="Création de la formation %(titre)s (%(acronyme)s)" % args,
|
||||
max_frequency=3,
|
||||
)
|
||||
return r
|
||||
|
||||
|
@ -348,7 +340,7 @@ def module_move(context, module_id, after=0, REQUEST=None, redirect=1):
|
|||
|
||||
# redirect to ue_list page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect("ue_list?formation_id=" + formation_id)
|
||||
return flask.redirect("ue_list?formation_id=" + formation_id)
|
||||
|
||||
|
||||
def ue_move(context, ue_id, after=0, REQUEST=None, redirect=1):
|
||||
|
@ -379,4 +371,4 @@ def ue_move(context, ue_id, after=0, REQUEST=None, redirect=1):
|
|||
sco_edit_ue._ueEditor.edit(cnx, neigh)
|
||||
# redirect to ue_list page
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect("ue_list?formation_id=" + o["formation_id"])
|
||||
return flask.redirect("ue_list?formation_id=" + o["formation_id"])
|
|
@ -28,6 +28,8 @@
|
|||
"""Ajout/Modification/Supression matieres
|
||||
(portage from DTML)
|
||||
"""
|
||||
import flask
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -68,7 +70,7 @@ def do_matiere_edit(context, *args, **kw):
|
|||
sco_edit_formation.invalidate_sems_in_formation(formation_id)
|
||||
|
||||
|
||||
def do_matiere_create(context, args, REQUEST):
|
||||
def do_matiere_create(context, args):
|
||||
"create a matiere"
|
||||
from app.scodoc import sco_edit_ue
|
||||
from app.scodoc import sco_formations
|
||||
|
@ -85,11 +87,10 @@ def do_matiere_create(context, args, REQUEST):
|
|||
context, args={"formation_id": ue["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=ue["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
return r
|
||||
|
||||
|
@ -100,9 +101,7 @@ def matiere_create(context, ue_id=None, REQUEST=None):
|
|||
|
||||
UE = sco_edit_ue.do_ue_list(context, args={"ue_id": ue_id})[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Création d'une matière"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Création d'une matière"),
|
||||
"""<h2>Création d'une matière dans l'UE %(titre)s (%(acronyme)s)</h2>""" % UE,
|
||||
"""<p class="help">Les matières sont des groupes de modules dans une UE
|
||||
d'une formation donnée. Les matières servent surtout pour la
|
||||
|
@ -140,9 +139,9 @@ associé.
|
|||
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# check unicity
|
||||
mats = do_matiere_list(context, args={"ue_id": ue_id, "titre": tf[2]["titre"]})
|
||||
|
@ -151,13 +150,13 @@ associé.
|
|||
"\n".join(H)
|
||||
+ tf_error_message("Titre de matière déjà existant dans cette UE")
|
||||
+ tf[1]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
_ = do_matiere_create(context, tf[2], REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
_ = do_matiere_create(context, tf[2])
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def do_matiere_delete(context, oid, REQUEST):
|
||||
def do_matiere_delete(context, oid):
|
||||
"delete matiere and attached modules"
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_edit_ue
|
||||
|
@ -178,7 +177,7 @@ def do_matiere_delete(context, oid, REQUEST):
|
|||
# delete all modules in this matiere
|
||||
mods = sco_edit_module.do_module_list(context, {"matiere_id": oid})
|
||||
for mod in mods:
|
||||
sco_edit_module.do_module_delete(context, mod["module_id"], REQUEST)
|
||||
sco_edit_module.do_module_delete(context, mod["module_id"])
|
||||
_matiereEditor.delete(cnx, oid)
|
||||
|
||||
# news
|
||||
|
@ -186,11 +185,10 @@ def do_matiere_delete(context, oid, REQUEST):
|
|||
context, args={"formation_id": ue["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=ue["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
|
||||
|
||||
|
@ -201,9 +199,7 @@ def matiere_delete(context, matiere_id=None, REQUEST=None):
|
|||
M = do_matiere_list(context, args={"matiere_id": matiere_id})[0]
|
||||
UE = sco_edit_ue.do_ue_list(context, args={"ue_id": M["ue_id"]})[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Suppression d'une matière"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Suppression d'une matière"),
|
||||
"<h2>Suppression de la matière %(titre)s" % M,
|
||||
" dans l'UE (%(acronyme)s))</h2>" % UE,
|
||||
]
|
||||
|
@ -217,12 +213,12 @@ def matiere_delete(context, matiere_id=None, REQUEST=None):
|
|||
cancelbutton="Annuler",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
do_matiere_delete(context, matiere_id, REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
do_matiere_delete(context, matiere_id)
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def matiere_edit(context, matiere_id=None, REQUEST=None):
|
||||
|
@ -246,9 +242,7 @@ def matiere_edit(context, matiere_id=None, REQUEST=None):
|
|||
ue_names = ["%(acronyme)s (%(titre)s)" % u for u in ues]
|
||||
ue_ids = [u["ue_id"] for u in ues]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Modification d'une matière"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Modification d'une matière"),
|
||||
"""<h2>Modification de la matière %(titre)s""" % F,
|
||||
"""(formation %(acronyme)s, version %(version)s)</h2>""" % Fo,
|
||||
]
|
||||
|
@ -292,11 +286,9 @@ associé.
|
|||
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + U["formation_id"]
|
||||
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H) + tf[1] + help + html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + tf[1] + help + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# check unicity
|
||||
mats = do_matiere_list(
|
||||
|
@ -307,21 +299,20 @@ associé.
|
|||
"\n".join(H)
|
||||
+ tf_error_message("Titre de matière déjà existant dans cette UE")
|
||||
+ tf[1]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
# changement d'UE ?
|
||||
if tf[2]["ue_id"] != F["ue_id"]:
|
||||
log("attaching mat %s to new UE %s" % (matiere_id, tf[2]["ue_id"]))
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"UPDATE notes_modules SET ue_id = %(ue_id)s WHERE matiere_id=%(matiere_id)s",
|
||||
{"ue_id": tf[2]["ue_id"], "matiere_id": matiere_id},
|
||||
)
|
||||
|
||||
do_matiere_edit(context, tf[2])
|
||||
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def matiere_is_locked(context, matiere_id):
|
||||
|
@ -329,7 +320,6 @@ def matiere_is_locked(context, matiere_id):
|
|||
(contains modules used in a locked formsemestre)
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT ma.* from notes_matieres ma, notes_modules mod, notes_formsemestre sem, notes_moduleimpl mi
|
||||
WHERE ma.matiere_id = mod.matiere_id AND mi.module_id = mod.module_id AND mi.formsemestre_id = sem.formsemestre_id
|
||||
AND ma.matiere_id = %(matiere_id)s AND sem.etat = 0
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
"""Ajout/Modification/Suppression modules
|
||||
(portage from DTML)
|
||||
"""
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -96,7 +99,7 @@ def do_module_list(context, *args, **kw):
|
|||
return _moduleEditor.list(cnx, *args, **kw)
|
||||
|
||||
|
||||
def do_module_create(context, args, REQUEST):
|
||||
def do_module_create(context, args):
|
||||
"create a module"
|
||||
# create
|
||||
from app.scodoc import sco_formations
|
||||
|
@ -109,11 +112,10 @@ def do_module_create(context, args, REQUEST):
|
|||
context, args={"formation_id": args["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=args["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
return r
|
||||
|
||||
|
@ -133,7 +135,7 @@ def module_create(context, matiere_id=None, REQUEST=None):
|
|||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title="Création d'un module"),
|
||||
html_sco_header.sco_header(page_title="Création d'un module"),
|
||||
"""<h2>Création d'un module dans la matière %(titre)s""" % M,
|
||||
""" (UE %(acronyme)s)</h2>""" % UE,
|
||||
_MODULE_HELP,
|
||||
|
@ -237,15 +239,19 @@ def module_create(context, matiere_id=None, REQUEST=None):
|
|||
submitlabel="Créer ce module",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
else:
|
||||
do_module_create(context, tf[2], REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
scu.NotesURL() + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
do_module_create(context, tf[2])
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.ue_list",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=UE["formation_id"],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def do_module_delete(context, oid, REQUEST):
|
||||
def do_module_delete(context, oid):
|
||||
"delete module"
|
||||
from app.scodoc import sco_formations
|
||||
|
||||
|
@ -257,12 +263,10 @@ def do_module_delete(context, oid, REQUEST):
|
|||
mods = sco_moduleimpl.do_moduleimpl_list(context, module_id=oid)
|
||||
if mods:
|
||||
err_page = scu.confirm_dialog(
|
||||
context,
|
||||
message="""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>""",
|
||||
helpmsg="""Il faut d'abord supprimer le semestre. Mais il est peut être préférable de laisser ce programme intact et d'en créer une nouvelle version pour la modifier.""",
|
||||
dest_url="ue_list",
|
||||
parameters={"formation_id": mod["formation_id"]},
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
raise ScoGenError(err_page)
|
||||
# delete
|
||||
|
@ -274,11 +278,10 @@ def do_module_delete(context, oid, REQUEST):
|
|||
context, args={"formation_id": mod["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=mod["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
|
||||
|
||||
|
@ -291,9 +294,7 @@ def module_delete(context, module_id=None, REQUEST=None):
|
|||
raise ScoValueError("Module inexistant !")
|
||||
Mod = Mods[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Suppression d'un module"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Suppression d'un module"),
|
||||
"""<h2>Suppression du module %(titre)s (%(code)s)</h2>""" % Mod,
|
||||
]
|
||||
|
||||
|
@ -307,12 +308,12 @@ def module_delete(context, module_id=None, REQUEST=None):
|
|||
cancelbutton="Annuler",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
do_module_delete(context, module_id, REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
do_module_delete(context, module_id)
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def do_module_edit(context, val):
|
||||
|
@ -359,7 +360,6 @@ def module_edit(context, module_id=None, REQUEST=None):
|
|||
)[0]
|
||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||
M = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT ue.acronyme, mat.* FROM notes_matieres mat, notes_ue ue WHERE mat.ue_id = ue.ue_id AND ue.formation_id = %(formation_id)s ORDER BY ue.numero, mat.numero",
|
||||
{"formation_id": Mod["formation_id"]},
|
||||
)
|
||||
|
@ -373,8 +373,6 @@ def module_edit(context, module_id=None, REQUEST=None):
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Modification du module %(titre)s" % Mod,
|
||||
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
|
||||
javascripts=[
|
||||
|
@ -505,16 +503,16 @@ def module_edit(context, module_id=None, REQUEST=None):
|
|||
)
|
||||
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# l'UE peut changer
|
||||
tf[2]["ue_id"], tf[2]["matiere_id"] = tf[2]["ue_matiere_id"].split("!")
|
||||
# Check unicité code module dans la formation
|
||||
|
||||
do_module_edit(context, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
# Edition en ligne du code Apogee
|
||||
|
@ -544,9 +542,7 @@ def module_list(context, formation_id, REQUEST=None):
|
|||
raise ScoValueError("invalid formation !")
|
||||
F = sco_formations.formation_list(context, args={"formation_id": formation_id})[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Liste des modules de %(titre)s" % F
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Liste des modules de %(titre)s" % F),
|
||||
"""<h2>Listes des modules dans la formation %(titre)s (%(acronyme)s)</h2>"""
|
||||
% F,
|
||||
'<ul class="notes_module_list">',
|
||||
|
@ -562,7 +558,7 @@ def module_list(context, formation_id, REQUEST=None):
|
|||
)
|
||||
H.append("</li>")
|
||||
H.append("</ul>")
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -571,7 +567,6 @@ def module_is_locked(context, module_id):
|
|||
(used in a locked formsemestre)
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT mi.* from notes_modules mod, notes_formsemestre sem, notes_moduleimpl mi
|
||||
WHERE mi.module_id = mod.module_id AND mi.formsemestre_id = sem.formsemestre_id
|
||||
AND mi.module_id = %(module_id)s AND sem.etat = 0
|
||||
|
@ -606,7 +601,7 @@ def formation_add_malus_modules(context, formation_id, titre=None, REQUEST=None)
|
|||
ue_add_malus_module(context, ue["ue_id"], titre=titre, REQUEST=REQUEST)
|
||||
|
||||
if REQUEST:
|
||||
return REQUEST.RESPONSE.redirect("ue_list?formation_id=" + formation_id)
|
||||
return flask.redirect("ue_list?formation_id=" + formation_id)
|
||||
|
||||
|
||||
def ue_add_malus_module(context, ue_id, titre=None, code=None, REQUEST=None):
|
||||
|
@ -635,7 +630,7 @@ def ue_add_malus_module(context, ue_id, titre=None, code=None, REQUEST=None):
|
|||
Matlist = sco_edit_matiere.do_matiere_list(context, args={"ue_id": ue_id})
|
||||
numero = max([mat["numero"] for mat in Matlist]) + 10
|
||||
matiere_id = sco_edit_matiere.do_matiere_create(
|
||||
context, {"ue_id": ue_id, "titre": "Malus", "numero": numero}, REQUEST
|
||||
context, {"ue_id": ue_id, "titre": "Malus", "numero": numero}
|
||||
)
|
||||
|
||||
module_id = do_module_create(
|
||||
|
@ -650,7 +645,6 @@ def ue_add_malus_module(context, ue_id, titre=None, code=None, REQUEST=None):
|
|||
"semestre_id": semestre_id,
|
||||
"module_type": scu.MODULE_MALUS,
|
||||
},
|
||||
REQUEST,
|
||||
)
|
||||
|
||||
return module_id
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
"""Ajout/Modification/Suppression UE
|
||||
|
||||
"""
|
||||
import flask
|
||||
from flask import g, url_for
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -83,7 +87,7 @@ def do_ue_list(context, *args, **kw):
|
|||
return _ueEditor.list(cnx, *args, **kw)
|
||||
|
||||
|
||||
def do_ue_create(context, args, REQUEST):
|
||||
def do_ue_create(context, args):
|
||||
"create an ue"
|
||||
from app.scodoc import sco_formations
|
||||
|
||||
|
@ -102,11 +106,10 @@ def do_ue_create(context, args, REQUEST):
|
|||
context, args={"formation_id": args["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=args["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
return r
|
||||
|
||||
|
@ -132,11 +135,9 @@ def do_ue_delete(context, ue_id, delete_validations=False, REQUEST=None, force=F
|
|||
)
|
||||
if validations and not delete_validations and not force:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"<p>%d étudiants ont validé l'UE %s (%s)</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p>"
|
||||
% (len(validations), ue["acronyme"], ue["titre"]),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
target_variable="delete_validations",
|
||||
cancel_url="ue_list?formation_id=%s" % ue["formation_id"],
|
||||
parameters={"ue_id": ue_id, "dialog_confirmed": 1},
|
||||
|
@ -144,7 +145,6 @@ def do_ue_delete(context, ue_id, delete_validations=False, REQUEST=None, force=F
|
|||
if delete_validations:
|
||||
log("deleting all validations of UE %s" % ue_id)
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM scolar_formsemestre_validation WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue_id},
|
||||
)
|
||||
|
@ -152,16 +152,13 @@ def do_ue_delete(context, ue_id, delete_validations=False, REQUEST=None, force=F
|
|||
# delete all matiere in this UE
|
||||
mats = sco_edit_matiere.do_matiere_list(context, {"ue_id": ue_id})
|
||||
for mat in mats:
|
||||
sco_edit_matiere.do_matiere_delete(context, mat["matiere_id"], REQUEST)
|
||||
sco_edit_matiere.do_matiere_delete(context, mat["matiere_id"])
|
||||
# delete uecoef and events
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_formsemestre_uecoef WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue_id},
|
||||
)
|
||||
ndb.SimpleQuery(
|
||||
context, "DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue_id}
|
||||
)
|
||||
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue_id})
|
||||
cnx = ndb.GetDBConnexion()
|
||||
_ueEditor.delete(cnx, ue_id)
|
||||
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement utilisé: acceptable de tout invalider ?):
|
||||
|
@ -171,16 +168,19 @@ def do_ue_delete(context, ue_id, delete_validations=False, REQUEST=None, force=F
|
|||
context, args={"formation_id": ue["formation_id"]}
|
||||
)[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=ue["formation_id"],
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
#
|
||||
if not force:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
scu.NotesURL() + "/ue_list?formation_id=" + str(ue["formation_id"])
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.ue_list",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=ue["formation_id"],
|
||||
)
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
@ -219,9 +219,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title=title, javascripts=["js/edit_ue.js"]
|
||||
),
|
||||
html_sco_header.sco_header(page_title=title, javascripts=["js/edit_ue.js"]),
|
||||
"<h2>" + title,
|
||||
" (formation %(acronyme)s, version %(version)s)</h2>" % Fo,
|
||||
"""
|
||||
|
@ -334,7 +332,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||
if tf[0] == 0:
|
||||
X = """<div id="ue_list_code"></div>
|
||||
"""
|
||||
return "\n".join(H) + tf[1] + X + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + tf[1] + X + html_sco_header.sco_footer()
|
||||
else:
|
||||
if create:
|
||||
if not tf[2]["ue_code"]:
|
||||
|
@ -347,12 +345,11 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||
context, formation_id, int(tf[2]["semestre_id"] or 0)
|
||||
)
|
||||
|
||||
ue_id = do_ue_create(context, tf[2], REQUEST)
|
||||
ue_id = do_ue_create(context, tf[2])
|
||||
if parcours.UE_IS_MODULE or tf[2]["create_matiere"]:
|
||||
matiere_id = sco_edit_matiere.do_matiere_create(
|
||||
context,
|
||||
{"ue_id": ue_id, "titre": tf[2]["titre"], "numero": 1},
|
||||
REQUEST,
|
||||
)
|
||||
if parcours.UE_IS_MODULE:
|
||||
# dans ce mode, crée un (unique) module dans l'UE:
|
||||
|
@ -367,12 +364,13 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||
"formation_id": formation_id,
|
||||
"semestre_id": tf[2]["semestre_id"],
|
||||
},
|
||||
REQUEST,
|
||||
)
|
||||
else:
|
||||
do_ue_edit(context, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
scu.NotesURL() + "/ue_list?formation_id=" + formation_id
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
@ -419,10 +417,8 @@ def ue_delete(
|
|||
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"<h2>Suppression de l'UE %(titre)s (%(acronyme)s))</h2>" % ue,
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
parameters={"ue_id": ue_id},
|
||||
cancel_url="ue_list?formation_id=%s" % ue["formation_id"],
|
||||
)
|
||||
|
@ -439,8 +435,6 @@ def ue_list(context, formation_id=None, msg="", REQUEST=None):
|
|||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_formsemestre_validation
|
||||
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
|
||||
F = sco_formations.formation_list(context, args={"formation_id": formation_id})
|
||||
if not F:
|
||||
raise ScoValueError("invalid formation_id")
|
||||
|
@ -454,7 +448,7 @@ def ue_list(context, formation_id=None, msg="", REQUEST=None):
|
|||
ue_list.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||
has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ue_list])) != len(ue_list)
|
||||
|
||||
perm_change = authuser.has_permission(Permission.ScoChangeFormation)
|
||||
perm_change = current_user.has_permission(Permission.ScoChangeFormation)
|
||||
# editable = (not locked) and perm_change
|
||||
# On autorise maintanant la modification des formations qui ont des semestres verrouillés,
|
||||
# sauf si cela affect les notes passées (verrouillées):
|
||||
|
@ -462,14 +456,14 @@ def ue_list(context, formation_id=None, msg="", REQUEST=None):
|
|||
# - pas de changement des codes d'UE utilisés dans des semestres verrouillés
|
||||
editable = perm_change
|
||||
tag_editable = (
|
||||
authuser.has_permission(Permission.ScoEditFormationTags) or perm_change
|
||||
current_user.has_permission(Permission.ScoEditFormationTags) or perm_change
|
||||
)
|
||||
if locked:
|
||||
lockicon = scu.icontag("lock32_img", title="verrouillé")
|
||||
else:
|
||||
lockicon = ""
|
||||
|
||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags(context, REQUEST)
|
||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags()
|
||||
delete_icon = scu.icontag(
|
||||
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer"
|
||||
)
|
||||
|
@ -478,8 +472,6 @@ def ue_list(context, formation_id=None, msg="", REQUEST=None):
|
|||
)
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
|
||||
javascripts=[
|
||||
"libjs/jinplace-1.2.1.min.js",
|
||||
|
@ -814,7 +806,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||
H.append("</li>")
|
||||
H.append("</ul>")
|
||||
|
||||
if authuser.has_permission(Permission.ScoImplement):
|
||||
if current_user.has_permission(Permission.ScoImplement):
|
||||
H.append(
|
||||
"""<ul>
|
||||
<li><a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">Mettre en place un nouveau semestre de formation %(acronyme)s</a>
|
||||
|
@ -828,7 +820,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||
warn, _ = sco_formsemestre_validation.check_formation_ues(context, formation_id)
|
||||
H.append(warn)
|
||||
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "".join(H)
|
||||
|
||||
|
||||
|
@ -949,7 +941,6 @@ def ue_is_locked(context, ue_id):
|
|||
(contains modules used in a locked formsemestre)
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT ue.* FROM notes_ue ue, notes_modules mod, notes_formsemestre sem, notes_moduleimpl mi
|
||||
WHERE ue.ue_id = mod.ue_id
|
||||
AND mi.module_id = mod.module_id AND mi.formsemestre_id = sem.formsemestre_id
|
||||
|
@ -1042,9 +1033,7 @@ def formation_table_recap(context, formation_id, format="html", REQUEST=None):
|
|||
page_title=title,
|
||||
html_title="<h2>" + title + "</h2>",
|
||||
pdf_title=title,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ def formsemestre_get_ics_url(context, sem):
|
|||
https://example.fr/agenda/{sem[etapes][0]}
|
||||
"""
|
||||
ics_url_tmpl = sco_preferences.get_preference(
|
||||
context, "edt_sem_ics_url", sem["formsemestre_id"]
|
||||
"edt_sem_ics_url", sem["formsemestre_id"]
|
||||
)
|
||||
if not ics_url_tmpl:
|
||||
return None
|
||||
|
@ -102,7 +102,7 @@ def get_edt_transcodage_groups(context, formsemestre_id):
|
|||
edt2sco = {}
|
||||
sco2edt = {}
|
||||
msg = "" # message erreur, '' si ok
|
||||
txt = sco_preferences.get_preference(context, "edt_groups2scodoc", formsemestre_id)
|
||||
txt = sco_preferences.get_preference("edt_groups2scodoc", formsemestre_id)
|
||||
if not txt:
|
||||
return edt2sco, sco2edt, msg
|
||||
|
||||
|
@ -166,8 +166,6 @@ def experimental_calendar(context, group_id=None, formsemestre_id=None, REQUEST=
|
|||
return "\n".join(
|
||||
[
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
javascripts=[
|
||||
"libjs/purl.js",
|
||||
"libjs/moment.min.js",
|
||||
|
@ -198,7 +196,7 @@ def experimental_calendar(context, group_id=None, formsemestre_id=None, REQUEST=
|
|||
"""</form><div id="loading">loading...</div>
|
||||
<div id="calendar"></div>
|
||||
""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
"""<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
|
|
|
@ -387,7 +387,7 @@ apo_csv_store(context, csv_data, annee_scolaire, sem_id)
|
|||
|
||||
|
||||
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(context, [sco_groups.get_default_group(context, formsemestre_id)], formsemestre_id=formsemestre_id, REQUEST=REQUEST)
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(context, [sco_groups.get_default_group(formsemestre_id)], formsemestre_id=formsemestre_id)
|
||||
|
||||
nt = sco_cache.NotesTableCache.get( formsemestre_id)
|
||||
|
||||
|
|
|
@ -28,12 +28,10 @@
|
|||
"""ScoDoc : formulaires gestion maquettes Apogee / export resultats
|
||||
"""
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
from io import StringIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -72,7 +70,7 @@ def apo_semset_maq_status(
|
|||
if not semset_id:
|
||||
raise ValueError("invalid null semset_id")
|
||||
semset = sco_semset.SemSet(context, semset_id=semset_id)
|
||||
semset.fill_formsemestres(REQUEST)
|
||||
semset.fill_formsemestres()
|
||||
# autorise export meme si etudiants Apo manquants:
|
||||
allow_missing_apo = int(allow_missing_apo)
|
||||
# autorise export meme s'il manque des décisions de jury:
|
||||
|
@ -85,9 +83,7 @@ def apo_semset_maq_status(
|
|||
block_export_res_modules = int(block_export_res_modules)
|
||||
block_export_res_sdj = int(block_export_res_sdj)
|
||||
|
||||
prefs = sco_preferences.SemPreferences(
|
||||
context,
|
||||
)
|
||||
prefs = sco_preferences.SemPreferences()
|
||||
|
||||
tab_archives = table_apo_csv_list(context, semset, REQUEST=REQUEST)
|
||||
|
||||
|
@ -110,8 +106,6 @@ def apo_semset_maq_status(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Export Apogée",
|
||||
javascripts=["js/apo_semset_maq_status.js"],
|
||||
),
|
||||
|
@ -435,7 +429,7 @@ def apo_semset_maq_status(
|
|||
"""
|
||||
% (APO_INPUT_ENCODING,)
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -489,9 +483,7 @@ def table_apo_csv_list(context, semset, REQUEST=None):
|
|||
html_sortable=True,
|
||||
# base_url = '%s?formsemestre_id=%s' % (REQUEST.URL0, formsemestre_id),
|
||||
# caption='Maquettes enregistrées',
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
|
||||
return tab
|
||||
|
@ -577,8 +569,6 @@ def _view_etuds_page(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=title,
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
|
@ -600,9 +590,7 @@ def _view_etuds_page(
|
|||
html_sortable=True,
|
||||
html_class="table_leftalign",
|
||||
filename="students_apo",
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
if format != "html":
|
||||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||
|
@ -614,7 +602,7 @@ def _view_etuds_page(
|
|||
% semset_id
|
||||
)
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def view_apo_csv_store(
|
||||
|
@ -653,7 +641,7 @@ def view_apo_csv_store(
|
|||
context, data, semset["annee_scolaire"], semset["sem_id"]
|
||||
)
|
||||
|
||||
return REQUEST.RESPONSE.redirect("apo_semset_maq_status?semset_id=" + semset_id)
|
||||
return flask.redirect("apo_semset_maq_status?semset_id=" + semset_id)
|
||||
|
||||
|
||||
def view_apo_csv_download_and_store(context, etape_apo="", semset_id="", REQUEST=None):
|
||||
|
@ -683,12 +671,10 @@ def view_apo_csv_delete(
|
|||
dest_url = "apo_semset_maq_status?semset_id=" + semset_id
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Confirmer la suppression du fichier étape <tt>%s</tt>?</h2>
|
||||
<p>La suppression sera définitive.</p>"""
|
||||
% (etape_apo,),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url=dest_url,
|
||||
parameters={"semset_id": semset_id, "etape_apo": etape_apo},
|
||||
)
|
||||
|
@ -697,7 +683,7 @@ def view_apo_csv_delete(
|
|||
context, etape_apo, semset["annee_scolaire"], semset["sem_id"]
|
||||
)
|
||||
sco_etape_apogee.apo_csv_delete(context, info["archive_id"])
|
||||
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||
return flask.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||
|
||||
|
||||
def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=None):
|
||||
|
@ -728,8 +714,6 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Maquette Apogée enregistrée pour %s" % etape_apo,
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
|
@ -752,11 +736,7 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
|||
# Liste des étudiants (sans les résultats pour le moment): TODO
|
||||
etuds = apo_data.etuds
|
||||
if not etuds:
|
||||
return (
|
||||
"\n".join(H)
|
||||
+ "<p>Aucun étudiant</p>"
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + "<p>Aucun étudiant</p>" + html_sco_header.sco_footer()
|
||||
|
||||
# Ajout infos sur ScoDoc vs Apogee
|
||||
for e in etuds:
|
||||
|
@ -788,9 +768,7 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
|||
base_url="%s?etape_apo=%s&semset_id=%s" % (REQUEST.URL0, etape_apo, semset_id),
|
||||
filename="students_" + etape_apo,
|
||||
caption="Etudiants Apogée en " + etape_apo,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
|
||||
if format != "html":
|
||||
|
@ -803,7 +781,7 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
|||
"""<div><a class="stdlink" href="apo_semset_maq_status?semset_id=%s">Retour</a>
|
||||
</div>"""
|
||||
% semset_id,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
|
||||
return "\n".join(H)
|
||||
|
@ -826,9 +804,7 @@ def apo_csv_export_results(
|
|||
# nota: on peut éventuellement exporter même si tout n'est pas ok
|
||||
# mais le lien via le tableau de bord n'est pas actif
|
||||
# Les fichiers résultats ne sont pas stockés: pas besoin de permission particulière
|
||||
prefs = sco_preferences.SemPreferences(
|
||||
context,
|
||||
)
|
||||
prefs = sco_preferences.SemPreferences()
|
||||
export_res_etape = prefs["export_res_etape"] and not int(block_export_res_etape)
|
||||
export_res_sem = prefs["export_res_sem"] and not int(block_export_res_sem)
|
||||
export_res_ues = prefs["export_res_ues"] and not int(block_export_res_ues)
|
||||
|
@ -869,7 +845,7 @@ def apo_csv_export_results(
|
|||
)
|
||||
|
||||
basename = (
|
||||
sco_preferences.get_preference(context, "DeptName")
|
||||
sco_preferences.get_preference("DeptName")
|
||||
+ str(annee_scolaire)
|
||||
+ "-%s-" % periode
|
||||
+ "-".join(etapes_apo)
|
||||
|
|
|
@ -351,7 +351,6 @@ def _check_duplicate_code(cnx, args, code_name, context, edit=True, REQUEST=None
|
|||
parameters = {}
|
||||
if context:
|
||||
err_page = scu.confirm_dialog(
|
||||
context,
|
||||
message="""<h3>Code étudiant (%s) dupliqué !</h3>""" % code_name,
|
||||
helpmsg="""Le %s %s est déjà utilisé: un seul étudiant peut avoir ce code. Vérifier votre valeur ou supprimer l'autre étudiant avec cette valeur.<p><ul><li>"""
|
||||
% (code_name, args[code_name])
|
||||
|
@ -360,7 +359,6 @@ def _check_duplicate_code(cnx, args, code_name, context, edit=True, REQUEST=None
|
|||
OK=OK,
|
||||
dest_url=dest_url,
|
||||
parameters=parameters,
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
else:
|
||||
err_page = """<h3>Code étudiant (%s) dupliqué !</h3>""" % code_name
|
||||
|
@ -368,6 +366,11 @@ def _check_duplicate_code(cnx, args, code_name, context, edit=True, REQUEST=None
|
|||
raise ScoGenError(err_page)
|
||||
|
||||
|
||||
def _check_civilite(args):
|
||||
civilite = args.get("civilite", "X") or "X"
|
||||
args["civilite"] = input_civilite(civilite) # TODO: A faire valider
|
||||
|
||||
|
||||
def identite_edit(cnx, args, context=None, REQUEST=None):
|
||||
"""Modifie l'identite d'un étudiant.
|
||||
Si context et notification et difference, envoie message notification.
|
||||
|
@ -377,9 +380,7 @@ def identite_edit(cnx, args, context=None, REQUEST=None):
|
|||
notify_to = None
|
||||
if context:
|
||||
try:
|
||||
notify_to = sco_preferences.get_preference(
|
||||
context, "notify_etud_changes_to"
|
||||
)
|
||||
notify_to = sco_preferences.get_preference("notify_etud_changes_to")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -407,6 +408,7 @@ def identite_create(cnx, args, context=None, REQUEST=None):
|
|||
"check unique etudid, then create"
|
||||
_check_duplicate_code(cnx, args, "code_nip", context, edit=False, REQUEST=REQUEST)
|
||||
_check_duplicate_code(cnx, args, "code_ine", context, edit=False, REQUEST=REQUEST)
|
||||
_check_civilite(args)
|
||||
|
||||
if "etudid" in args:
|
||||
etudid = args["etudid"]
|
||||
|
@ -446,7 +448,7 @@ def notify_etud_change(context, email_addr, etud, before, after, subject):
|
|||
msg = MIMEMultipart()
|
||||
subj = Header("[ScoDoc] " + subject, SCO_ENCODING)
|
||||
msg["Subject"] = subj
|
||||
msg["From"] = sco_preferences.get_preference(context, "email_from_addr")
|
||||
msg["From"] = sco_preferences.get_preference("email_from_addr")
|
||||
msg["To"] = email_addr
|
||||
mime_txt = MIMEText(txt, "plain", SCO_ENCODING)
|
||||
msg.attach(mime_txt)
|
||||
|
@ -492,9 +494,7 @@ def adresse_edit(cnx, args, context=None):
|
|||
notify_to = None
|
||||
if context:
|
||||
try:
|
||||
notify_to = sco_preferences.get_preference(
|
||||
context, "notify_etud_changes_to"
|
||||
)
|
||||
notify_to = sco_preferences.get_preference("notify_etud_changes_to")
|
||||
except:
|
||||
pass
|
||||
if notify_to:
|
||||
|
@ -696,7 +696,6 @@ def create_etud(context, cnx, args={}, REQUEST=None):
|
|||
)
|
||||
# log
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="etudident_edit_form",
|
||||
etudid=etudid,
|
||||
|
@ -706,8 +705,6 @@ def create_etud(context, cnx, args={}, REQUEST=None):
|
|||
fill_etuds_info([etud])
|
||||
etud["url"] = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_INSCR,
|
||||
object=None, # pas d'object pour ne montrer qu'un etudiant
|
||||
text='Nouvel étudiant <a href="%(url)s">%(nomprenom)s</a>' % etud,
|
||||
|
@ -743,7 +740,7 @@ scolar_events_edit = _scolar_eventsEditor.edit
|
|||
|
||||
def scolar_events_create(cnx, args):
|
||||
# several "events" may share the same values
|
||||
_scolar_eventsEditor.create(cnx, args, has_uniq_values=False)
|
||||
_scolar_eventsEditor.create(cnx, args)
|
||||
|
||||
|
||||
# --------
|
||||
|
@ -764,7 +761,6 @@ _etud_annotationsEditor = ndb.EditableTable(
|
|||
output_formators={"comment": safehtml.html_to_safe_html, "date": ndb.DateISOtoDMY},
|
||||
)
|
||||
|
||||
|
||||
etud_annotations_create = _etud_annotationsEditor.create
|
||||
etud_annotations_delete = _etud_annotationsEditor.delete
|
||||
etud_annotations_list = _etud_annotationsEditor.list
|
||||
|
@ -1058,4 +1054,4 @@ def descr_situation_etud(context, etudid, ne=""):
|
|||
else:
|
||||
date_dem = events[0]["event_date"]
|
||||
situation += " le " + str(date_dem)
|
||||
return situation
|
||||
return situation
|
||||
|
|
|
@ -33,6 +33,11 @@ import pprint
|
|||
import time
|
||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
|
||||
import flask
|
||||
from flask import url_for
|
||||
from flask import g
|
||||
from flask_login import current_user
|
||||
|
||||
from app.scodoc.notes_log import log, logCallStack
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -124,7 +129,7 @@ _evaluationEditor = ndb.EditableTable(
|
|||
)
|
||||
|
||||
|
||||
def do_evaluation_list(context, args, sortkey=None):
|
||||
def do_evaluation_list(args, sortkey=None):
|
||||
"""List evaluations, sorted by numero (or most recent date first).
|
||||
|
||||
Ajoute les champs:
|
||||
|
@ -172,19 +177,19 @@ def do_evaluation_list(context, args, sortkey=None):
|
|||
return evals
|
||||
|
||||
|
||||
def do_evaluation_list_in_formsemestre(context, formsemestre_id):
|
||||
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
||||
"list evaluations in this formsemestre"
|
||||
context = None # #context
|
||||
mods = sco_moduleimpl.do_moduleimpl_list(context, formsemestre_id=formsemestre_id)
|
||||
evals = []
|
||||
for mod in mods:
|
||||
evals += do_evaluation_list(
|
||||
context, args={"moduleimpl_id": mod["moduleimpl_id"]}
|
||||
)
|
||||
evals += do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
||||
return evals
|
||||
|
||||
|
||||
def _check_evaluation_args(context, args):
|
||||
def _check_evaluation_args(args):
|
||||
"Check coefficient, dates and duration, raises exception if invalid"
|
||||
context = None # #context
|
||||
moduleimpl_id = args["moduleimpl_id"]
|
||||
# check bareme
|
||||
note_max = args.get("note_max", None)
|
||||
|
@ -236,7 +241,6 @@ def _check_evaluation_args(context, args):
|
|||
|
||||
|
||||
def do_evaluation_create(
|
||||
context,
|
||||
moduleimpl_id=None,
|
||||
jour=None,
|
||||
heure_debut=None,
|
||||
|
@ -249,29 +253,24 @@ def do_evaluation_create(
|
|||
evaluation_type=None,
|
||||
numero=None,
|
||||
REQUEST=None,
|
||||
**kw # ceci pour absorber les arguments excedentaires de tf #sco8
|
||||
**kw, # ceci pour absorber les arguments excedentaires de tf #sco8
|
||||
):
|
||||
"""Create an evaluation"""
|
||||
if not sco_permissions_check.can_edit_evaluation(
|
||||
context, REQUEST, moduleimpl_id=moduleimpl_id
|
||||
):
|
||||
context = None # #context
|
||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||
raise AccessDenied(
|
||||
"Modification évaluation impossible pour %s"
|
||||
% scu.get_current_user_name(REQUEST)
|
||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||
)
|
||||
args = locals()
|
||||
log("do_evaluation_create: args=" + str(args))
|
||||
_check_evaluation_args(context, args)
|
||||
_check_evaluation_args(args)
|
||||
# Check numeros
|
||||
module_evaluation_renumber(
|
||||
context, moduleimpl_id, REQUEST=REQUEST, only_if_unumbered=True
|
||||
)
|
||||
module_evaluation_renumber(moduleimpl_id, only_if_unumbered=True)
|
||||
if not "numero" in args or args["numero"] is None:
|
||||
n = None
|
||||
# determine le numero avec la date
|
||||
# Liste des eval existantes triees par date, la plus ancienne en tete
|
||||
ModEvals = do_evaluation_list(
|
||||
context,
|
||||
args={"moduleimpl_id": moduleimpl_id},
|
||||
sortkey="jour asc, heure_debut asc",
|
||||
)
|
||||
|
@ -289,9 +288,7 @@ def do_evaluation_create(
|
|||
next_eval = e
|
||||
break
|
||||
if next_eval:
|
||||
n = module_evaluation_insert_before(
|
||||
context, ModEvals, next_eval, REQUEST
|
||||
)
|
||||
n = module_evaluation_insert_before(ModEvals, next_eval)
|
||||
else:
|
||||
n = None # a placer en fin
|
||||
if n is None: # pas de date ou en fin:
|
||||
|
@ -313,8 +310,6 @@ def do_evaluation_create(
|
|||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=moduleimpl_id,
|
||||
text='Création d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||
|
@ -324,22 +319,20 @@ def do_evaluation_create(
|
|||
return r
|
||||
|
||||
|
||||
def do_evaluation_edit(context, REQUEST, args):
|
||||
def do_evaluation_edit(args):
|
||||
"edit an evaluation"
|
||||
context = None # #context
|
||||
evaluation_id = args["evaluation_id"]
|
||||
the_evals = do_evaluation_list(context, {"evaluation_id": evaluation_id})
|
||||
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not the_evals:
|
||||
raise ValueError("evaluation inexistante !")
|
||||
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
||||
if not sco_permissions_check.can_edit_evaluation(
|
||||
context, REQUEST, moduleimpl_id=moduleimpl_id
|
||||
):
|
||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||
raise AccessDenied(
|
||||
"Modification évaluation impossible pour %s"
|
||||
% scu.get_current_user_name(REQUEST)
|
||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||
)
|
||||
args["moduleimpl_id"] = moduleimpl_id
|
||||
_check_evaluation_args(context, args)
|
||||
_check_evaluation_args(args)
|
||||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
_evaluationEditor.edit(cnx, args)
|
||||
|
@ -348,20 +341,18 @@ def do_evaluation_edit(context, REQUEST, args):
|
|||
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||
|
||||
|
||||
def do_evaluation_delete(context, REQUEST, evaluation_id):
|
||||
def do_evaluation_delete(evaluation_id):
|
||||
"delete evaluation"
|
||||
the_evals = do_evaluation_list(context, {"evaluation_id": evaluation_id})
|
||||
context = None # #context
|
||||
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not the_evals:
|
||||
raise ValueError("evaluation inexistante !")
|
||||
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
||||
if not sco_permissions_check.can_edit_evaluation(
|
||||
context, REQUEST, moduleimpl_id=moduleimpl_id
|
||||
):
|
||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||
raise AccessDenied(
|
||||
"Modification évaluation impossible pour %s"
|
||||
% scu.get_current_user_name(REQUEST)
|
||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||
)
|
||||
NotesDB = do_evaluation_get_all_notes(context, evaluation_id) # { etudid : value }
|
||||
NotesDB = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
||||
notes = [x["value"] for x in NotesDB.values()]
|
||||
if notes:
|
||||
raise ScoValueError(
|
||||
|
@ -381,8 +372,6 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
|
|||
scu.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
)
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=moduleimpl_id,
|
||||
text='Suppression d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||
|
@ -393,9 +382,7 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
|
|||
_DEE_TOT = 0
|
||||
|
||||
|
||||
def do_evaluation_etat(
|
||||
context, evaluation_id, partition_id=None, select_first_partition=False
|
||||
):
|
||||
def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
|
||||
"""donne infos sur l'etat du evaluation
|
||||
{ nb_inscrits, nb_notes, nb_abs, nb_neutre, nb_att,
|
||||
moyenne, mediane, mini, maxi,
|
||||
|
@ -404,12 +391,11 @@ def do_evaluation_etat(
|
|||
à ce module ont des notes)
|
||||
evalattente est vrai s'il ne manque que des notes en attente
|
||||
"""
|
||||
context = None # #context
|
||||
nb_inscrits = len(
|
||||
sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True
|
||||
)
|
||||
sco_groups.do_evaluation_listeetuds_groups(evaluation_id, getallstudents=True)
|
||||
)
|
||||
NotesDB = do_evaluation_get_all_notes(context, evaluation_id) # { etudid : value }
|
||||
NotesDB = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
||||
notes = [x["value"] for x in NotesDB.values()]
|
||||
nb_abs = len([x for x in notes if x is None])
|
||||
nb_neutre = len([x for x in notes if x == scu.NOTES_NEUTRALISE])
|
||||
|
@ -432,7 +418,7 @@ def do_evaluation_etat(
|
|||
else:
|
||||
last_modif = None
|
||||
# ---- Liste des groupes complets et incomplets
|
||||
E = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
|
||||
E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
Mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
|
||||
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
||||
|
@ -568,7 +554,7 @@ def do_evaluation_etat(
|
|||
}
|
||||
|
||||
|
||||
def do_evaluation_list_in_sem(context, formsemestre_id, with_etat=True):
|
||||
def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
||||
"""Liste les evaluations de tous les modules de ce semestre.
|
||||
Donne pour chaque eval son état (voir do_evaluation_etat)
|
||||
{ evaluation_id,nb_inscrits, nb_notes, nb_abs, nb_neutre, moy, median, last_modif ... }
|
||||
|
@ -625,19 +611,18 @@ def do_evaluation_list_in_sem(context, formsemestre_id, with_etat=True):
|
|||
for r in res:
|
||||
r["jour"] = r["jour"] or datetime.date(1900, 1, 1) # pour les comparaisons
|
||||
if with_etat:
|
||||
r["etat"] = do_evaluation_etat(context, r["evaluation_id"])
|
||||
r["etat"] = do_evaluation_etat(r["evaluation_id"])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
# ancien _notes_getall
|
||||
def do_evaluation_get_all_notes(
|
||||
context, evaluation_id, table="notes_notes", filter_suppressed=True, by_uid=None
|
||||
evaluation_id, table="notes_notes", filter_suppressed=True, by_uid=None
|
||||
):
|
||||
"""Toutes les notes pour une evaluation: { etudid : { 'value' : value, 'date' : date ... }}
|
||||
Attention: inclut aussi les notes des étudiants qui ne sont plus inscrits au module.
|
||||
"""
|
||||
# log('do_evaluation_get_all_notes( e=%s fs=%s )' % (evaluation_id, filter_suppressed))
|
||||
do_cache = (
|
||||
filter_suppressed and table == "notes_notes" and (by_uid is None)
|
||||
) # pas de cache pour (rares) appels via undo_notes ou specifiant un enseignant
|
||||
|
@ -665,7 +650,9 @@ def do_evaluation_get_all_notes(
|
|||
for x in res:
|
||||
d[x["etudid"]] = x
|
||||
if do_cache:
|
||||
sco_cache.EvaluationCache.set(evaluation_id, d)
|
||||
status = sco_cache.EvaluationCache.set(evaluation_id, d)
|
||||
if not status:
|
||||
log(f"Warning: EvaluationCache.set: {evaluation_id}\t{status}")
|
||||
return d
|
||||
|
||||
|
||||
|
@ -703,7 +690,7 @@ def _eval_etat(evals):
|
|||
}
|
||||
|
||||
|
||||
def do_evaluation_etat_in_sem(context, formsemestre_id, REQUEST=None):
|
||||
def do_evaluation_etat_in_sem(formsemestre_id):
|
||||
"""-> nb_eval_completes, nb_evals_en_cours, nb_evals_vides,
|
||||
date derniere modif, attente"""
|
||||
nt = sco_cache.NotesTableCache.get(
|
||||
|
@ -716,7 +703,7 @@ def do_evaluation_etat_in_sem(context, formsemestre_id, REQUEST=None):
|
|||
return etat
|
||||
|
||||
|
||||
def do_evaluation_etat_in_mod(context, nt, moduleimpl_id):
|
||||
def do_evaluation_etat_in_mod(nt, moduleimpl_id):
|
||||
""""""
|
||||
evals = nt.get_mod_evaluation_etat_list(moduleimpl_id)
|
||||
etat = _eval_etat(evals)
|
||||
|
@ -726,8 +713,9 @@ def do_evaluation_etat_in_mod(context, nt, moduleimpl_id):
|
|||
return etat
|
||||
|
||||
|
||||
def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None):
|
||||
def formsemestre_evaluations_cal(formsemestre_id, REQUEST=None):
|
||||
"""Page avec calendrier de toutes les evaluations de ce semestre"""
|
||||
context = None # #context
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
||||
|
||||
|
@ -810,16 +798,16 @@ def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None):
|
|||
"""<p><a href="formsemestre_evaluations_delai_correction?formsemestre_id=%s" class="stdlink">voir les délais de correction</a></p>
|
||||
"""
|
||||
% (formsemestre_id,),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def evaluation_date_first_completion(context, evaluation_id):
|
||||
def evaluation_date_first_completion(evaluation_id):
|
||||
"""Première date à laquelle l'évaluation a été complète
|
||||
ou None si actuellement incomplète
|
||||
"""
|
||||
etat = do_evaluation_etat(context, evaluation_id)
|
||||
etat = do_evaluation_etat(evaluation_id)
|
||||
if not etat["evalcomplete"]:
|
||||
return None
|
||||
|
||||
|
@ -827,7 +815,7 @@ def evaluation_date_first_completion(context, evaluation_id):
|
|||
# Il faut considerer les inscriptions au semestre
|
||||
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
||||
# au module (pour gerer les modules optionnels correctement)
|
||||
# E = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
|
||||
# E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||
# M = sco_moduleimpl.do_moduleimpl_list(context,moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
# formsemestre_id = M["formsemestre_id"]
|
||||
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(context, formsemestre_id)
|
||||
|
@ -837,13 +825,11 @@ def evaluation_date_first_completion(context, evaluation_id):
|
|||
# ins = [i for i in insem if i["etudid"] in insmodset]
|
||||
|
||||
notes = list(
|
||||
do_evaluation_get_all_notes(
|
||||
context, evaluation_id, filter_suppressed=False
|
||||
).values()
|
||||
do_evaluation_get_all_notes(evaluation_id, filter_suppressed=False).values()
|
||||
)
|
||||
notes_log = list(
|
||||
do_evaluation_get_all_notes(
|
||||
context, evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||
).values()
|
||||
)
|
||||
date_premiere_note = {} # etudid : date
|
||||
|
@ -861,13 +847,14 @@ def evaluation_date_first_completion(context, evaluation_id):
|
|||
|
||||
|
||||
def formsemestre_evaluations_delai_correction(
|
||||
context, formsemestre_id, format="html", REQUEST=None
|
||||
formsemestre_id, format="html", REQUEST=None
|
||||
):
|
||||
"""Experimental: un tableau indiquant pour chaque évaluation
|
||||
le nombre de jours avant la publication des notes.
|
||||
|
||||
N'indique pas les évaluations de ratrapage ni celles des modules de bonus/malus.
|
||||
"""
|
||||
context = None # #context
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
||||
|
||||
|
@ -884,9 +871,7 @@ def formsemestre_evaluations_delai_correction(
|
|||
Mod["module_type"] == scu.MODULE_MALUS
|
||||
):
|
||||
continue
|
||||
e["date_first_complete"] = evaluation_date_first_completion(
|
||||
context, e["evaluation_id"]
|
||||
)
|
||||
e["date_first_complete"] = evaluation_date_first_completion(e["evaluation_id"])
|
||||
if e["date_first_complete"]:
|
||||
e["delai_correction"] = (e["date_first_complete"].date() - e["jour"]).days
|
||||
else:
|
||||
|
@ -930,7 +915,7 @@ def formsemestre_evaluations_delai_correction(
|
|||
html_sortable=True,
|
||||
html_title="<h2>Correction des évaluations du semestre</h2>",
|
||||
caption="Correction des évaluations du semestre",
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
||||
|
@ -938,7 +923,7 @@ def formsemestre_evaluations_delai_correction(
|
|||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||
|
||||
|
||||
def module_evaluation_insert_before(context, ModEvals, next_eval, REQUEST):
|
||||
def module_evaluation_insert_before(ModEvals, next_eval):
|
||||
"""Renumber evals such that an evaluation with can be inserted before next_eval
|
||||
Returns numero suitable for the inserted evaluation
|
||||
"""
|
||||
|
@ -946,9 +931,9 @@ def module_evaluation_insert_before(context, ModEvals, next_eval, REQUEST):
|
|||
n = next_eval["numero"]
|
||||
if not n:
|
||||
log("renumbering old evals")
|
||||
module_evaluation_renumber(context, next_eval["moduleimpl_id"], REQUEST)
|
||||
module_evaluation_renumber(next_eval["moduleimpl_id"])
|
||||
next_eval = do_evaluation_list(
|
||||
context, args={"evaluation_id": next_eval["evaluation_id"]}
|
||||
args={"evaluation_id": next_eval["evaluation_id"]}
|
||||
)[0]
|
||||
n = next_eval["numero"]
|
||||
else:
|
||||
|
@ -959,35 +944,30 @@ def module_evaluation_insert_before(context, ModEvals, next_eval, REQUEST):
|
|||
if e["numero"] >= n:
|
||||
e["numero"] += 1
|
||||
# log('incrementing %s to %s' % (e['evaluation_id'], e['numero']))
|
||||
do_evaluation_edit(context, REQUEST, e)
|
||||
do_evaluation_edit(e)
|
||||
|
||||
return n
|
||||
|
||||
|
||||
def module_evaluation_move(context, evaluation_id, after=0, REQUEST=None, redirect=1):
|
||||
def module_evaluation_move(evaluation_id, after=0, redirect=1):
|
||||
"""Move before/after previous one (decrement/increment numero)
|
||||
(published)
|
||||
"""
|
||||
e = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
|
||||
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||
redirect = int(redirect)
|
||||
# access: can change eval ?
|
||||
if not sco_permissions_check.can_edit_evaluation(
|
||||
context, REQUEST, moduleimpl_id=e["moduleimpl_id"]
|
||||
):
|
||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=e["moduleimpl_id"]):
|
||||
raise AccessDenied(
|
||||
"Modification évaluation impossible pour %s"
|
||||
% scu.get_current_user_name(REQUEST)
|
||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||
)
|
||||
|
||||
module_evaluation_renumber(
|
||||
context, e["moduleimpl_id"], REQUEST=REQUEST, only_if_unumbered=True
|
||||
)
|
||||
e = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
|
||||
module_evaluation_renumber(e["moduleimpl_id"], only_if_unumbered=True)
|
||||
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||
|
||||
after = int(after) # 0: deplace avant, 1 deplace apres
|
||||
if after not in (0, 1):
|
||||
raise ValueError('invalid value for "after"')
|
||||
ModEvals = do_evaluation_list(context, {"moduleimpl_id": e["moduleimpl_id"]})
|
||||
ModEvals = do_evaluation_list({"moduleimpl_id": e["moduleimpl_id"]})
|
||||
# log('ModEvals=%s' % [ x['evaluation_id'] for x in ModEvals] )
|
||||
if len(ModEvals) > 1:
|
||||
idx = [p["evaluation_id"] for p in ModEvals].index(evaluation_id)
|
||||
|
@ -999,18 +979,20 @@ def module_evaluation_move(context, evaluation_id, after=0, REQUEST=None, redire
|
|||
if neigh: #
|
||||
# swap numero with neighbor
|
||||
e["numero"], neigh["numero"] = neigh["numero"], e["numero"]
|
||||
do_evaluation_edit(context, REQUEST, e)
|
||||
do_evaluation_edit(context, REQUEST, neigh)
|
||||
do_evaluation_edit(e)
|
||||
do_evaluation_edit(neigh)
|
||||
# redirect to moduleimpl page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"moduleimpl_status?moduleimpl_id=" + e["moduleimpl_id"]
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=e["moduleimpl_id"],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def module_evaluation_renumber(
|
||||
context, moduleimpl_id, REQUEST=None, only_if_unumbered=False, redirect=0
|
||||
):
|
||||
def module_evaluation_renumber(moduleimpl_id, only_if_unumbered=False, redirect=0):
|
||||
"""Renumber evaluations in this module, according to their date. (numero=0: oldest one)
|
||||
Needed because previous versions of ScoDoc did not have eval numeros
|
||||
Note: existing numeros are ignored
|
||||
|
@ -1020,7 +1002,6 @@ def module_evaluation_renumber(
|
|||
# List sorted according to date/heure, ignoring numeros:
|
||||
# (note that we place evaluations with NULL date at the end)
|
||||
ModEvals = do_evaluation_list(
|
||||
context,
|
||||
args={"moduleimpl_id": moduleimpl_id},
|
||||
sortkey="jour asc, heure_debut asc",
|
||||
)
|
||||
|
@ -1034,24 +1015,29 @@ def module_evaluation_renumber(
|
|||
i = 1
|
||||
for e in ModEvals:
|
||||
e["numero"] = i
|
||||
do_evaluation_edit(context, REQUEST, e)
|
||||
do_evaluation_edit(e)
|
||||
i += 1
|
||||
|
||||
# If requested, redirect to moduleimpl page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"moduleimpl_status?moduleimpl_id=" + moduleimpl_id
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=moduleimpl_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# -------------- VIEWS
|
||||
def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=None):
|
||||
def evaluation_describe(evaluation_id="", edit_in_place=True, REQUEST=None):
|
||||
"""HTML description of evaluation, for page headers
|
||||
edit_in_place: allow in-place editing when permitted (not implemented)
|
||||
"""
|
||||
context = None # #context
|
||||
from app.scodoc import sco_saisie_notes
|
||||
|
||||
E = do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
moduleimpl_id = E["moduleimpl_id"]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||
Mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
|
||||
|
@ -1060,7 +1046,7 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||
resp = u["prenomnom"]
|
||||
nomcomplet = u["nomcomplet"]
|
||||
can_edit = sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, moduleimpl_id, allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, moduleimpl_id, allow_ens=False
|
||||
)
|
||||
|
||||
link = (
|
||||
|
@ -1097,7 +1083,7 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||
% (jour, E["heure_debut"], E["heure_fin"])
|
||||
)
|
||||
if E["jour"]:
|
||||
group_id = sco_groups.get_default_group(context, formsemestre_id)
|
||||
group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
H.append(
|
||||
'<span class="noprint"><a href="%s/Absences/EtatAbsencesDate?group_ids=%s&date=%s">(absences ce jour)</a></span>'
|
||||
% (
|
||||
|
@ -1122,7 +1108,6 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||
|
||||
|
||||
def evaluation_create_form(
|
||||
context,
|
||||
moduleimpl_id=None,
|
||||
evaluation_id=None,
|
||||
REQUEST=None,
|
||||
|
@ -1131,8 +1116,9 @@ def evaluation_create_form(
|
|||
page_title="Evaluation",
|
||||
):
|
||||
"formulaire creation/edition des evaluations (pas des notes)"
|
||||
context = None # #context
|
||||
if evaluation_id != None:
|
||||
the_eval = do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
the_eval = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
moduleimpl_id = the_eval["moduleimpl_id"]
|
||||
#
|
||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||
|
@ -1142,18 +1128,16 @@ def evaluation_create_form(
|
|||
formsemestre_id = M["formsemestre_id"]
|
||||
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
||||
if not readonly:
|
||||
if not sco_permissions_check.can_edit_evaluation(
|
||||
context, REQUEST, moduleimpl_id=moduleimpl_id
|
||||
):
|
||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "<h2>Opération non autorisée</h2><p>"
|
||||
+ "Modification évaluation impossible pour %s"
|
||||
% scu.get_current_user_name(REQUEST)
|
||||
% current_user.get_nomplogin()
|
||||
+ "</p>"
|
||||
+ '<p><a href="moduleimpl_status?moduleimpl_id=%s">Revenir</a></p>'
|
||||
% (moduleimpl_id,)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
if readonly:
|
||||
edit = True # montre les donnees existantes
|
||||
|
@ -1187,7 +1171,7 @@ def evaluation_create_form(
|
|||
action = "Modification d'une é"
|
||||
link = ""
|
||||
# Note maximale actuelle dans cette eval ?
|
||||
etat = do_evaluation_etat(context, evaluation_id)
|
||||
etat = do_evaluation_etat(evaluation_id)
|
||||
if etat["maxi_num"] is not None:
|
||||
min_note_max = max(scu.NOTES_PRECISION, etat["maxi_num"])
|
||||
else:
|
||||
|
@ -1242,7 +1226,7 @@ def evaluation_create_form(
|
|||
if not readonly:
|
||||
H = ["<h3>%svaluation en %s</h3>" % (action, mod_descr)]
|
||||
else:
|
||||
return evaluation_describe(context, evaluation_id, REQUEST=REQUEST)
|
||||
return evaluation_describe(evaluation_id, REQUEST=REQUEST)
|
||||
|
||||
heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)]
|
||||
#
|
||||
|
@ -1376,17 +1360,10 @@ def evaluation_create_form(
|
|||
|
||||
dest_url = "moduleimpl_status?moduleimpl_id=%s" % M["moduleimpl_id"]
|
||||
if tf[0] == 0:
|
||||
head = html_sco_header.sco_header(context, REQUEST, page_title=page_title)
|
||||
return (
|
||||
head
|
||||
+ "\n".join(H)
|
||||
+ "\n"
|
||||
+ tf[1]
|
||||
+ help
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
head = html_sco_header.sco_header(page_title=page_title)
|
||||
return head + "\n".join(H) + "\n" + tf[1] + help + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# form submission
|
||||
if tf[2]["visibulletinlist"]:
|
||||
|
@ -1395,8 +1372,8 @@ def evaluation_create_form(
|
|||
tf[2]["visibulletin"] = 0
|
||||
if not edit:
|
||||
# creation d'une evaluation
|
||||
evaluation_id = do_evaluation_create(context, REQUEST=REQUEST, **tf[2])
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
evaluation_id = do_evaluation_create(REQUEST=REQUEST, **tf[2])
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
do_evaluation_edit(context, REQUEST, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
do_evaluation_edit(tf[2])
|
||||
return flask.redirect(dest_url)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -102,9 +102,7 @@ def _build_results_table(context, start_date=None, end_date=None, types_parcours
|
|||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
html_class="table_leftalign",
|
||||
html_sortable=True,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return tab, semlist
|
||||
|
||||
|
@ -207,7 +205,6 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
|||
def get_set_formsemestre_id_dates(context, start_date, end_date):
|
||||
"""Ensemble des formsemestre_id entre ces dates"""
|
||||
s = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT formsemestre_id FROM notes_formsemestre WHERE date_debut >= %(start_date)s AND date_fin <= %(end_date)s",
|
||||
{"start_date": start_date, "end_date": end_date},
|
||||
)
|
||||
|
@ -281,8 +278,6 @@ def scodoc_table_results(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Export résultats",
|
||||
init_qtip=True,
|
||||
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
|
||||
|
@ -309,7 +304,7 @@ def scodoc_table_results(
|
|||
""",
|
||||
"\n".join(info_sems),
|
||||
"""</div>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
|
||||
"""Recherche d'étudiants
|
||||
"""
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
from flask_login import current_user
|
||||
|
||||
from scodoc_manager import sco_mgr
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -85,11 +87,9 @@ def form_search_etud(
|
|||
|
||||
if add_headers:
|
||||
return (
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Choix d'un étudiant"
|
||||
)
|
||||
html_sco_header.sco_header(page_title="Choix d'un étudiant")
|
||||
+ "\n".join(H)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
else:
|
||||
return "\n".join(H)
|
||||
|
@ -98,8 +98,8 @@ def form_search_etud(
|
|||
def search_etud_in_dept(context, expnom="", REQUEST=None):
|
||||
"""Page recherche d'un etudiant.
|
||||
|
||||
Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats, la liste des étudianst
|
||||
correspondants.
|
||||
Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats,
|
||||
la liste des étudiants correspondants.
|
||||
Appelée par boite de recherche barre latérale gauche.
|
||||
|
||||
Args:
|
||||
|
@ -109,15 +109,15 @@ def search_etud_in_dept(context, expnom="", REQUEST=None):
|
|||
etuds = sco_etud.get_etud_info(filled=1, etudid=expnom, REQUEST=REQUEST)
|
||||
if len(etuds) != 1:
|
||||
if scu.is_valid_code_nip(expnom):
|
||||
etuds = search_etuds_infos(context, code_nip=expnom, REQUEST=REQUEST)
|
||||
etuds = search_etuds_infos(code_nip=expnom)
|
||||
else:
|
||||
etuds = search_etuds_infos(context, expnom=expnom, REQUEST=REQUEST)
|
||||
etuds = search_etuds_infos(expnom=expnom)
|
||||
else:
|
||||
etuds = [] # si expnom est trop court, n'affiche rien
|
||||
|
||||
if len(etuds) == 1:
|
||||
# va directement a la fiche
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etuds[0]["etudid"]
|
||||
)
|
||||
|
@ -125,12 +125,10 @@ def search_etud_in_dept(context, expnom="", REQUEST=None):
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
page_title="Recherche d'un étudiant",
|
||||
no_side_bar=True,
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
REQUEST=REQUEST,
|
||||
),
|
||||
"""<h2>%d résultats pour "%s": choisissez un étudiant:</h2>"""
|
||||
% (len(etuds), expnom),
|
||||
|
@ -165,9 +163,7 @@ def search_etud_in_dept(context, expnom="", REQUEST=None):
|
|||
rows=etuds,
|
||||
html_sortable=True,
|
||||
html_class="table_leftalign",
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
H.append(tab.html())
|
||||
if len(etuds) > 20: # si la page est grande
|
||||
|
@ -184,11 +180,11 @@ def search_etud_in_dept(context, expnom="", REQUEST=None):
|
|||
H.append(
|
||||
"""<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP de l'étudiant</p>"""
|
||||
)
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
# Was chercheEtudsInfo()
|
||||
def search_etuds_infos(context, expnom=None, code_nip=None, REQUEST=None):
|
||||
def search_etuds_infos(expnom=None, code_nip=None):
|
||||
"""recherche les étudiants correspondants à expnom ou au code_nip
|
||||
et ramene liste de mappings utilisables en DTML.
|
||||
"""
|
||||
|
@ -223,7 +219,6 @@ def search_etud_by_name(context, term, REQUEST=None):
|
|||
else:
|
||||
if may_be_nip:
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT nom, prenom, code_nip FROM identite WHERE code_nip LIKE %(beginning)s ORDER BY nom",
|
||||
{"beginning": term + "%"},
|
||||
)
|
||||
|
@ -237,7 +232,6 @@ def search_etud_by_name(context, term, REQUEST=None):
|
|||
]
|
||||
else:
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT etudid, nom, prenom FROM identite WHERE nom LIKE %(beginning)s ORDER BY nom",
|
||||
{"beginning": term + "%"},
|
||||
)
|
||||
|
@ -256,50 +250,31 @@ def search_etud_by_name(context, term, REQUEST=None):
|
|||
# ---------- Recherche sur plusieurs département
|
||||
|
||||
|
||||
def form_search_etud_in_accessible_depts(context, REQUEST):
|
||||
"""Form recherche etudiants pour page accueil ScoDoc"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
# present form only to authenticated users
|
||||
if not authuser.has_role("Authenticated"):
|
||||
return ""
|
||||
return """<form action="table_etud_in_accessible_depts" method="POST">
|
||||
<b>Chercher étudiant:</b>
|
||||
<input type="text" name="expnom" width="12" spellcheck="false" value="">
|
||||
<input type="submit" value="Chercher">
|
||||
<br/>(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
|
||||
def search_etud_in_accessible_depts(expnom=None, code_nip=None):
|
||||
"""
|
||||
|
||||
|
||||
def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST=None):
|
||||
"""
|
||||
context est le ZScoDoc
|
||||
result is a list of (sorted) etuds, one list per dept.
|
||||
"""
|
||||
result = []
|
||||
accessible_depts = []
|
||||
depts = sco_mgr.get_dept_ids()
|
||||
for dept in depts:
|
||||
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept))
|
||||
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoView, dept=dept):
|
||||
if current_user.has_permission(Permission.ScoView, dept=dept):
|
||||
if expnom or code_nip:
|
||||
accessible_depts.append(dept.Scolarite.DeptId())
|
||||
etuds = search_etuds_infos(
|
||||
dept.Scolarite, expnom=expnom, code_nip=code_nip, REQUEST=REQUEST
|
||||
)
|
||||
accessible_depts.append(dept)
|
||||
ndb.set_sco_dept(dept)
|
||||
etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip)
|
||||
else:
|
||||
etuds = []
|
||||
result.append(etuds)
|
||||
return result, accessible_depts
|
||||
|
||||
|
||||
def table_etud_in_accessible_depts(context, expnom=None, REQUEST=None):
|
||||
def table_etud_in_accessible_depts(expnom=None):
|
||||
"""
|
||||
Page avec table étudiants trouvés, dans tous les departements.
|
||||
Attention: nous sommes ici au niveau de ScoDoc, pas dans un département
|
||||
"""
|
||||
result, accessible_depts = search_etud_in_accessible_depts(
|
||||
context, expnom=expnom, REQUEST=REQUEST
|
||||
)
|
||||
result, accessible_depts = search_etud_in_accessible_depts(expnom=expnom)
|
||||
H = [
|
||||
"""<div class="table_etud_in_accessible_depts">""",
|
||||
"""<h3>Recherche multi-département de "<tt>%s</tt>"</h3>""" % expnom,
|
||||
|
@ -330,16 +305,17 @@ def table_etud_in_accessible_depts(context, expnom=None, REQUEST=None):
|
|||
else:
|
||||
ss = ""
|
||||
H.append(
|
||||
"""<p>(recherche menée dans le%s département%s: %s)</p><p>
|
||||
<a href=".." class="stdlink">Retour à l'accueil</a></p>"""
|
||||
% (ss, ss, ", ".join(accessible_depts))
|
||||
f"""<p>(recherche menée dans le{ss} département{ss}:
|
||||
{", ".join(accessible_depts)})
|
||||
</p>
|
||||
<p>
|
||||
<a href="{url_for("scodoc.index")}" class="stdlink">Retour à l'accueil</a>
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
H.append("</div>")
|
||||
|
||||
return (
|
||||
html_sco_header.scodoc_top_html_header(
|
||||
context, REQUEST, page_title="Choix d'un étudiant"
|
||||
)
|
||||
html_sco_header.scodoc_top_html_header(page_title="Choix d'un étudiant")
|
||||
+ "\n".join(H)
|
||||
+ html_sco_header.standard_html_footer()
|
||||
)
|
||||
|
@ -352,9 +328,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
|||
Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc:
|
||||
code_nip, nom, prenom, civilite_str, dept, formsemestre_id, date_debut_sem, date_fin_sem
|
||||
"""
|
||||
result, _ = search_etud_in_accessible_depts(
|
||||
context, code_nip=code_nip, REQUEST=REQUEST
|
||||
)
|
||||
result, _ = search_etud_in_accessible_depts(code_nip=code_nip)
|
||||
|
||||
T = []
|
||||
for etuds in result:
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
from operator import itemgetter
|
||||
import xml.dom.minidom
|
||||
|
||||
import flask
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -134,13 +136,22 @@ def formation_export(
|
|||
)
|
||||
|
||||
|
||||
def formation_import_xml(context, REQUEST, doc, import_tags=True):
|
||||
def formation_import_xml(context, doc, import_tags=True):
|
||||
"""Create a formation from XML representation
|
||||
(format dumped by formation_export( format='xml' ))
|
||||
XML may contain object (UE, modules) ids: this function returns two
|
||||
dicts mapping these ids to the created ids.
|
||||
|
||||
Args:
|
||||
doc: str, xml data
|
||||
import_tags: if false, does not import tags on modules.
|
||||
|
||||
Returns:
|
||||
formation_id, modules_old2new, ues_old2new
|
||||
"""
|
||||
from app.scodoc import sco_edit_formation
|
||||
|
||||
log("formation_import_xml: doc=%s" % doc)
|
||||
# log("formation_import_xml: doc=%s" % doc)
|
||||
try:
|
||||
dom = xml.dom.minidom.parseString(doc)
|
||||
except:
|
||||
|
@ -175,7 +186,7 @@ def formation_import_xml(context, REQUEST, doc, import_tags=True):
|
|||
# create formation
|
||||
# F_unquoted = F.copy()
|
||||
# unescape_html_dict(F_unquoted)
|
||||
formation_id = sco_edit_formation.do_formation_create(context, F, REQUEST)
|
||||
formation_id = sco_edit_formation.do_formation_create(context, F)
|
||||
log("formation %s created" % formation_id)
|
||||
ues_old2new = {} # xml ue_id : new ue_id
|
||||
modules_old2new = {} # xml module_id : new module_id
|
||||
|
@ -189,14 +200,14 @@ def formation_import_xml(context, REQUEST, doc, import_tags=True):
|
|||
del ue_info[1]["ue_id"]
|
||||
else:
|
||||
xml_ue_id = None
|
||||
ue_id = sco_edit_ue.do_ue_create(context, ue_info[1], REQUEST)
|
||||
ue_id = sco_edit_ue.do_ue_create(context, ue_info[1])
|
||||
if xml_ue_id:
|
||||
ues_old2new[xml_ue_id] = ue_id
|
||||
# -- create matieres
|
||||
for mat_info in ue_info[2]:
|
||||
assert mat_info[0] == "matiere"
|
||||
mat_info[1]["ue_id"] = ue_id
|
||||
mat_id = sco_edit_matiere.do_matiere_create(context, mat_info[1], REQUEST)
|
||||
mat_id = sco_edit_matiere.do_matiere_create(context, mat_info[1])
|
||||
# -- create modules
|
||||
for mod_info in mat_info[2]:
|
||||
assert mod_info[0] == "module"
|
||||
|
@ -208,7 +219,7 @@ def formation_import_xml(context, REQUEST, doc, import_tags=True):
|
|||
mod_info[1]["formation_id"] = formation_id
|
||||
mod_info[1]["matiere_id"] = mat_id
|
||||
mod_info[1]["ue_id"] = ue_id
|
||||
mod_id = sco_edit_module.do_module_create(context, mod_info[1], REQUEST)
|
||||
mod_id = sco_edit_module.do_module_create(context, mod_info[1])
|
||||
if xml_module_id:
|
||||
modules_old2new[xml_module_id] = mod_id
|
||||
if import_tags:
|
||||
|
@ -248,6 +259,7 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||
f["parcours_name"] = ""
|
||||
f["_titre_target"] = "ue_list?formation_id=%(formation_id)s" % f
|
||||
f["_titre_link_class"] = "stdlink"
|
||||
f["_titre_id"] = "titre-%s" % f["acronyme"].lower().replace(" ", "-")
|
||||
# Ajoute les semestres associés à chaque formation:
|
||||
f["sems"] = sco_formsemestre.do_formsemestre_list(
|
||||
context, args={"formation_id": f["formation_id"]}
|
||||
|
@ -255,13 +267,14 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||
f["sems_list_txt"] = ", ".join([s["session_id"] for s in f["sems"]])
|
||||
f["_sems_list_txt_html"] = ", ".join(
|
||||
[
|
||||
'<a class="discretelink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(session_id)s<a>'
|
||||
% s
|
||||
'<a class="discretelink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%('
|
||||
"session_id)s<a> " % s
|
||||
for s in f["sems"]
|
||||
]
|
||||
+ [
|
||||
'<a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">ajouter</a>'
|
||||
% f
|
||||
'<a class="stdlink" id="add-semestre-%s" '
|
||||
'href="formsemestre_createwithmodules?formation_id=%s&semestre_id=1">ajouter</a> '
|
||||
% (f["acronyme"].lower().replace(" ", "-"), f["formation_id"])
|
||||
]
|
||||
)
|
||||
if f["sems"]:
|
||||
|
@ -277,16 +290,17 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||
else:
|
||||
but_locked = '<span class="but_placeholder"></span>'
|
||||
if editable and not locked:
|
||||
but_suppr = (
|
||||
'<a class="stdlink" href="formation_delete?formation_id=%s">%s</a>'
|
||||
% (f["formation_id"], suppricon)
|
||||
but_suppr = '<a class="stdlink" href="formation_delete?formation_id=%s" id="delete-formation-%s">%s</a>' % (
|
||||
f["formation_id"],
|
||||
f["acronyme"].lower().replace(" ", "-"),
|
||||
suppricon,
|
||||
)
|
||||
else:
|
||||
but_suppr = '<span class="but_placeholder"></span>'
|
||||
if editable:
|
||||
but_edit = (
|
||||
'<a class="stdlink" href="formation_edit?formation_id=%s">%s</a>'
|
||||
% (f["formation_id"], editicon)
|
||||
'<a class="stdlink" href="formation_edit?formation_id=%s" id="edit-formation-%s">%s</a>'
|
||||
% (f["formation_id"], f["acronyme"].lower().replace(" ", "-"), editicon)
|
||||
)
|
||||
else:
|
||||
but_edit = '<span class="but_placeholder"></span>'
|
||||
|
@ -334,28 +348,24 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||
base_url="%s?formation_id=%s" % (REQUEST.URL0, formation_id),
|
||||
page_title=title,
|
||||
pdf_title=title,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
|
||||
|
||||
def formation_create_new_version(context, formation_id, redirect=True, REQUEST=None):
|
||||
"duplicate formation, with new version number"
|
||||
xml = formation_export(context, formation_id, export_ids=True, format="xml")
|
||||
new_id, modules_old2new, ues_old2new = formation_import_xml(context, REQUEST, xml)
|
||||
new_id, modules_old2new, ues_old2new = formation_import_xml(context, xml)
|
||||
# news
|
||||
F = formation_list(context, args={"formation_id": new_id})[0]
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=new_id,
|
||||
text="Nouvelle version de la formation %(acronyme)s" % F,
|
||||
)
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"ue_list?formation_id=" + new_id + "&msg=Nouvelle version !"
|
||||
)
|
||||
else:
|
||||
return new_id, modules_old2new, ues_old2new
|
||||
return new_id, modules_old2new, ues_old2new
|
||||
|
|
|
@ -219,8 +219,9 @@ def etapes_apo_str(etapes):
|
|||
return ", ".join([str(x) for x in etapes])
|
||||
|
||||
|
||||
def do_formsemestre_create(context, args, REQUEST, silent=False):
|
||||
def do_formsemestre_create(args, silent=False):
|
||||
"create a formsemestre"
|
||||
context = None # XXX #context
|
||||
from app.scodoc import sco_groups
|
||||
from app.scodoc import sco_news
|
||||
|
||||
|
@ -235,11 +236,12 @@ def do_formsemestre_create(context, args, REQUEST, silent=False):
|
|||
|
||||
# create default partition
|
||||
partition_id = sco_groups.partition_create(
|
||||
context, formsemestre_id, default=True, redirect=0, REQUEST=REQUEST
|
||||
)
|
||||
_group_id = sco_groups.createGroup(
|
||||
context, partition_id, default=True, REQUEST=REQUEST
|
||||
context,
|
||||
formsemestre_id,
|
||||
default=True,
|
||||
redirect=0,
|
||||
)
|
||||
_group_id = sco_groups.createGroup(context, partition_id, default=True)
|
||||
|
||||
# news
|
||||
if "titre" not in args:
|
||||
|
@ -248,8 +250,6 @@ def do_formsemestre_create(context, args, REQUEST, silent=False):
|
|||
args["url"] = "Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s" % args
|
||||
if not silent:
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_SEM,
|
||||
text='Création du semestre <a href="%(url)s">%(titre)s</a>' % args,
|
||||
url=args["url"],
|
||||
|
@ -277,7 +277,6 @@ def read_formsemestre_responsables(context, formsemestre_id):
|
|||
:returns: liste de chaines
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT responsable_id FROM notes_formsemestre_responsables WHERE formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -340,7 +339,6 @@ def read_formsemestre_etapes(context, formsemestre_id):
|
|||
:returns: liste d'instance de ApoEtapeVDI
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT etape_apo FROM notes_formsemestre_etapes WHERE formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -410,7 +408,7 @@ def sem_in_semestre_scolaire(context, sem, year=False, saison=0, REQUEST=None):
|
|||
)
|
||||
"""
|
||||
if not year:
|
||||
year = scu.AnneeScolaire(REQUEST)
|
||||
year = scu.AnneeScolaire()
|
||||
# est-on dans la même année universitaire ?
|
||||
if sem["mois_debut_ord"] > 7:
|
||||
if sem["annee_debut"] != str(year):
|
||||
|
@ -434,7 +432,7 @@ def sem_in_annee_scolaire(context, sem, year=False, REQUEST=None):
|
|||
Si annee non specifiée, année scolaire courante
|
||||
"""
|
||||
if not year:
|
||||
year = scu.AnneeScolaire(REQUEST)
|
||||
year = scu.AnneeScolaire()
|
||||
return ((sem["annee_debut"] == str(year)) and (sem["mois_debut_ord"] > 7)) or (
|
||||
(sem["annee_debut"] == str(year + 1)) and (sem["mois_debut_ord"] <= 7)
|
||||
)
|
||||
|
@ -518,13 +516,9 @@ def table_formsemestres(
|
|||
"etapes_apo_str": "Apo.",
|
||||
}
|
||||
if sems:
|
||||
preferences = sco_preferences.SemPreferences(
|
||||
context, sems[0]["formsemestre_id"]
|
||||
)
|
||||
preferences = sco_preferences.SemPreferences(sems[0]["formsemestre_id"])
|
||||
else:
|
||||
preferences = sco_preferences.SemPreferences(
|
||||
context,
|
||||
)
|
||||
preferences = sco_preferences.SemPreferences()
|
||||
tab = GenTable(
|
||||
columns_ids=columns_ids,
|
||||
rows=sems,
|
||||
|
@ -580,7 +574,7 @@ def view_formsemestre_by_etape(context, etape_apo=None, format="html", REQUEST=N
|
|||
tab = table_formsemestres(
|
||||
context,
|
||||
list_formsemestre_by_etape(
|
||||
context, etape_apo=etape_apo, annee_scolaire=scu.AnneeScolaire(REQUEST)
|
||||
context, etape_apo=etape_apo, annee_scolaire=scu.AnneeScolaire()
|
||||
),
|
||||
html_title=html_title,
|
||||
html_next_section="""<form action="view_formsemestre_by_etape">
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
"""Menu "custom" (défini par l'utilisateur) dans les semestres
|
||||
"""
|
||||
|
||||
import flask
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -128,11 +128,9 @@ def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
|||
name="tf",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H) + "\n" + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + "\n" + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# form submission
|
||||
cnx = ndb.GetDBConnexion()
|
||||
|
@ -159,4 +157,4 @@ def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
|||
"url": tf[2]["url_" + custommenu_id],
|
||||
},
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
"""Form choix modules / responsables et creation formsemestre
|
||||
"""
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
from app.auth.models import User
|
||||
|
||||
|
@ -68,8 +69,6 @@ def formsemestre_createwithmodules(context, REQUEST=None):
|
|||
"""Page création d'un semestre"""
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Création d'un semestre",
|
||||
javascripts=["libjs/AutoSuggest.js"],
|
||||
cssstyles=["css/autosuggest_inquisitor.css"],
|
||||
|
@ -82,7 +81,7 @@ def formsemestre_createwithmodules(context, REQUEST=None):
|
|||
H.append(r)
|
||||
else:
|
||||
return r # response redirect
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
||||
|
@ -119,7 +118,7 @@ def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
|||
<p class="help">Les modules ont toujours un responsable. Par défaut, c'est le directeur des études.</p>"""
|
||||
)
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def can_edit_sem(context, REQUEST, formsemestre_id="", sem=None):
|
||||
|
@ -412,7 +411,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
"title": "Element(s) Apogée:",
|
||||
"explanation": "du semestre (ex: VRTW1). Séparés par des virgules.",
|
||||
"allow_null": not sco_preferences.get_preference(
|
||||
context, "always_require_apo_sem_codes"
|
||||
"always_require_apo_sem_codes"
|
||||
),
|
||||
},
|
||||
)
|
||||
|
@ -425,7 +424,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
"title": "Element(s) Apogée:",
|
||||
"explanation": "de l'année (ex: VRT1A). Séparés par des virgules.",
|
||||
"allow_null": not sco_preferences.get_preference(
|
||||
context, "always_require_apo_sem_codes"
|
||||
"always_require_apo_sem_codes"
|
||||
),
|
||||
},
|
||||
)
|
||||
|
@ -552,9 +551,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
else:
|
||||
disabled = ""
|
||||
fcg = '<select name="%s" %s>' % (select_name, disabled)
|
||||
default_group_id = sco_groups.get_default_group(
|
||||
context, formsemestre_id
|
||||
)
|
||||
default_group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
fcg += '<option value="%s" %s>Tous</option>' % (
|
||||
default_group_id,
|
||||
opt_selected(default_group_id),
|
||||
|
@ -676,9 +673,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
# check dates
|
||||
if ndb.DateDMYtoISO(tf[2]["date_debut"]) > ndb.DateDMYtoISO(tf[2]["date_fin"]):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Dates de début et fin incompatibles !</li></ul>'
|
||||
if sco_preferences.get_preference(
|
||||
context, "always_require_apo_sem_codes"
|
||||
) and not any(
|
||||
if sco_preferences.get_preference("always_require_apo_sem_codes") and not any(
|
||||
[tf[2]["etape_apo" + str(n)] for n in range(0, scu.EDIT_NB_ETAPES + 1)]
|
||||
):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Code étape Apogée manquant</li></ul>'
|
||||
|
@ -738,9 +733,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
)
|
||||
if not edit:
|
||||
# creation du semestre
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(
|
||||
context, tf[2], REQUEST
|
||||
)
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(tf[2])
|
||||
# creation des modules
|
||||
for module_id in tf[2]["tf-checked"]:
|
||||
modargs = {
|
||||
|
@ -749,7 +742,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
"responsable_id": tf[2][module_id],
|
||||
}
|
||||
_ = sco_moduleimpl.do_moduleimpl_create(context, modargs)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
||||
% formsemestre_id
|
||||
)
|
||||
|
@ -853,7 +846,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||
)
|
||||
return msg_html
|
||||
else:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Semestre modifié"
|
||||
% formsemestre_id
|
||||
)
|
||||
|
@ -873,9 +866,7 @@ def formsemestre_delete_moduleimpls(context, formsemestre_id, module_ids_to_del)
|
|||
)[0]["moduleimpl_id"]
|
||||
mod = sco_edit_module.do_module_list(context, {"module_id": module_id})[0]
|
||||
# Evaluations dans ce module ?
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"moduleimpl_id": moduleimpl_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||
if evals:
|
||||
msg += [
|
||||
'<b>impossible de supprimer %s (%s) car il y a %d évaluations définies (<a href="moduleimpl_status?moduleimpl_id=%s" class="stdlink">supprimer les d\'abord</a>)</b>'
|
||||
|
@ -997,9 +988,9 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
|||
if ndb.DateDMYtoISO(tf[2]["date_debut"]) > ndb.DateDMYtoISO(tf[2]["date_fin"]):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Dates de début et fin incompatibles !</li></ul>'
|
||||
if tf[0] == 0 or msg:
|
||||
return "".join(H) + msg + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "".join(H) + msg + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1: # cancel
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
else:
|
||||
|
@ -1013,7 +1004,7 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
|||
clone_partitions=tf[2]["clone_partitions"],
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
||||
% new_formsemestre_id
|
||||
)
|
||||
|
@ -1042,7 +1033,7 @@ def do_formsemestre_clone(
|
|||
args["date_debut"] = date_debut
|
||||
args["date_fin"] = date_fin
|
||||
args["etat"] = 1 # non verrouillé
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(context, args, REQUEST)
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(args)
|
||||
log("created formsemestre %s" % formsemestre_id)
|
||||
# 2- create moduleimpls
|
||||
mods_orig = sco_moduleimpl.do_moduleimpl_list(
|
||||
|
@ -1063,15 +1054,13 @@ def do_formsemestre_clone(
|
|||
# optionally, copy evaluations
|
||||
if clone_evaluations:
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": mod_orig["moduleimpl_id"]}
|
||||
args={"moduleimpl_id": mod_orig["moduleimpl_id"]}
|
||||
)
|
||||
for e in evals:
|
||||
args = e.copy()
|
||||
del args["jour"] # erase date
|
||||
args["moduleimpl_id"] = mid
|
||||
_ = sco_evaluations.do_evaluation_create(
|
||||
context, REQUEST=REQUEST, **args
|
||||
)
|
||||
_ = sco_evaluations.do_evaluation_create(REQUEST=REQUEST, **args)
|
||||
|
||||
# 3- copy uecoefs
|
||||
objs = sco_formsemestre.formsemestre_uecoef_list(
|
||||
|
@ -1085,7 +1074,7 @@ def do_formsemestre_clone(
|
|||
# NB: don't copy notes_formsemestre_custommenu (usually specific)
|
||||
|
||||
# 4- Copy new style preferences
|
||||
prefs = sco_preferences.SemPreferences(context, orig_formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(orig_formsemestre_id)
|
||||
|
||||
if orig_formsemestre_id in prefs.base_prefs.prefs:
|
||||
for pname in prefs.base_prefs.prefs[orig_formsemestre_id]:
|
||||
|
@ -1120,7 +1109,6 @@ def do_formsemestre_clone(
|
|||
context,
|
||||
formsemestre_id,
|
||||
partition_name=partname,
|
||||
REQUEST=REQUEST,
|
||||
redirect=0,
|
||||
)
|
||||
for g in sco_groups.get_partition_groups(context, part):
|
||||
|
@ -1136,7 +1124,7 @@ def do_formsemestre_clone(
|
|||
part_id = g[0]
|
||||
for group_name in g[1]:
|
||||
_ = sco_groups.createGroup(
|
||||
context, part_id, group_name=group_name, REQUEST=REQUEST
|
||||
context, part_id, group_name=group_name
|
||||
)
|
||||
|
||||
return formsemestre_id
|
||||
|
@ -1186,7 +1174,6 @@ def formsemestre_associate_new_version(
|
|||
)
|
||||
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Associer à une nouvelle version de formation non verrouillée ?</h2>
|
||||
<p>Le programme pédagogique ("formation") va être dupliqué pour que vous puissiez le modifier sans affecter les autres semestres. Les autres paramètres (étudiants, notes...) du semestre seront inchangés.</p>
|
||||
<p>Veillez à ne pas abuser de cette possibilité, car créer trop de versions de formations va vous compliquer la gestion (à vous de garder trace des différences et à ne pas vous tromper par la suite...).
|
||||
|
@ -1196,7 +1183,6 @@ def formsemestre_associate_new_version(
|
|||
+ "</div>",
|
||||
OK="Associer ces semestres à une nouvelle version",
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id,
|
||||
parameters={"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -1204,7 +1190,7 @@ def formsemestre_associate_new_version(
|
|||
do_formsemestres_associate_new_version(
|
||||
context, [formsemestre_id] + other_formsemestre_ids, REQUEST=REQUEST
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Formation%%20dupliquée"
|
||||
% formsemestre_id
|
||||
)
|
||||
|
@ -1299,7 +1285,7 @@ def formsemestre_delete(context, formsemestre_id, REQUEST=None):
|
|||
</ol></div>""",
|
||||
]
|
||||
|
||||
evals = sco_evaluations.do_evaluation_list_in_formsemestre(context, formsemestre_id)
|
||||
evals = sco_evaluations.do_evaluation_list_in_formsemestre(formsemestre_id)
|
||||
if evals:
|
||||
H.append(
|
||||
"""<p class="warning">Attention: il y a %d évaluations dans ce semestre (sa suppression entrainera l'effacement définif des notes) !</p>"""
|
||||
|
@ -1326,15 +1312,13 @@ def formsemestre_delete(context, formsemestre_id, REQUEST=None):
|
|||
)
|
||||
else:
|
||||
H.append(tf[1])
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1: # cancel
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
scu.NotesURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
else:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_delete2?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
return flask.redirect("formsemestre_delete2?formsemestre_id=" + formsemestre_id)
|
||||
|
||||
|
||||
def formsemestre_delete2(
|
||||
|
@ -1344,16 +1328,14 @@ def formsemestre_delete2(
|
|||
# Confirmation dialog
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Vous voulez vraiment supprimer ce semestre ???</h2><p>(opération irréversible)</p>""",
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id,
|
||||
parameters={"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
# Bon, s'il le faut...
|
||||
do_formsemestre_delete(context, formsemestre_id, REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(scu.ScoURL() + "?head_message=Semestre%20supprimé")
|
||||
do_formsemestre_delete(context, formsemestre_id)
|
||||
return flask.redirect(scu.ScoURL() + "?head_message=Semestre%20supprimé")
|
||||
|
||||
|
||||
def formsemestre_has_decisions_or_compensations(context, formsemestre_id):
|
||||
|
@ -1361,14 +1343,13 @@ def formsemestre_has_decisions_or_compensations(context, formsemestre_id):
|
|||
ou bien compensation de ce semestre par d'autre ssemestres.
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT v.* FROM scolar_formsemestre_validation v WHERE v.formsemestre_id = %(formsemestre_id)s OR v.compense_formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
return r
|
||||
|
||||
|
||||
def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
||||
def do_formsemestre_delete(context, formsemestre_id):
|
||||
"""delete formsemestre, and all its moduleimpls.
|
||||
No checks, no warnings: erase all !
|
||||
"""
|
||||
|
@ -1382,21 +1363,18 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
|||
for mod in mods:
|
||||
# evaluations
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": mod["moduleimpl_id"]}
|
||||
args={"moduleimpl_id": mod["moduleimpl_id"]}
|
||||
)
|
||||
for e in evals:
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_notes WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
)
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_notes_log WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
)
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_evaluation WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
)
|
||||
|
@ -1449,8 +1427,6 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
|||
from app.scodoc import sco_news
|
||||
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_SEM,
|
||||
object=formsemestre_id,
|
||||
text="Suppression du semestre %(titre)s" % sem,
|
||||
|
@ -1463,12 +1439,10 @@ def formsemestre_edit_options(context, formsemestre_id, target_url=None, REQUEST
|
|||
(accessible par ScoImplement ou dir. etudes)
|
||||
"""
|
||||
log("formsemestre_edit_options")
|
||||
ok, err = sco_permissions_check.check_access_diretud(
|
||||
context, formsemestre_id, REQUEST
|
||||
)
|
||||
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
||||
if not ok:
|
||||
return err
|
||||
return sco_preferences.SemPreferences(context, formsemestre_id).edit(
|
||||
return sco_preferences.SemPreferences(formsemestre_id).edit(
|
||||
REQUEST=REQUEST, categories=["bul"]
|
||||
)
|
||||
|
||||
|
@ -1479,9 +1453,7 @@ def formsemestre_change_lock(
|
|||
"""Change etat (verrouille si ouvert, déverrouille si fermé)
|
||||
nota: etat (1 ouvert, 0 fermé)
|
||||
"""
|
||||
ok, err = sco_permissions_check.check_access_diretud(
|
||||
context, formsemestre_id, REQUEST
|
||||
)
|
||||
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
||||
if not ok:
|
||||
return err
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
@ -1493,7 +1465,6 @@ def formsemestre_change_lock(
|
|||
else:
|
||||
msg = "verrouillage"
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"<h2>Confirmer le %s du semestre ?</h2>" % msg,
|
||||
helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées.
|
||||
Un semestre verrouillé peut cependant être déverrouillé facilement à tout moment
|
||||
|
@ -1502,7 +1473,6 @@ def formsemestre_change_lock(
|
|||
Le programme d'une formation qui a un semestre verrouillé ne peut plus être modifié.
|
||||
""",
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id,
|
||||
parameters={"etat": etat, "formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -1512,7 +1482,7 @@ def formsemestre_change_lock(
|
|||
args = {"formsemestre_id": formsemestre_id, "etat": etat}
|
||||
sco_formsemestre.do_formsemestre_edit(context, args)
|
||||
if REQUEST:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
|
||||
|
@ -1521,9 +1491,7 @@ def formsemestre_change_publication_bul(
|
|||
context, formsemestre_id, REQUEST=None, dialog_confirmed=False
|
||||
):
|
||||
"""Change etat publication bulletins sur portail"""
|
||||
ok, err = sco_permissions_check.check_access_diretud(
|
||||
context, formsemestre_id, REQUEST
|
||||
)
|
||||
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
||||
if not ok:
|
||||
return err
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
@ -1535,7 +1503,6 @@ def formsemestre_change_publication_bul(
|
|||
else:
|
||||
msg = ""
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"<h2>Confirmer la %s publication des bulletins ?</h2>" % msg,
|
||||
helpmsg="""Il est parfois utile de désactiver la diffusion des bulletins,
|
||||
par exemple pendant la tenue d'un jury ou avant harmonisation des notes.
|
||||
|
@ -1543,7 +1510,6 @@ def formsemestre_change_publication_bul(
|
|||
Ce réglage n'a d'effet que si votre établissement a interfacé ScoDoc et un portail étudiant.
|
||||
""",
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id,
|
||||
parameters={"bul_hide_xml": etat, "formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -1555,7 +1521,7 @@ def formsemestre_change_publication_bul(
|
|||
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
|
||||
sco_formsemestre.do_formsemestre_edit(context, args)
|
||||
if REQUEST:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
return None
|
||||
|
@ -1565,14 +1531,12 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||
"""Changement manuel des coefficients des UE capitalisées."""
|
||||
from app.scodoc import notes_table
|
||||
|
||||
ok, err = sco_permissions_check.check_access_diretud(
|
||||
context, formsemestre_id, REQUEST
|
||||
)
|
||||
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
||||
if not ok:
|
||||
return err
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
footer = html_sco_header.sco_footer()
|
||||
help = """<p class="help">
|
||||
Seuls les modules ont un coefficient. Cependant, il est nécessaire d'affecter un coefficient aux UE capitalisée pour pouvoir les prendre en compte dans la moyenne générale.
|
||||
</p>
|
||||
|
@ -1741,10 +1705,10 @@ def get_formsemestre_session_id(context, sem, F, parcours):
|
|||
# parcours = sco_codes_parcours.get_parcours_from_code(F['type_parcours'])
|
||||
|
||||
ImputationDept = sco_preferences.get_preference(
|
||||
context, "ImputationDept", sem["formsemestre_id"]
|
||||
"ImputationDept", sem["formsemestre_id"]
|
||||
)
|
||||
if not ImputationDept:
|
||||
ImputationDept = sco_preferences.get_preference(context, "DeptName")
|
||||
ImputationDept = sco_preferences.get_preference("DeptName")
|
||||
ImputationDept = ImputationDept.upper()
|
||||
parcours_type = parcours.NAME
|
||||
modalite = sem["modalite"]
|
||||
|
|
|
@ -33,6 +33,7 @@ Ces semestres n'auront qu'un seul inscrit !
|
|||
"""
|
||||
import time
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -65,9 +66,7 @@ def formsemestre_ext_create(context, etudid, sem_params, REQUEST=None):
|
|||
sem_params["modalite"] = "EXT"
|
||||
sem_params["etapes"] = None
|
||||
sem_params["responsables"] = [str(REQUEST.AUTHENTICATED_USER)]
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(
|
||||
context, sem_params, REQUEST, silent=True
|
||||
)
|
||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(sem_params, silent=True)
|
||||
# nota: le semestre est créé vide: pas de modules
|
||||
|
||||
# Inscription au semestre
|
||||
|
@ -85,7 +84,7 @@ def formsemestre_ext_create_form(context, etudid, formsemestre_id, REQUEST=None)
|
|||
"""Formulaire creation/inscription à un semestre extérieur"""
|
||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=1)[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST),
|
||||
html_sco_header.sco_header(),
|
||||
"""<h2>Enregistrement d'une inscription antérieure dans un autre établissement</h2>
|
||||
<p class="help">
|
||||
Cette opération créé un semestre extérieur ("ancien") et y inscrit juste cet étudiant.
|
||||
|
@ -105,7 +104,7 @@ def formsemestre_ext_create_form(context, etudid, formsemestre_id, REQUEST=None)
|
|||
etud["nomprenom"],
|
||||
),
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
orig_sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
# Ne propose que des semestres de semestre_id strictement inférieur au semestre courant
|
||||
# et seulement si pas inscrit au même semestre_id d'un semestre ordinaire ScoDoc.
|
||||
|
@ -201,14 +200,14 @@ def formsemestre_ext_create_form(context, etudid, formsemestre_id, REQUEST=None)
|
|||
)
|
||||
return "\n".join(H) + "\n" + tf[1] + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"%s/formsemestre_bulletinetud?formsemestre_id==%s&etudid=%s"
|
||||
% (scu.ScoURL(), formsemestre_id, etudid)
|
||||
)
|
||||
else:
|
||||
tf[2]["formation_id"] = orig_sem["formation_id"]
|
||||
formsemestre_ext_create(context, etudid, tf[2], REQUEST=REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
)
|
||||
|
||||
|
@ -260,7 +259,7 @@ def formsemestre_ext_edit_ue_validations(
|
|||
_record_ue_validations_and_coefs(
|
||||
context, formsemestre_id, etudid, ue_list, tf[2], REQUEST=REQUEST
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s"
|
||||
% (formsemestre_id, etudid)
|
||||
)
|
||||
|
@ -271,8 +270,6 @@ def _make_page(context, etud, sem, tf, message="", REQUEST=None):
|
|||
moy_gen = nt.get_etud_moy_gen(etud["etudid"])
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Validation des UE d'un semestre extérieur",
|
||||
javascripts=["js/formsemestre_ext_edit_ue_validations.js"],
|
||||
),
|
||||
|
@ -297,7 +294,7 @@ def _make_page(context, etud, sem, tf, message="", REQUEST=None):
|
|||
</a></div>
|
||||
"""
|
||||
% (sem["formsemestre_id"], etud["etudid"]),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return H
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"""
|
||||
import time
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -102,7 +103,6 @@ def do_formsemestre_inscription_create(context, args, REQUEST, method=None):
|
|||
)
|
||||
# Log etudiant
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method=method,
|
||||
etudid=args["etudid"],
|
||||
|
@ -187,13 +187,10 @@ def do_formsemestre_desinscription(context, etudid, formsemestre_id, REQUEST=Non
|
|||
"do_formsemestre_desinscription: suppression du semestre extérieur %s"
|
||||
% formsemestre_id
|
||||
)
|
||||
sco_formsemestre_edit.do_formsemestre_delete(
|
||||
context, formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
sco_formsemestre_edit.do_formsemestre_delete(context, formsemestre_id)
|
||||
|
||||
if REQUEST:
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="formsemestre_desinscription",
|
||||
etudid=etudid,
|
||||
|
@ -226,7 +223,7 @@ def do_formsemestre_inscription_with_modules(
|
|||
)
|
||||
# inscriptions aux groupes
|
||||
# 1- inscrit au groupe 'tous'
|
||||
group_id = sco_groups.get_default_group(context, formsemestre_id)
|
||||
group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
sco_groups.set_group(context, etudid, group_id)
|
||||
gdone = {group_id: 1} # empeche doublons
|
||||
|
||||
|
@ -279,7 +276,7 @@ def formsemestre_inscription_with_modules_form(
|
|||
"""
|
||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=1)[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST),
|
||||
html_sco_header.sco_header(),
|
||||
"<h2>Inscription de %s" % etud["nomprenom"],
|
||||
]
|
||||
if only_ext:
|
||||
|
@ -291,7 +288,7 @@ def formsemestre_inscription_with_modules_form(
|
|||
</p>
|
||||
<h3>Choisir un semestre:</h3>"""
|
||||
)
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
sems = sco_formsemestre.do_formsemestre_list(context, args={"etat": "1"})
|
||||
insem = do_formsemestre_inscription_list(
|
||||
context, args={"etudid": etudid, "etat": "I"}
|
||||
|
@ -348,7 +345,7 @@ def formsemestre_inscription_with_modules(
|
|||
sem,
|
||||
)
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
# Check 1: déjà inscrit ici ?
|
||||
ins = do_formsemestre_inscription_list(context, {"etudid": etudid})
|
||||
already = False
|
||||
|
@ -416,7 +413,7 @@ def formsemestre_inscription_with_modules(
|
|||
REQUEST=REQUEST,
|
||||
method="formsemestre_inscription_with_modules",
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
)
|
||||
else:
|
||||
|
@ -453,9 +450,9 @@ def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=No
|
|||
etud = sco_etud.get_etud_info(etudid=etudid, filled=1)[0]
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_ue_status
|
||||
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "<h2>Inscription de %s aux modules de %s (%s - %s)</h2>"
|
||||
% (etud["nomprenom"], sem["titre_num"], sem["date_debut"], sem["date_fin"])
|
||||
]
|
||||
|
@ -569,7 +566,7 @@ function chkbx_select(field_id, state) {
|
|||
)
|
||||
return "\n".join(H) + "\n" + tf[1] + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
)
|
||||
else:
|
||||
|
@ -725,13 +722,13 @@ def do_moduleimpl_incription_options(
|
|||
|
||||
if REQUEST:
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST),
|
||||
html_sco_header.sco_header(),
|
||||
"""<h3>Modifications effectuées</h3>
|
||||
<p><a class="stdlink" href="%s">
|
||||
Retour à la fiche étudiant</a></p>
|
||||
"""
|
||||
% url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -823,4 +820,4 @@ def formsemestre_inscrits_ailleurs(context, formsemestre_id, REQUEST=None):
|
|||
)
|
||||
else:
|
||||
H.append("""<p>Aucun étudiant en inscription multiple (c'est normal) !</p>""")
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
|
|
@ -28,12 +28,11 @@
|
|||
"""Tableau de bord semestre
|
||||
"""
|
||||
|
||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
import cgi
|
||||
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import request
|
||||
from flask import url_for
|
||||
from flask_login import current_user
|
||||
|
||||
from app.scodoc.notes_log import log
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -64,22 +63,6 @@ from app.scodoc.gen_tables import GenTable
|
|||
from app.scodoc.sco_formsemestre_custommenu import formsemestre_custommenu_html
|
||||
|
||||
|
||||
# H = [ """<span class="barrenav"><ul class="nav">
|
||||
# <li onmouseover="MenuDisplay(this)" onmouseout="MenuHide(this)"><a href="#" class="menu %s">%s</a><ul>""" % (cssclass, title)
|
||||
# ]
|
||||
# for item in items:
|
||||
# if item.get('enabled', True):
|
||||
# if base_url:
|
||||
# item['urlq'] = urllib.quote(item['url'])
|
||||
# else:
|
||||
# item['urlq'] = item['url']
|
||||
# H.append('<li><a href="' + base_url + '%(urlq)s">%(title)s</a></li>' % item)
|
||||
# else:
|
||||
# H.append('<li><span class="disabled_menu_item">%(title)s</span></li>' % item)
|
||||
# H.append('</ul></li></ul></%s>' % elem)
|
||||
# return ''.join(H)
|
||||
|
||||
|
||||
def defMenuStats(context, formsemestre_id):
|
||||
"Définition du menu 'Statistiques' "
|
||||
return [
|
||||
|
@ -98,7 +81,7 @@ def defMenuStats(context, formsemestre_id):
|
|||
"title": "Graphe des parcours",
|
||||
"endpoint": "notes.formsemestre_graph_parcours",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": scu.WITH_PYDOT,
|
||||
"enabled": True,
|
||||
},
|
||||
{
|
||||
"title": "Codes des parcours",
|
||||
|
@ -138,10 +121,9 @@ def defMenuStats(context, formsemestre_id):
|
|||
]
|
||||
|
||||
|
||||
def formsemestre_status_menubar(context, sem, REQUEST):
|
||||
def formsemestre_status_menubar(context, sem):
|
||||
"""HTML to render menubar"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
uid = str(authuser)
|
||||
uid = current_user.user_name
|
||||
formsemestre_id = sem["formsemestre_id"]
|
||||
if int(sem["etat"]):
|
||||
change_lock_msg = "Verrouiller"
|
||||
|
@ -175,9 +157,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"formsemestre_id": formsemestre_id,
|
||||
},
|
||||
"enabled": (
|
||||
authuser.has_permission(Permission.ScoImplement)
|
||||
current_user.has_permission(Permission.ScoImplement)
|
||||
or (
|
||||
str(REQUEST.AUTHENTICATED_USER) in sem["responsables"]
|
||||
current_user.user_name in sem["responsables"]
|
||||
and sem["resp_can_edit"]
|
||||
)
|
||||
)
|
||||
|
@ -189,9 +171,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"endpoint": "scolar.formsemestre_edit_preferences",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": (
|
||||
authuser.has_permission(Permission.ScoImplement)
|
||||
current_user.has_permission(Permission.ScoImplement)
|
||||
or (
|
||||
str(REQUEST.AUTHENTICATED_USER) in sem["responsables"]
|
||||
current_user.user_name in sem["responsables"]
|
||||
and sem["resp_can_edit"]
|
||||
)
|
||||
)
|
||||
|
@ -203,7 +185,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"endpoint": "notes.formsemestre_edit_options",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": (uid in sem["responsables"])
|
||||
or authuser.has_permission(Permission.ScoImplement),
|
||||
or current_user.has_permission(Permission.ScoImplement),
|
||||
"helpmsg": "Change les options",
|
||||
},
|
||||
{
|
||||
|
@ -211,7 +193,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"endpoint": "notes.formsemestre_change_lock",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": (uid in sem["responsables"])
|
||||
or authuser.has_permission(Permission.ScoImplement),
|
||||
or current_user.has_permission(Permission.ScoImplement),
|
||||
"helpmsg": "",
|
||||
},
|
||||
{
|
||||
|
@ -239,14 +221,14 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"title": "Cloner ce semestre",
|
||||
"endpoint": "notes.formsemestre_clone",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoImplement),
|
||||
"enabled": current_user.has_permission(Permission.ScoImplement),
|
||||
"helpmsg": "",
|
||||
},
|
||||
{
|
||||
"title": "Associer à une nouvelle version du programme",
|
||||
"endpoint": "notes.formsemestre_associate_new_version",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoChangeFormation)
|
||||
"enabled": current_user.has_permission(Permission.ScoChangeFormation)
|
||||
and (sem["etat"] == "1"),
|
||||
"helpmsg": "",
|
||||
},
|
||||
|
@ -254,7 +236,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"title": "Supprimer ce semestre",
|
||||
"endpoint": "notes.formsemestre_delete",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoImplement),
|
||||
"enabled": current_user.has_permission(Permission.ScoImplement),
|
||||
"helpmsg": "",
|
||||
},
|
||||
]
|
||||
|
@ -281,43 +263,43 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"title": "Passage des étudiants depuis d'autres semestres",
|
||||
"endpoint": "notes.formsemestre_inscr_passage",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
|
||||
"enabled": current_user.has_permission(Permission.ScoEtudInscrit)
|
||||
and (sem["etat"] == "1"),
|
||||
},
|
||||
{
|
||||
"title": "Synchroniser avec étape Apogée",
|
||||
"endpoint": "notes.formsemestre_synchro_etuds",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoView)
|
||||
and sco_preferences.get_preference(context, "portal_url")
|
||||
"enabled": current_user.has_permission(Permission.ScoView)
|
||||
and sco_preferences.get_preference("portal_url")
|
||||
and (sem["etat"] == "1"),
|
||||
},
|
||||
{
|
||||
"title": "Inscrire un étudiant",
|
||||
"endpoint": "notes.formsemestre_inscription_with_modules_etud",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
|
||||
"enabled": current_user.has_permission(Permission.ScoEtudInscrit)
|
||||
and (sem["etat"] == "1"),
|
||||
},
|
||||
{
|
||||
"title": "Importer des étudiants dans ce semestre (table Excel)",
|
||||
"endpoint": "scolar.form_students_import_excel",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
|
||||
"enabled": current_user.has_permission(Permission.ScoEtudInscrit)
|
||||
and (sem["etat"] == "1"),
|
||||
},
|
||||
{
|
||||
"title": "Import/export des données admission",
|
||||
"endpoint": "scolar.form_students_import_infos_admissions",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoView),
|
||||
"enabled": current_user.has_permission(Permission.ScoView),
|
||||
},
|
||||
{
|
||||
"title": "Resynchroniser données identité",
|
||||
"endpoint": "scolar.formsemestre_import_etud_admission",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": authuser.has_permission(Permission.ScoEtudChangeAdr)
|
||||
and sco_preferences.get_preference(context, "portal_url"),
|
||||
"enabled": current_user.has_permission(Permission.ScoEtudChangeAdr)
|
||||
and sco_preferences.get_preference("portal_url"),
|
||||
},
|
||||
{
|
||||
"title": "Exporter table des étudiants",
|
||||
|
@ -325,7 +307,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"args": {
|
||||
"format": "allxls",
|
||||
"group_ids": sco_groups.get_default_group(
|
||||
context, formsemestre_id, fix_if_missing=True, REQUEST=REQUEST
|
||||
formsemestre_id, fix_if_missing=True
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -349,7 +331,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"endpoint": "scolar.editPartitionForm",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": sco_groups.sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
formsemestre_id
|
||||
),
|
||||
},
|
||||
]
|
||||
|
@ -359,9 +341,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
)
|
||||
submenu = []
|
||||
enabled = (
|
||||
sco_groups.sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
)
|
||||
sco_groups.sco_permissions_check.can_change_groups(formsemestre_id)
|
||||
and partitions
|
||||
)
|
||||
for partition in partitions:
|
||||
|
@ -401,7 +381,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"endpoint": "notes.formsemestre_bulletins_mailetuds_choice",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": sco_bulletins.can_send_bulletin_by_mail(
|
||||
context, formsemestre_id, REQUEST
|
||||
context, formsemestre_id
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -436,17 +416,13 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
"hidebac": 1,
|
||||
"pref_override": 0,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_validate_sem(
|
||||
context, REQUEST, formsemestre_id
|
||||
),
|
||||
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
|
||||
},
|
||||
{
|
||||
"title": "Editer les PV et archiver les résultats",
|
||||
"endpoint": "notes.formsemestre_archive",
|
||||
"args": {"formsemestre_id": formsemestre_id},
|
||||
"enabled": sco_permissions_check.can_edit_pv(
|
||||
context, REQUEST, formsemestre_id
|
||||
),
|
||||
"enabled": sco_permissions_check.can_edit_pv(formsemestre_id),
|
||||
},
|
||||
{
|
||||
"title": "Documents archivés",
|
||||
|
@ -475,27 +451,32 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||
return "\n".join(H)
|
||||
|
||||
|
||||
def retreive_formsemestre_from_request(context, REQUEST):
|
||||
def retreive_formsemestre_from_request():
|
||||
"""Cherche si on a de quoi déduire le semestre affiché à partir des
|
||||
arguments de la requête:
|
||||
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
|
||||
"""
|
||||
context = None # XXX #context
|
||||
if request.method == "GET":
|
||||
args = request.args
|
||||
elif request.method == "POST":
|
||||
args = request.form
|
||||
else:
|
||||
return None
|
||||
# Search formsemestre
|
||||
group_ids = REQUEST.form.get("group_ids", [])
|
||||
if "formsemestre_id" in REQUEST.form:
|
||||
formsemestre_id = REQUEST.form["formsemestre_id"]
|
||||
elif "moduleimpl_id" in REQUEST.form:
|
||||
group_ids = args.get("group_ids", [])
|
||||
if "formsemestre_id" in args:
|
||||
formsemestre_id = args["formsemestre_id"]
|
||||
elif "moduleimpl_id" in args:
|
||||
modimpl = sco_moduleimpl.do_moduleimpl_list(
|
||||
context, moduleimpl_id=REQUEST.form["moduleimpl_id"]
|
||||
context, moduleimpl_id=args["moduleimpl_id"]
|
||||
)
|
||||
if not modimpl:
|
||||
return None # suppressed ?
|
||||
modimpl = modimpl[0]
|
||||
formsemestre_id = modimpl["formsemestre_id"]
|
||||
elif "evaluation_id" in REQUEST.form:
|
||||
E = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": REQUEST.form["evaluation_id"]}
|
||||
)
|
||||
elif "evaluation_id" in args:
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": args["evaluation_id"]})
|
||||
if not E:
|
||||
return None # evaluation suppressed ?
|
||||
E = E[0]
|
||||
|
@ -503,8 +484,8 @@ def retreive_formsemestre_from_request(context, REQUEST):
|
|||
context, moduleimpl_id=E["moduleimpl_id"]
|
||||
)[0]
|
||||
formsemestre_id = modimpl["formsemestre_id"]
|
||||
elif "group_id" in REQUEST.form:
|
||||
group = sco_groups.get_group(context, REQUEST.form["group_id"])
|
||||
elif "group_id" in args:
|
||||
group = sco_groups.get_group(context, args["group_id"])
|
||||
formsemestre_id = group["formsemestre_id"]
|
||||
elif group_ids:
|
||||
if group_ids:
|
||||
|
@ -515,8 +496,8 @@ def retreive_formsemestre_from_request(context, REQUEST):
|
|||
group_id = group_ids[0]
|
||||
group = sco_groups.get_group(context, group_id)
|
||||
formsemestre_id = group["formsemestre_id"]
|
||||
elif "partition_id" in REQUEST.form:
|
||||
partition = sco_groups.get_partition(context, REQUEST.form["partition_id"])
|
||||
elif "partition_id" in args:
|
||||
partition = sco_groups.get_partition(context, args["partition_id"])
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
else:
|
||||
return None # no current formsemestre
|
||||
|
@ -525,11 +506,11 @@ def retreive_formsemestre_from_request(context, REQUEST):
|
|||
|
||||
|
||||
# Element HTML decrivant un semestre (barre de menu et infos)
|
||||
def formsemestre_page_title(context, REQUEST):
|
||||
def formsemestre_page_title(context):
|
||||
"""Element HTML decrivant un semestre (barre de menu et infos)
|
||||
Cherche dans REQUEST si un semestre est défini (formsemestre_id ou moduleimpl ou evaluation ou group)
|
||||
"""
|
||||
formsemestre_id = retreive_formsemestre_from_request(context, REQUEST)
|
||||
formsemestre_id = retreive_formsemestre_from_request()
|
||||
#
|
||||
if not formsemestre_id:
|
||||
return ""
|
||||
|
@ -539,21 +520,22 @@ def formsemestre_page_title(context, REQUEST):
|
|||
log("can't find formsemestre_id %s" % formsemestre_id)
|
||||
return ""
|
||||
|
||||
fill_formsemestre(context, sem, REQUEST=REQUEST)
|
||||
fill_formsemestre(sem)
|
||||
|
||||
H = [
|
||||
"""<div class="formsemestre_page_title">""",
|
||||
"""<div class="infos">
|
||||
<span class="semtitle"><a class="stdlink" title="%(session_id)s" href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre)s</a><a title="%(etape_apo_str)s">%(num_sem)s</a>%(modalitestr)s</span><span class="dates"><a title="du %(date_debut)s au %(date_fin)s ">%(mois_debut)s - %(mois_fin)s</a></span><span class="resp"><a title="%(nomcomplet)s">%(resp)s</a></span><span class="nbinscrits"><a class="discretelink" href="%(notes_url)s/formsemestre_lists?formsemestre_id=%(formsemestre_id)s">%(nbinscrits)d inscrits</a></span><span class="lock">%(locklink)s</span><span class="eye">%(eyelink)s</span></div>"""
|
||||
% sem,
|
||||
formsemestre_status_menubar(context, sem, REQUEST),
|
||||
formsemestre_status_menubar(context, sem),
|
||||
"""</div>""",
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def fill_formsemestre(context, sem, REQUEST=None):
|
||||
def fill_formsemestre(sem):
|
||||
"""Add some useful fields to help display formsemestres"""
|
||||
context = None # XXX #context
|
||||
notes_url = scu.NotesURL()
|
||||
sem["notes_url"] = notes_url
|
||||
formsemestre_id = sem["formsemestre_id"]
|
||||
|
@ -567,9 +549,7 @@ def fill_formsemestre(context, sem, REQUEST=None):
|
|||
)
|
||||
else:
|
||||
sem["locklink"] = ""
|
||||
if sco_preferences.get_preference(
|
||||
context, "bul_display_publication", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("bul_display_publication", formsemestre_id):
|
||||
if sem["bul_hide_xml"] != "0":
|
||||
eyeicon = scu.icontag("hide_img", border="0", title="Bulletins NON publiés")
|
||||
else:
|
||||
|
@ -618,9 +598,7 @@ def formsemestre_description_table(
|
|||
"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
||||
use_ue_coefs = sco_preferences.get_preference(
|
||||
context, "use_ue_coefs", formsemestre_id
|
||||
)
|
||||
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
||||
F = sco_formations.formation_list(
|
||||
context, args={"formation_id": sem["formation_id"]}
|
||||
)[0]
|
||||
|
@ -705,7 +683,7 @@ def formsemestre_description_table(
|
|||
sums = {"_css_row_class": "moyenne sortbottom", "ects": sum_ects, "Coef.": sum_coef}
|
||||
R.append(sums)
|
||||
columns_ids = ["UE", "Code", "Module", "Coef."]
|
||||
if sco_preferences.get_preference(context, "bul_show_ects", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_ects", formsemestre_id):
|
||||
columns_ids += ["ects"]
|
||||
columns_ids += ["Inscrits", "Responsable", "Enseignants"]
|
||||
if with_evals:
|
||||
|
@ -742,7 +720,7 @@ def formsemestre_description_table(
|
|||
context, REQUEST, "Description du semestre", sem, with_page_header=False
|
||||
),
|
||||
pdf_title=title,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
|
||||
|
||||
|
@ -772,26 +750,17 @@ def formsemestre_description(
|
|||
# genere liste html pour accès aux groupes de ce semestre
|
||||
def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
|
||||
context = context
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
r = scu.ScoURL() # root url
|
||||
# construit l'URL "destination"
|
||||
# (a laquelle on revient apres saisie absences)
|
||||
query_args = cgi.parse_qs(REQUEST.QUERY_STRING) # XXX TODO a revoir #py3
|
||||
# soit via flask soit via https://docs.python.org/3/library/urllib.parse.html#module-urllib.parse
|
||||
if "head_message" in query_args:
|
||||
del query_args["head_message"]
|
||||
destination = "%s?%s" % (
|
||||
REQUEST.URL,
|
||||
six.moves.urllib.parse.urlencode(query_args, True),
|
||||
destination = url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=sem["formsemestre_id"],
|
||||
)
|
||||
destination = destination.replace(
|
||||
"%", "%%"
|
||||
) # car ici utilisee dans un format string !
|
||||
|
||||
#
|
||||
H = []
|
||||
# pas de menu absences si pas autorise:
|
||||
if with_absences and not authuser.has_permission(Permission.ScoAbsChange):
|
||||
if with_absences and not current_user.has_permission(Permission.ScoAbsChange):
|
||||
with_absences = False
|
||||
|
||||
#
|
||||
|
@ -806,39 +775,29 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
|
|||
try:
|
||||
if with_absences:
|
||||
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
|
||||
FA = [] # formulaire avec menu saisi absences
|
||||
FA.append(
|
||||
'<td><form action="{}" method="get">'.format(
|
||||
url_for(
|
||||
form_abs_tmpl = f"""
|
||||
<td><form action="{url_for(
|
||||
"absences.SignaleAbsenceGrSemestre", scodoc_dept=g.scodoc_dept
|
||||
)
|
||||
)
|
||||
)
|
||||
FA.append(
|
||||
'<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem
|
||||
)
|
||||
FA.append('<input type="hidden" name="group_ids" value="%(group_id)s"/>')
|
||||
|
||||
FA.append(
|
||||
'<input type="hidden" name="destination" value="%s"/>' % destination
|
||||
)
|
||||
FA.append('<input type="submit" value="Saisir absences du" />')
|
||||
FA.append('<select name="datedebut" class="noprint">')
|
||||
)}" method="get">
|
||||
<input type="hidden" name="datefin" value="{sem['date_fin']}"/>
|
||||
<input type="hidden" name="group_ids" value="%(group_id)s"/>
|
||||
<input type="hidden" name="destination" value="{destination}"/>
|
||||
<input type="submit" value="Saisir absences du" />
|
||||
<select name="datedebut" class="noprint">
|
||||
"""
|
||||
date = first_monday
|
||||
for jour in sco_abs.day_names(context):
|
||||
FA.append('<option value="%s">%s</option>' % (date, jour))
|
||||
form_abs_tmpl += '<option value="%s">%s</option>' % (date, jour)
|
||||
date = date.next_day()
|
||||
FA.append("</select>")
|
||||
FA.append(
|
||||
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
|
||||
% sem
|
||||
)
|
||||
FA.append("</form></td>")
|
||||
FormAbs = "\n".join(FA)
|
||||
form_abs_tmpl += """
|
||||
</select>
|
||||
<a href="%(url_etat)s">état</a>
|
||||
</form></td>
|
||||
"""
|
||||
else:
|
||||
FormAbs = ""
|
||||
form_abs_tmpl = ""
|
||||
except ScoInvalidDateError: # dates incorrectes dans semestres ?
|
||||
FormAbs = ""
|
||||
form_abs_tmpl = ""
|
||||
#
|
||||
H.append('<div id="grouplists">')
|
||||
# Genere liste pour chaque partition (categorie de groupes)
|
||||
|
@ -854,44 +813,70 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
|
|||
n_members = len(
|
||||
sco_groups.get_group_members(context, group["group_id"])
|
||||
)
|
||||
group["url"] = r
|
||||
group["url_etat"] = url_for(
|
||||
"absences.EtatAbsencesGr",
|
||||
group_ids=group["group_id"],
|
||||
debut=sem["date_debut"],
|
||||
fin=sem["date_fin"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
if group["group_name"]:
|
||||
group["label"] = "groupe %(group_name)s" % group
|
||||
else:
|
||||
group["label"] = "liste"
|
||||
H.append('<tr class="listegroupelink">')
|
||||
H.append(
|
||||
"""<td>
|
||||
<a href="%(url)s/groups_view?group_ids=%(group_id)s">%(label)s</a>
|
||||
f"""
|
||||
<tr class="listegroupelink">
|
||||
<td>
|
||||
<a href="{
|
||||
url_for("scolar.groups_view",
|
||||
group_ids=group["group_id"],
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
}">{group["label"]}</a>
|
||||
</td><td>
|
||||
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
|
||||
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
|
||||
</td>"""
|
||||
% group
|
||||
(<a href="{
|
||||
url_for("scolar.groups_view",
|
||||
group_ids=group["group_id"],
|
||||
format="xls",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
}">tableur</a>)
|
||||
<a href="{
|
||||
url_for("scolar.groups_view",
|
||||
curtab="tab-photos",
|
||||
group_ids=group["group_id"],
|
||||
etat="I",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
}">Photos</a>
|
||||
</td>
|
||||
<td>({n_members} étudiants)</td>
|
||||
"""
|
||||
)
|
||||
H.append("<td>(%d étudiants)</td>" % n_members)
|
||||
|
||||
if with_absences:
|
||||
H.append(FormAbs % group)
|
||||
H.append(form_abs_tmpl % group)
|
||||
|
||||
H.append("</tr>")
|
||||
H.append("</table>")
|
||||
else:
|
||||
H.append('<p class="help indent">Aucun groupe dans cette partition')
|
||||
if sco_groups.sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
):
|
||||
if sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
H.append(
|
||||
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
|
||||
% partition["partition_id"]
|
||||
)
|
||||
H.append("</p>")
|
||||
if sco_groups.sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
):
|
||||
if sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
H.append(
|
||||
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
|
||||
% formsemestre_id
|
||||
f"""<h4><a
|
||||
href="{
|
||||
url_for("scolar.editPartitionForm",
|
||||
formsemestre_id=formsemestre_id,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
)
|
||||
}">Ajouter une partition</a></h4>"""
|
||||
)
|
||||
|
||||
H.append("</div>")
|
||||
|
@ -966,7 +951,7 @@ def formsemestre_status_head(
|
|||
)
|
||||
H.append("</td></tr>")
|
||||
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(context, formsemestre_id)
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(formsemestre_id)
|
||||
H.append(
|
||||
'<tr><td class="fichetitre2">Evaluations: </td><td> %(nb_evals_completes)s ok, %(nb_evals_en_cours)s en cours, %(nb_evals_vides)s vides'
|
||||
% evals
|
||||
|
@ -992,7 +977,7 @@ Il y a des notes en attente ! Le classement des étudiants n'a qu'une valeur ind
|
|||
H.append(
|
||||
'<p class="fontorange"><em>Attention: ce semestre couvre plusieurs années scolaires !</em></p>'
|
||||
)
|
||||
# elif sco_preferences.get_preference(context, 'bul_display_publication', formsemestre_id):
|
||||
# elif sco_preferences.get_preference( 'bul_display_publication', formsemestre_id):
|
||||
# H.append('<p><em>Bulletins publiés sur le portail</em></p>')
|
||||
|
||||
return "".join(H)
|
||||
|
@ -1016,9 +1001,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||
)
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Semestre %s" % sem["titreannee"]
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Semestre %s" % sem["titreannee"]),
|
||||
'<div class="formsemestre_status">',
|
||||
formsemestre_status_head(
|
||||
context, formsemestre_id=formsemestre_id, page_title="Tableau de bord"
|
||||
|
@ -1072,7 +1055,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||
prev_ue_id = ue["ue_id"]
|
||||
acronyme = ue["acronyme"]
|
||||
titre = ue["titre"]
|
||||
if sco_preferences.get_preference(context, "use_ue_coefs", formsemestre_id):
|
||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
||||
titre += " <b>(coef. %s)</b>" % (ue["coefficient"] or 0.0)
|
||||
H.append(
|
||||
"""<tr class="formsemestre_status_ue"><td colspan="4">
|
||||
|
@ -1113,9 +1096,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||
else:
|
||||
fontorange = ""
|
||||
|
||||
etat = sco_evaluations.do_evaluation_etat_in_mod(
|
||||
context, nt, M["moduleimpl_id"]
|
||||
)
|
||||
etat = sco_evaluations.do_evaluation_etat_in_mod(nt, M["moduleimpl_id"])
|
||||
if (
|
||||
etat["nb_evals_completes"] > 0
|
||||
and etat["nb_evals_en_cours"] == 0
|
||||
|
@ -1183,7 +1164,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||
|
||||
H.append("</td></tr>")
|
||||
H.append("</table></p>")
|
||||
if sco_preferences.get_preference(context, "use_ue_coefs", formsemestre_id):
|
||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
||||
H.append(
|
||||
"""
|
||||
<p class="infop">utilise les coefficients d'UE pour calculer la moyenne générale.</p>
|
||||
|
@ -1202,4 +1183,4 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||
'<p><a class="stdlink" href="mailto:?cc=%s">Courrier aux %d enseignants du semestre</a></p>'
|
||||
% (",".join(adrlist), len(adrlist))
|
||||
)
|
||||
return "".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "".join(H) + html_sco_header.sco_footer()
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"""
|
||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error, time, datetime
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -106,8 +107,6 @@ def formsemestre_validation_etud_form(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Parcours %(nomprenom)s" % etud,
|
||||
javascripts=["js/recap_parcours.js"],
|
||||
)
|
||||
|
@ -128,7 +127,7 @@ def formsemestre_validation_etud_form(
|
|||
% (formsemestre_id, etud_index_next, etud_n["nomprenom"])
|
||||
)
|
||||
Footer.append("</p>")
|
||||
Footer.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
Footer.append(html_sco_header.sco_footer())
|
||||
|
||||
H.append('<table style="width: 100%"><tr><td>')
|
||||
if not check:
|
||||
|
@ -224,7 +223,7 @@ def formsemestre_validation_etud_form(
|
|||
'<a href="formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s" class="stdlink">Supprimer décision existante</a>'
|
||||
% (etudid, formsemestre_id)
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
# Infos sur decisions déjà saisies
|
||||
|
@ -267,7 +266,7 @@ def formsemestre_validation_etud_form(
|
|||
H.append('<input type="hidden" name="sortcol" value="%s"/>' % sortcol)
|
||||
H.append("</form></div>")
|
||||
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
# Explication sur barres actuelles
|
||||
|
@ -419,17 +418,17 @@ def _redirect_valid_choice(
|
|||
adr += "&sortcol=" + sortcol
|
||||
# if desturl:
|
||||
# desturl += "&desturl=" + desturl
|
||||
return REQUEST.RESPONSE.redirect(adr)
|
||||
return flask.redirect(adr)
|
||||
# Si le precedent a été modifié, demande relecture du parcours.
|
||||
# sinon renvoie au listing general,
|
||||
|
||||
|
||||
# if choice.new_code_prev:
|
||||
# REQUEST.RESPONSE.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
|
||||
# flask.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
|
||||
# else:
|
||||
# if not desturl:
|
||||
# desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + formsemestre_id
|
||||
# REQUEST.RESPONSE.redirect(desturl)
|
||||
# flask.redirect(desturl)
|
||||
|
||||
|
||||
def _dispcode(c):
|
||||
|
@ -664,9 +663,7 @@ def formsemestre_recap_parcours_table(
|
|||
H.append("</tr>")
|
||||
# 3eme ligne: ECTS
|
||||
if (
|
||||
sco_preferences.get_preference(
|
||||
context, "bul_show_ects", sem["formsemestre_id"]
|
||||
)
|
||||
sco_preferences.get_preference("bul_show_ects", sem["formsemestre_id"])
|
||||
or nt.parcours.ECTS_ONLY
|
||||
):
|
||||
etud_moy_infos = nt.get_etud_moy_infos(etudid)
|
||||
|
@ -853,7 +850,7 @@ def formsemestre_validation_auto(context, formsemestre_id, REQUEST):
|
|||
</form>
|
||||
"""
|
||||
% formsemestre_id,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -923,7 +920,7 @@ def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
|
|||
"do_formsemestre_validation_auto: %d validations, %d conflicts"
|
||||
% (nb_valid, len(conflicts))
|
||||
)
|
||||
H = [html_sco_header.sco_header(context, REQUEST, page_title="Saisie automatique")]
|
||||
H = [html_sco_header.sco_header(page_title="Saisie automatique")]
|
||||
H.append(
|
||||
"""<h2>Saisie automatique des décisions du semestre %s</h2>
|
||||
<p>Opération effectuée.</p>
|
||||
|
@ -946,7 +943,7 @@ def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
|
|||
'<a href="formsemestre_recapcomplet?formsemestre_id=%s&modejury=1&hidemodules=1&hidebac=1&pref_override=0">continuer</a>'
|
||||
% formsemestre_id
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -994,8 +991,6 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Validation UE",
|
||||
javascripts=["js/validate_previous_ue.js"],
|
||||
),
|
||||
|
@ -1084,15 +1079,9 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
|
|||
<div id="ue_list_code"><!-- filled by ue_sharing_code --></div>
|
||||
"""
|
||||
warn, ue_multiples = check_formation_ues(context, Fo["formation_id"])
|
||||
return (
|
||||
"\n".join(H)
|
||||
+ tf[1]
|
||||
+ X
|
||||
+ warn
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + tf[1] + X + warn + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
scu.NotesURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
else:
|
||||
|
@ -1110,7 +1099,7 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
|
|||
semestre_id=semestre_id,
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
scu.ScoURL()
|
||||
+ "/Notes/formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s&head_message=Validation%%20d'UE%%20enregistree"
|
||||
% (formsemestre_id, etudid)
|
||||
|
@ -1158,7 +1147,6 @@ def do_formsemestre_validate_previous_ue(
|
|||
)
|
||||
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="formsemestre_validate_previous_ue",
|
||||
etudid=etudid,
|
||||
|
@ -1172,7 +1160,6 @@ def do_formsemestre_validate_previous_ue(
|
|||
def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
||||
"Invalide tous les semestres de cette formation où l'etudiant est inscrit..."
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT sem.*
|
||||
FROM notes_formsemestre sem, notes_formsemestre_inscription i
|
||||
WHERE sem.formation_id = %(formation_id)s
|
||||
|
@ -1190,7 +1177,6 @@ def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
|||
def get_etud_ue_cap_html(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||
"""Ramene bout de HTML pour pouvoir supprimer une validation de cette UE"""
|
||||
valids = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT SFV.* FROM scolar_formsemestre_validation SFV
|
||||
WHERE ue_id=%(ue_id)s AND etudid=%(etudid)s""",
|
||||
{"etudid": etudid, "ue_id": ue_id},
|
||||
|
@ -1235,7 +1221,7 @@ def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST
|
|||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
_invalidate_etud_formation_caches(context, etudid, sem["formation_id"])
|
||||
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
scu.NotesURL()
|
||||
+ "/formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
||||
% (etudid, formsemestre_id)
|
||||
|
@ -1253,7 +1239,6 @@ def check_formation_ues(context, formation_id):
|
|||
for ue in ues:
|
||||
# formsemestres utilisant cette ue ?
|
||||
sems = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT DISTINCT sem.*
|
||||
FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi
|
||||
WHERE sem.formation_id = %(formation_id)s
|
||||
|
|
|
@ -33,15 +33,18 @@ Optimisation possible:
|
|||
et éviter ainsi l'appel ulterieur à get_etud_groups() dans _make_table_notes
|
||||
|
||||
"""
|
||||
import time
|
||||
import collections
|
||||
import re
|
||||
import operator
|
||||
import re
|
||||
import time
|
||||
|
||||
import xml.dom.minidom
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
import flask
|
||||
from flask import g
|
||||
from flask import url_for
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -95,7 +98,6 @@ group_list = groupEditor.list
|
|||
def get_group(context, group_id):
|
||||
"""Returns group object, with partition"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE gd.group_id=%(group_id)s AND p.partition_id = gd.partition_id",
|
||||
{"group_id": group_id},
|
||||
)
|
||||
|
@ -109,18 +111,13 @@ def group_delete(context, group, force=False):
|
|||
# if not group['group_name'] and not force:
|
||||
# raise ValueError('cannot suppress this group')
|
||||
# remove memberships:
|
||||
ndb.SimpleQuery(
|
||||
context, "DELETE FROM group_membership WHERE group_id=%(group_id)s", group
|
||||
)
|
||||
ndb.SimpleQuery("DELETE FROM group_membership WHERE group_id=%(group_id)s", group)
|
||||
# delete group:
|
||||
ndb.SimpleQuery(
|
||||
context, "DELETE FROM group_descr WHERE group_id=%(group_id)s", group
|
||||
)
|
||||
ndb.SimpleQuery("DELETE FROM group_descr WHERE group_id=%(group_id)s", group)
|
||||
|
||||
|
||||
def get_partition(context, partition_id):
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.* FROM partition p WHERE p.partition_id = %(partition_id)s",
|
||||
{"partition_id": partition_id},
|
||||
)
|
||||
|
@ -132,7 +129,6 @@ def get_partition(context, partition_id):
|
|||
def get_partitions_list(context, formsemestre_id, with_default=True):
|
||||
"""Liste des partitions pour ce semestre (list of dicts)"""
|
||||
partitions = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s order by numero",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -146,7 +142,6 @@ def get_partitions_list(context, formsemestre_id, with_default=True):
|
|||
def get_default_partition(context, formsemestre_id):
|
||||
"""Get partition for 'all' students (this one always exists, with NULL name)"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s AND partition_name is NULL",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -174,16 +169,15 @@ def get_partition_groups(context, partition):
|
|||
"""List of groups in this partition (list of dicts).
|
||||
Some groups may be empty."""
|
||||
return ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE gd.partition_id=%(partition_id)s AND gd.partition_id=p.partition_id ORDER BY group_name",
|
||||
partition,
|
||||
)
|
||||
|
||||
|
||||
def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None):
|
||||
def get_default_group(formsemestre_id, fix_if_missing=False):
|
||||
"""Returns group_id for default ('tous') group"""
|
||||
context = None # #context
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.group_id FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_name is NULL AND p.partition_id = gd.partition_id",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -200,10 +194,8 @@ def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=No
|
|||
]
|
||||
except ScoException:
|
||||
log("creating default partition for %s" % formsemestre_id)
|
||||
partition_id = partition_create(
|
||||
context, formsemestre_id, default=True, REQUEST=REQUEST
|
||||
)
|
||||
group_id = createGroup(context, partition_id, default=True, REQUEST=REQUEST)
|
||||
partition_id = partition_create(context, formsemestre_id, default=True)
|
||||
group_id = createGroup(context, partition_id, default=True)
|
||||
return group_id
|
||||
# debug check
|
||||
if len(r) != 1:
|
||||
|
@ -215,7 +207,6 @@ def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=No
|
|||
def get_sem_groups(context, formsemestre_id):
|
||||
"""Returns groups for this sem (in all partitions)."""
|
||||
return ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_id = gd.partition_id",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -230,7 +221,7 @@ def get_group_members(context, group_id, etat=None):
|
|||
if etat is not None:
|
||||
req += " and ins.etat = %(etat)s"
|
||||
|
||||
r = ndb.SimpleDictFetch(context, req, {"group_id": group_id, "etat": etat})
|
||||
r = ndb.SimpleDictFetch(req, {"group_id": group_id, "etat": etat})
|
||||
|
||||
for etud in r:
|
||||
sco_etud.format_etud_ident(etud)
|
||||
|
@ -329,7 +320,6 @@ def get_etud_groups(context, etudid, sem, exclude_default=False):
|
|||
if exclude_default:
|
||||
req += " and p.partition_name is not NULL"
|
||||
groups = ndb.SimpleDictFetch(
|
||||
context,
|
||||
req + " ORDER BY p.numero",
|
||||
{"etudid": etudid, "formsemestre_id": sem["formsemestre_id"]},
|
||||
)
|
||||
|
@ -342,7 +332,7 @@ def get_etud_main_group(context, etudid, sem):
|
|||
if groups:
|
||||
return groups[0]
|
||||
else:
|
||||
return get_group(context, get_default_group(context, sem["formsemestre_id"]))
|
||||
return get_group(context, get_default_group(sem["formsemestre_id"]))
|
||||
|
||||
|
||||
def formsemestre_get_main_partition(context, formsemestre_id):
|
||||
|
@ -357,7 +347,6 @@ def formsemestre_get_etud_groupnames(context, formsemestre_id, attr="group_name"
|
|||
{ etudid : { partition_id : group_name }} (attr=group_name or group_id)
|
||||
"""
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"select i.etudid, p.partition_id, gd.group_name, gd.group_id from notes_formsemestre_inscription i, partition p, group_descr gd, group_membership gm where i.formsemestre_id=%(formsemestre_id)s and i.formsemestre_id=p.formsemestre_id and p.partition_id=gd.partition_id and gm.etudid=i.etudid and gm.group_id = gd.group_id and p.partition_name is not NULL",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -380,7 +369,6 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
|||
return etud
|
||||
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.partition_name, g.* from group_descr g, partition p, group_membership gm WHERE gm.etudid=%(etudid)s and gm.group_id = g.group_id and g.partition_id = p.partition_id and p.formsemestre_id = %(formsemestre_id)s ORDER BY p.numero",
|
||||
{"etudid": etud["etudid"], "formsemestre_id": sem["formsemestre_id"]},
|
||||
)
|
||||
|
@ -407,7 +395,6 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
|||
def get_etud_groups_in_partition(context, partition_id):
|
||||
"""Returns { etudid : group }, with all students in this partition"""
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, etudid from group_descr gd, group_membership gm where gd.partition_id = %(partition_id)s and gm.group_id = gd.group_id",
|
||||
{"partition_id": partition_id},
|
||||
)
|
||||
|
@ -535,7 +522,6 @@ def set_group(context, etudid, group_id):
|
|||
args = {"etudid": etudid, "group_id": group_id}
|
||||
# déjà inscrit ?
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM group_membership gm WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||
args,
|
||||
cursor=cursor,
|
||||
|
@ -544,7 +530,6 @@ def set_group(context, etudid, group_id):
|
|||
return False
|
||||
# inscrit
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"INSERT INTO group_membership (etudid, group_id) VALUES (%(etudid)s, %(group_id)s)",
|
||||
args,
|
||||
cursor=cursor,
|
||||
|
@ -571,7 +556,6 @@ def change_etud_group_in_partition(
|
|||
partition = get_partition(context, group["partition_id"])
|
||||
# 1- Supprime membership dans cette partition
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"""DELETE FROM group_membership WHERE group_membership_id IN
|
||||
(SELECT gm.group_membership_id
|
||||
FROM group_membership gm, group_descr gd
|
||||
|
@ -587,7 +571,6 @@ def change_etud_group_in_partition(
|
|||
if REQUEST:
|
||||
cnx = ndb.GetDBConnexion()
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="changeGroup",
|
||||
etudid=etudid,
|
||||
|
@ -618,7 +601,7 @@ def setGroups(
|
|||
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
log("***setGroups: partition_id=%s" % partition_id)
|
||||
log("groupsLists=%s" % groupsLists)
|
||||
|
@ -660,13 +643,11 @@ def setGroups(
|
|||
for etudid in old_members_set:
|
||||
log("removing %s from group %s" % (etudid, group_id))
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM group_membership WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||
{"etudid": etudid, "group_id": group_id},
|
||||
cursor=cursor,
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="removeFromGroup",
|
||||
etudid=etudid,
|
||||
|
@ -688,7 +669,7 @@ def setGroups(
|
|||
# group_name = six.text_type(group_name, "utf-8").encode(
|
||||
# scu.SCO_ENCODING
|
||||
# ) # #py3 #sco8
|
||||
group_id = createGroup(context, partition_id, group_name, REQUEST=REQUEST)
|
||||
group_id = createGroup(context, partition_id, group_name)
|
||||
# Place dans ce groupe les etudiants indiqués:
|
||||
for etudid in fs[1:-1]:
|
||||
change_etud_group_in_partition(
|
||||
|
@ -701,15 +682,11 @@ def setGroups(
|
|||
)
|
||||
|
||||
|
||||
def createGroup(context, partition_id, group_name="", default=False, REQUEST=None):
|
||||
"""Create a new group in this partition
|
||||
(called from JS)
|
||||
"""
|
||||
def createGroup(context, partition_id, group_name="", default=False):
|
||||
"""Create a new group in this partition"""
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if REQUEST and not sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
#
|
||||
if group_name:
|
||||
|
@ -746,9 +723,7 @@ def suppressGroup(context, group_id, partition_id=None, REQUEST=None):
|
|||
else:
|
||||
partition_id = group["partition_id"]
|
||||
partition = get_partition(context, partition_id)
|
||||
if not sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, partition["formsemestre_id"]
|
||||
):
|
||||
if not sco_permissions_check.can_change_groups(partition["formsemestre_id"]):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
log(
|
||||
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
|
||||
|
@ -763,13 +738,10 @@ def partition_create(
|
|||
partition_name="",
|
||||
default=False,
|
||||
numero=None,
|
||||
REQUEST=None,
|
||||
redirect=1,
|
||||
):
|
||||
"""Create a new partition"""
|
||||
if REQUEST and not sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
if partition_name:
|
||||
partition_name = partition_name.strip()
|
||||
|
@ -793,14 +765,18 @@ def partition_create(
|
|||
log("createPartition: created partition_id=%s" % partition_id)
|
||||
#
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"editPartitionForm?formsemestre_id=" + formsemestre_id
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"scolar.editPartitionForm",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
else:
|
||||
return partition_id
|
||||
|
||||
|
||||
def getArrowIconsTags(context, REQUEST):
|
||||
def getArrowIconsTags():
|
||||
"""returns html tags for arrows"""
|
||||
#
|
||||
arrow_up = scu.icontag("arrow_up", title="remonter")
|
||||
|
@ -813,18 +789,16 @@ def getArrowIconsTags(context, REQUEST):
|
|||
def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
||||
"""Form to create/suppress partitions"""
|
||||
# ad-hoc form
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
partitions = get_partitions_list(context, formsemestre_id)
|
||||
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
|
||||
arrow_up, arrow_down, arrow_none = getArrowIconsTags()
|
||||
suppricon = scu.icontag(
|
||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||
)
|
||||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Partitions...",
|
||||
javascripts=["js/editPartitionForm.js"],
|
||||
),
|
||||
|
@ -933,7 +907,7 @@ def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
|||
</div>
|
||||
"""
|
||||
)
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
|
||||
|
@ -943,7 +917,7 @@ def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
|
|||
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
|
||||
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value))
|
||||
|
@ -966,7 +940,7 @@ def partition_delete(
|
|||
default partition cannot be suppressed (unless force)"""
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
|
||||
if not partition["partition_name"] and not force:
|
||||
|
@ -981,13 +955,11 @@ def partition_delete(
|
|||
else:
|
||||
grnames = ""
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Supprimer la partition "%s" ?</h2>
|
||||
<p>Les groupes %s de cette partition seront supprimés</p>
|
||||
"""
|
||||
% (partition["partition_name"], grnames),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="editPartitionForm?formsemestre_id=%s" % formsemestre_id,
|
||||
parameters={"redirect": redirect, "partition_id": partition_id},
|
||||
)
|
||||
|
@ -1001,16 +973,14 @@ def partition_delete(
|
|||
|
||||
# redirect to partition edit page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"editPartitionForm?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id)
|
||||
|
||||
|
||||
def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
|
||||
"""Move before/after previous one (decrement/increment numero)"""
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
#
|
||||
redirect = int(redirect)
|
||||
|
@ -1036,16 +1006,14 @@ def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
|
|||
|
||||
# redirect to partition edit page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"editPartitionForm?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id)
|
||||
|
||||
|
||||
def partition_rename(context, partition_id, REQUEST=None):
|
||||
"""Form to rename a partition"""
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
H = ["<h2>Renommer une partition</h2>"]
|
||||
tf = TrivialFormulator(
|
||||
|
@ -1068,16 +1036,14 @@ def partition_rename(context, partition_id, REQUEST=None):
|
|||
)
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "\n".join(H)
|
||||
+ "\n"
|
||||
+ tf[1]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"editPartitionForm?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id)
|
||||
else:
|
||||
# form submission
|
||||
return partition_set_name(
|
||||
|
@ -1097,7 +1063,6 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
|||
|
||||
# check unicity
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.* FROM partition p WHERE p.partition_name = %(partition_name)s AND formsemestre_id = %(formsemestre_id)s",
|
||||
{"partition_name": partition_name, "formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -1106,7 +1071,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
|||
"Partition %s déjà existante dans ce semestre !" % partition_name
|
||||
)
|
||||
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
redirect = int(redirect)
|
||||
cnx = ndb.GetDBConnexion()
|
||||
|
@ -1116,9 +1081,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
|||
|
||||
# redirect to partition edit page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"editPartitionForm?formsemestre_id=" + formsemestre_id
|
||||
)
|
||||
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id)
|
||||
|
||||
|
||||
def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
|
||||
|
@ -1131,7 +1094,7 @@ def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
|
|||
if group["group_name"] is None:
|
||||
raise ValueError("can't set a name to default group")
|
||||
formsemestre_id = group["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
redirect = int(redirect)
|
||||
cnx = ndb.GetDBConnexion()
|
||||
|
@ -1139,16 +1102,14 @@ def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
|
|||
|
||||
# redirect to partition edit page:
|
||||
if redirect:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"affectGroups?partition_id=" + group["partition_id"]
|
||||
)
|
||||
return flask.redirect("affectGroups?partition_id=" + group["partition_id"])
|
||||
|
||||
|
||||
def group_rename(context, group_id, REQUEST=None):
|
||||
"""Form to rename a group"""
|
||||
group = get_group(context, group_id)
|
||||
formsemestre_id = group["formsemestre_id"]
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
|
||||
tf = TrivialFormulator(
|
||||
|
@ -1171,16 +1132,14 @@ def group_rename(context, group_id, REQUEST=None):
|
|||
)
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "\n".join(H)
|
||||
+ "\n"
|
||||
+ tf[1]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"affectGroups?partition_id=" + group["partition_id"]
|
||||
)
|
||||
return flask.redirect("affectGroups?partition_id=" + group["partition_id"])
|
||||
else:
|
||||
# form submission
|
||||
return group_set_name(
|
||||
|
@ -1198,7 +1157,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||
formsemestre_id = partition["formsemestre_id"]
|
||||
# renvoie sur page édition groupes
|
||||
dest_url = "affectGroups?partition_id=%s" % partition_id
|
||||
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
|
||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
||||
|
@ -1216,9 +1175,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||
]
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Répartition des groupes"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Répartition des groupes"),
|
||||
"<h2>Répartition des groupes de %s</h2>" % partition["partition_name"],
|
||||
"<p>Semestre %s</p>" % sem["titreannee"],
|
||||
"""<p class="help">Les groupes existants seront <b>effacés</b> et remplacés par
|
||||
|
@ -1238,11 +1195,9 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||
name="tf",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H) + "\n" + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + "\n" + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
else:
|
||||
# form submission
|
||||
log(
|
||||
|
@ -1261,10 +1216,8 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||
# checkGroupName(group_name)
|
||||
# except:
|
||||
# H.append('<p class="warning">Nom de groupe invalide: %s</p>'%group_name)
|
||||
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer(context, REQUEST)
|
||||
group_ids.append(
|
||||
createGroup(context, partition_id, group_name, REQUEST=REQUEST)
|
||||
)
|
||||
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer( REQUEST)
|
||||
group_ids.append(createGroup(context, partition_id, group_name))
|
||||
#
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > identdict
|
||||
identdict = nt.identdict
|
||||
|
@ -1294,7 +1247,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||
context, etudid, group_id, partition, REQUEST=REQUEST
|
||||
)
|
||||
log("%s in group %s" % (etudid, group_id))
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def get_prev_moy(context, etudid, formsemestre_id):
|
||||
|
@ -1362,7 +1315,7 @@ def create_etapes_partition(context, formsemestre_id, partition_name="apo_etapes
|
|||
|
||||
|
||||
def do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, groups=None, getallstudents=False, include_dems=False
|
||||
evaluation_id, groups=None, getallstudents=False, include_dems=False
|
||||
):
|
||||
"""Donne la liste des etudids inscrits a cette evaluation dans les
|
||||
groupes indiqués.
|
||||
|
|
|
@ -40,15 +40,11 @@ def affectGroups(context, partition_id, REQUEST=None):
|
|||
# Ported from DTML and adapted to new group management (nov 2009)
|
||||
partition = sco_groups.get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
if not sco_groups.sco_permissions_check.can_change_groups(
|
||||
context, REQUEST, formsemestre_id
|
||||
):
|
||||
if not sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
|
||||
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Affectation aux groupes",
|
||||
javascripts=["js/groupmgr.js"],
|
||||
cssstyles=["css/groups.css"],
|
||||
|
@ -97,6 +93,6 @@ Editer groupes de
|
|||
|
||||
</div>
|
||||
""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,10 +32,14 @@ import collections
|
|||
import os
|
||||
import re
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
import flask
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.sco_excel import COLORS
|
||||
from app.scodoc.sco_formsemestre_inscriptions import (
|
||||
do_formsemestre_inscription_with_modules,
|
||||
)
|
||||
|
@ -163,8 +167,8 @@ def sco_import_generate_excel_sample(
|
|||
(only columns from these tables will be generated)
|
||||
If group_ids, liste les etudiants de ces groupes
|
||||
"""
|
||||
style = sco_excel.Excel_MakeStyle(bold=True)
|
||||
style_required = sco_excel.Excel_MakeStyle(bold=True, color="red")
|
||||
style = sco_excel.excel_make_style(bold=True)
|
||||
style_required = sco_excel.excel_make_style(bold=True, color=COLORS.RED)
|
||||
titles = []
|
||||
titlesStyles = []
|
||||
for l in fmt:
|
||||
|
@ -213,8 +217,8 @@ def sco_import_generate_excel_sample(
|
|||
lines.append(l)
|
||||
else:
|
||||
lines = [[]] # empty content, titles only
|
||||
return sco_excel.Excel_SimpleTable(
|
||||
titles=titles, titlesStyles=titlesStyles, SheetName="Etudiants", lines=lines
|
||||
return sco_excel.excel_simple_table(
|
||||
titles=titles, titles_styles=titlesStyles, sheet_name="Etudiants", lines=lines
|
||||
)
|
||||
|
||||
|
||||
|
@ -238,19 +242,17 @@ def students_import_excel(
|
|||
)
|
||||
if REQUEST:
|
||||
if formsemestre_id:
|
||||
dest = "formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
dest = "Notes/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
else:
|
||||
dest = scu.NotesURL()
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title="Import etudiants")
|
||||
]
|
||||
H = [html_sco_header.sco_header(page_title="Import etudiants")]
|
||||
H.append("<ul>")
|
||||
for d in diag:
|
||||
H.append("<li>%s</li>" % d)
|
||||
H.append("</ul>")
|
||||
H.append("<p>Import terminé !</p>")
|
||||
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % dest)
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def scolars_import_excel_file(
|
||||
|
@ -269,16 +271,15 @@ def scolars_import_excel_file(
|
|||
cnx = ndb.GetDBConnexion(autocommit=False)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
annee_courante = time.localtime()[0]
|
||||
always_require_ine = sco_preferences.get_preference(context, "always_require_ine")
|
||||
always_require_ine = sco_preferences.get_preference("always_require_ine")
|
||||
exceldata = datafile.read()
|
||||
if not exceldata:
|
||||
raise ScoValueError("Ficher excel vide ou invalide")
|
||||
diag, data = sco_excel.Excel_to_list(exceldata)
|
||||
diag, data = sco_excel.excel_bytes_to_list(exceldata)
|
||||
if not data: # probably a bug
|
||||
raise ScoException("scolars_import_excel_file: empty file !")
|
||||
|
||||
formsemestre_to_invalidate = set()
|
||||
|
||||
# 1- --- check title line
|
||||
titles = {}
|
||||
fmt = sco_import_format()
|
||||
|
@ -380,8 +381,8 @@ def scolars_import_excel_file(
|
|||
# Excel date conversion:
|
||||
if scu.strlower(titleslist[i]) == "date_naissance":
|
||||
if val:
|
||||
if re.match(r"^[0-9]*\.?[0-9]*$", str(val)):
|
||||
val = sco_excel.xldate_as_datetime(float(val))
|
||||
# if re.match(r"^[0-9]*\.?[0-9]*$", str(val)):
|
||||
val = sco_excel.xldate_as_datetime(val)
|
||||
# INE
|
||||
if (
|
||||
scu.strlower(titleslist[i]) == "code_ine"
|
||||
|
@ -475,8 +476,6 @@ def scolars_import_excel_file(
|
|||
diag.append("Import et inscription de %s étudiants" % len(created_etudids))
|
||||
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_INSCR,
|
||||
text="Inscription de %d étudiants" # peuvent avoir ete inscrits a des semestres differents
|
||||
% len(created_etudids),
|
||||
|
@ -505,11 +504,7 @@ def students_import_admission(
|
|||
type_admission=type_admission,
|
||||
)
|
||||
if REQUEST:
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Import données admissions"
|
||||
)
|
||||
]
|
||||
H = [html_sco_header.sco_header(page_title="Import données admissions")]
|
||||
H.append("<p>Import terminé !</p>")
|
||||
H.append(
|
||||
'<p><a class="stdlink" href="%s">Continuer</a></p>'
|
||||
|
@ -519,7 +514,7 @@ def students_import_admission(
|
|||
if diag:
|
||||
H.append("<p>Diagnostic: <ul><li>%s</li></ul></p>" % "</li><li>".join(diag))
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer(REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def _import_one_student(
|
||||
|
@ -620,7 +615,7 @@ def scolars_import_admission(
|
|||
|
||||
log("scolars_import_admission: formsemestre_id=%s" % formsemestre_id)
|
||||
members = sco_groups.get_group_members(
|
||||
context, sco_groups.get_default_group(context, formsemestre_id)
|
||||
context, sco_groups.get_default_group(formsemestre_id)
|
||||
)
|
||||
etuds_by_nomprenom = {} # { nomprenom : etud }
|
||||
diag = []
|
||||
|
@ -633,7 +628,7 @@ def scolars_import_admission(
|
|||
etuds_by_nomprenom[np] = m
|
||||
|
||||
exceldata = datafile.read()
|
||||
diag2, data = sco_excel.Excel_to_list(exceldata, convert_to_string=False)
|
||||
diag2, data = sco_excel.excel_bytes_to_list(exceldata)
|
||||
if not data:
|
||||
raise ScoException("scolars_import_admission: empty file !")
|
||||
diag += diag2
|
||||
|
@ -822,8 +817,6 @@ def adm_table_description_format(context):
|
|||
rows=list(Fmt.values()),
|
||||
html_sortable=True,
|
||||
html_class="table_leftalign",
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return tab
|
||||
|
|
|
@ -46,11 +46,11 @@ TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")
|
|||
|
||||
def generate_excel_sample():
|
||||
"""generates an excel document suitable to import users"""
|
||||
style = sco_excel.Excel_MakeStyle(bold=True)
|
||||
style = sco_excel.excel_make_style(bold=True)
|
||||
titles = TITLES
|
||||
titlesStyles = [style] * len(titles)
|
||||
return sco_excel.Excel_SimpleTable(
|
||||
titles=titles, titlesStyles=titlesStyles, SheetName="Utilisateurs ScoDoc"
|
||||
return sco_excel.excel_simple_table(
|
||||
titles=titles, titlesStyles=titlesStyles, sheet_name="Utilisateurs ScoDoc"
|
||||
)
|
||||
|
||||
|
||||
|
@ -225,7 +225,7 @@ Pour plus d'informations sur ce logiciel, voir %s
|
|||
msg["Subject"] = Header("Mot de passe ScoDoc", scu.SCO_ENCODING)
|
||||
else:
|
||||
msg["Subject"] = Header("Votre accès ScoDoc", scu.SCO_ENCODING)
|
||||
msg["From"] = sco_preferences.get_preference(context, "email_from_addr")
|
||||
msg["From"] = sco_preferences.get_preference("email_from_addr")
|
||||
msg["To"] = u["email"]
|
||||
msg.epilogue = ""
|
||||
txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
|
||||
|
|
|
@ -287,10 +287,8 @@ def formsemestre_inscr_passage(
|
|||
# -- check lock
|
||||
if sem["etat"] != "1":
|
||||
raise ScoValueError("opération impossible: semestre verrouille")
|
||||
header = html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Passage des étudiants"
|
||||
)
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
header = html_sco_header.sco_header(page_title="Passage des étudiants")
|
||||
footer = html_sco_header.sco_footer()
|
||||
H = [header]
|
||||
if type(etuds) == type(""):
|
||||
etuds = etuds.split(",") # vient du form de confirmation
|
||||
|
@ -352,7 +350,6 @@ def formsemestre_inscr_passage(
|
|||
H.append("""<h3>Il n'y a rien à modifier !</h3>""")
|
||||
H.append(
|
||||
scu.confirm_dialog(
|
||||
context,
|
||||
dest_url="formsemestre_inscr_passage",
|
||||
add_headers=False,
|
||||
cancel_url="formsemestre_inscr_passage?formsemestre_id="
|
||||
|
@ -364,7 +361,6 @@ def formsemestre_inscr_passage(
|
|||
"inscrit_groupes": inscrit_groupes,
|
||||
"submitted": 1,
|
||||
},
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
@ -643,8 +639,6 @@ def etuds_select_box_xls(context, src_cat):
|
|||
columns_ids=columns_ids,
|
||||
rows=etuds,
|
||||
caption="%(title)s. %(help)s" % src_cat["infos"],
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
return tab.excel()
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
from operator import itemgetter
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -64,15 +65,11 @@ def do_evaluation_listenotes(context, REQUEST):
|
|||
if "evaluation_id" in REQUEST.form:
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
mode = "eval"
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if "moduleimpl_id" in REQUEST.form:
|
||||
moduleimpl_id = REQUEST.form["moduleimpl_id"]
|
||||
mode = "module"
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"moduleimpl_id": moduleimpl_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||
if not mode:
|
||||
raise ValueError("missing argument: evaluation or module")
|
||||
if not evals:
|
||||
|
@ -84,7 +81,7 @@ def do_evaluation_listenotes(context, REQUEST):
|
|||
if mode == "eval":
|
||||
H = [
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
)
|
||||
]
|
||||
else:
|
||||
|
@ -196,7 +193,7 @@ def do_evaluation_listenotes(context, REQUEST):
|
|||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1]
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"%s/Notes/moduleimpl_status?moduleimpl_id=%s"
|
||||
% (scu.ScoURL(), E["moduleimpl_id"])
|
||||
)
|
||||
|
@ -250,14 +247,14 @@ def _make_table_notes(
|
|||
keep_numeric = False
|
||||
# Si pas de groupe, affiche tout
|
||||
if not group_ids:
|
||||
group_ids = [sco_groups.get_default_group(context, M["formsemestre_id"])]
|
||||
group_ids = [sco_groups.get_default_group(M["formsemestre_id"])]
|
||||
groups = sco_groups.listgroups(context, group_ids)
|
||||
|
||||
gr_title = sco_groups.listgroups_abbrev(groups)
|
||||
gr_title_filename = sco_groups.listgroups_filename(groups)
|
||||
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, E["evaluation_id"], groups, include_dems=True
|
||||
E["evaluation_id"], groups, include_dems=True
|
||||
)
|
||||
|
||||
if anonymous_listing:
|
||||
|
@ -314,9 +311,9 @@ def _make_table_notes(
|
|||
grc = inscr["etat"]
|
||||
|
||||
code = "" # code pour listings anonyme, à la place du nom
|
||||
if sco_preferences.get_preference(context, "anonymous_lst_code") == "INE":
|
||||
if sco_preferences.get_preference("anonymous_lst_code") == "INE":
|
||||
code = etud["code_ine"]
|
||||
elif sco_preferences.get_preference(context, "anonymous_lst_code") == "NIP":
|
||||
elif sco_preferences.get_preference("anonymous_lst_code") == "NIP":
|
||||
code = etud["code_nip"]
|
||||
if not code: # laisser le code vide n'aurait aucun sens, prenons l'etudid
|
||||
code = etudid
|
||||
|
@ -367,9 +364,7 @@ def _make_table_notes(
|
|||
}
|
||||
# Ajoute les notes de chaque évaluation:
|
||||
for e in evals:
|
||||
e["eval_state"] = sco_evaluations.do_evaluation_etat(
|
||||
context, e["evaluation_id"]
|
||||
)
|
||||
e["eval_state"] = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||
notes, nb_abs, nb_att = _add_eval_columns(
|
||||
context,
|
||||
e,
|
||||
|
@ -485,7 +480,7 @@ def _make_table_notes(
|
|||
html_title=html_title,
|
||||
pdf_title=pdf_title,
|
||||
html_class="table_leftalign notes_evaluation",
|
||||
preferences=sco_preferences.SemPreferences(context, M["formsemestre_id"]),
|
||||
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
|
||||
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
|
||||
)
|
||||
|
||||
|
@ -534,7 +529,7 @@ def _make_table_notes(
|
|||
|
||||
return (
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=E["evaluation_id"], REQUEST=REQUEST
|
||||
evaluation_id=E["evaluation_id"], REQUEST=REQUEST
|
||||
)
|
||||
+ eval_info
|
||||
+ html_form
|
||||
|
@ -553,7 +548,7 @@ def _add_eval_columns(
|
|||
sum_notes = 0
|
||||
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
|
||||
evaluation_id = e["evaluation_id"]
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
||||
for row in rows:
|
||||
etudid = row["etudid"]
|
||||
if etudid in NotesDB:
|
||||
|
@ -717,12 +712,12 @@ def evaluation_check_absences(context, evaluation_id):
|
|||
EXC et pas justifie
|
||||
Ramene 3 listes d'etudid
|
||||
"""
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
if not E["jour"]:
|
||||
return [], [], [], [], [] # evaluation sans date
|
||||
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True
|
||||
evaluation_id, getallstudents=True
|
||||
)
|
||||
|
||||
am, pm, demijournee = _eval_demijournee(E)
|
||||
|
@ -738,7 +733,7 @@ def evaluation_check_absences(context, evaluation_id):
|
|||
Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif
|
||||
|
||||
# Les notes:
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
||||
ValButAbs = [] # une note mais noté absent
|
||||
AbsNonSignalee = [] # note ABS mais pas noté absent
|
||||
ExcNonSignalee = [] # note EXC mais pas noté absent
|
||||
|
@ -773,7 +768,7 @@ def evaluation_check_absences_html(
|
|||
):
|
||||
"""Affiche etat verification absences d'une evaluation"""
|
||||
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
am, pm, demijournee = _eval_demijournee(E)
|
||||
|
||||
(
|
||||
|
@ -790,7 +785,7 @@ def evaluation_check_absences_html(
|
|||
context, REQUEST, "Vérification absences à l'évaluation"
|
||||
),
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
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>""",
|
||||
]
|
||||
|
@ -867,7 +862,7 @@ def evaluation_check_absences_html(
|
|||
etudlist(AbsButExc)
|
||||
|
||||
if with_header:
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -892,7 +887,7 @@ def formsemestre_check_absences_html(context, formsemestre_id, REQUEST=None):
|
|||
)
|
||||
for M in Mlist:
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"moduleimpl_id": M["moduleimpl_id"]}
|
||||
{"moduleimpl_id": M["moduleimpl_id"]}
|
||||
)
|
||||
if evals:
|
||||
H.append(
|
||||
|
@ -911,5 +906,5 @@ def formsemestre_check_absences_html(context, formsemestre_id, REQUEST=None):
|
|||
)
|
||||
if evals:
|
||||
H.append("</div>")
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
|
|
@ -59,7 +59,7 @@ def formsemestre_table_etuds_lycees(
|
|||
etuds,
|
||||
group_lycees,
|
||||
title,
|
||||
sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
|
||||
|
||||
|
@ -75,9 +75,7 @@ def scodoc_table_etuds_lycees(context, format="html", REQUEST=None):
|
|||
etuds,
|
||||
False,
|
||||
"Lycées de TOUS les étudiants",
|
||||
sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
sco_preferences.SemPreferences(),
|
||||
no_links=True,
|
||||
)
|
||||
tab.base_url = REQUEST.URL0
|
||||
|
@ -86,8 +84,6 @@ def scodoc_table_etuds_lycees(context, format="html", REQUEST=None):
|
|||
return t
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=tab.page_title,
|
||||
init_google_maps=True,
|
||||
init_qtip=True,
|
||||
|
@ -99,7 +95,7 @@ def scodoc_table_etuds_lycees(context, format="html", REQUEST=None):
|
|||
"""<div id="lyc_map_canvas"></div>
|
||||
""",
|
||||
js_coords_lycees(etuds_by_lycee),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -201,8 +197,6 @@ def formsemestre_etuds_lycees(
|
|||
]
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=tab.page_title,
|
||||
init_google_maps=True,
|
||||
init_qtip=True,
|
||||
|
@ -214,7 +208,7 @@ def formsemestre_etuds_lycees(
|
|||
"""<div id="lyc_map_canvas"></div>
|
||||
""",
|
||||
js_coords_lycees(etuds_by_lycee),
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ def do_moduleimpl_inscription_create(context, args, REQUEST=None, formsemestre_i
|
|||
) # > moduleimpl_inscription
|
||||
if REQUEST:
|
||||
scolog.logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="moduleimpl_inscription",
|
||||
etudid=args["etudid"],
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"""
|
||||
from operator import itemgetter
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -71,13 +72,11 @@ def moduleimpl_inscriptions_edit(
|
|||
if sem["etat"] != "1":
|
||||
raise ScoValueError("opération impossible: semestre verrouille")
|
||||
header = html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Inscription au module",
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
)
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
footer = html_sco_header.sco_footer()
|
||||
H = [
|
||||
header,
|
||||
"""<h2>Inscriptions au module <a href="moduleimpl_status?moduleimpl_id=%s">%s</a> (%s)</a></h2>
|
||||
|
@ -202,9 +201,7 @@ def moduleimpl_inscriptions_edit(
|
|||
sco_moduleimpl.do_moduleimpl_inscrit_etuds(
|
||||
context, moduleimpl_id, formsemestre_id, etuds, reset=True, REQUEST=REQUEST
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"moduleimpl_status?moduleimpl_id=%s" % (moduleimpl_id)
|
||||
)
|
||||
return flask.redirect("moduleimpl_status?moduleimpl_id=%s" % (moduleimpl_id))
|
||||
#
|
||||
H.append(footer)
|
||||
return "\n".join(H)
|
||||
|
@ -425,7 +422,7 @@ def moduleimpl_inscriptions_stats(context, formsemestre_id, REQUEST=None):
|
|||
"""
|
||||
)
|
||||
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -521,7 +518,6 @@ def is_inscrit_ue(context, etudid, formsemestre_id, ue_id):
|
|||
auxquels l'étudiant est inscrit.
|
||||
"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT mod.*
|
||||
FROM notes_moduleimpl mi, notes_modules mod,
|
||||
notes_formsemestre sem, notes_moduleimpl_inscription i
|
||||
|
@ -560,7 +556,6 @@ def do_etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None)
|
|||
)
|
||||
if REQUEST:
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="etud_desinscrit_ue",
|
||||
etudid=etudid,
|
||||
|
|
|
@ -31,6 +31,7 @@ import time
|
|||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
|
||||
from flask import g, url_for
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
|
@ -55,16 +56,16 @@ from app.scodoc import sco_users
|
|||
# menu evaluation dans moduleimpl
|
||||
def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
||||
"Menu avec actions sur une evaluation"
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
modimpl = sco_moduleimpl.do_moduleimpl_list(
|
||||
context, moduleimpl_id=E["moduleimpl_id"]
|
||||
)[0]
|
||||
|
||||
group_id = sco_groups.get_default_group(context, modimpl["formsemestre_id"])
|
||||
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
||||
|
||||
if (
|
||||
sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
)
|
||||
and nbnotes != 0
|
||||
):
|
||||
|
@ -80,7 +81,7 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -90,7 +91,7 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -101,7 +102,7 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
},
|
||||
"enabled": nbnotes == 0
|
||||
and sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -111,7 +112,7 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
"evaluation_id": evaluation_id,
|
||||
},
|
||||
"enabled": sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -130,7 +131,7 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
},
|
||||
"enabled": nbnotes == 0
|
||||
and sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -157,7 +158,6 @@ def moduleimpl_evaluation_menu(context, evaluation_id, nbnotes=0, REQUEST=None):
|
|||
|
||||
def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=None):
|
||||
"""Tableau de bord module (liste des evaluations etc)"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
Mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
|
||||
|
@ -170,26 +170,20 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||
)
|
||||
|
||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||
ModEvals = sco_evaluations.do_evaluation_list(
|
||||
context, {"moduleimpl_id": moduleimpl_id}
|
||||
)
|
||||
ModEvals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||
ModEvals.sort(
|
||||
key=lambda x: (x["numero"], x["jour"], x["heure_debut"]), reverse=True
|
||||
) # la plus RECENTE en tête
|
||||
|
||||
#
|
||||
caneditevals = sco_permissions_check.can_edit_notes(
|
||||
context, authuser, moduleimpl_id, allow_ens=sem["ens_can_edit_eval"]
|
||||
current_user, moduleimpl_id, allow_ens=sem["ens_can_edit_eval"]
|
||||
)
|
||||
caneditnotes = sco_permissions_check.can_edit_notes(
|
||||
context, authuser, moduleimpl_id
|
||||
)
|
||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags(context, REQUEST)
|
||||
caneditnotes = sco_permissions_check.can_edit_notes(current_user, moduleimpl_id)
|
||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags()
|
||||
#
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Module %(titre)s" % Mod
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Module %(titre)s" % Mod),
|
||||
"""<h2 class="formsemestre">Module <tt>%(code)s</tt> %(titre)s</h2>""" % Mod,
|
||||
# XXX """caneditevals=%s caneditnotes=%s""" % (caneditevals,caneditnotes),
|
||||
"""<div class="moduleimpl_tableaubord">
|
||||
|
@ -244,7 +238,7 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||
"""<tr><td class="fichetitre2">Inscrits: </td><td> %d étudiants"""
|
||||
% len(ModInscrits)
|
||||
)
|
||||
if authuser.has_permission(Permission.ScoEtudInscrit):
|
||||
if current_user.has_permission(Permission.ScoEtudInscrit):
|
||||
H.append(
|
||||
"""<a class="stdlink" style="margin-left:2em;" href="moduleimpl_inscriptions_edit?moduleimpl_id=%s">modifier</a>"""
|
||||
% M["moduleimpl_id"]
|
||||
|
@ -283,11 +277,11 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||
)
|
||||
# Adapté à partir d'une suggestion de DS (Le Havre)
|
||||
# Liens saisies absences seulement si permission et date courante dans le semestre
|
||||
if authuser.has_permission(
|
||||
if current_user.has_permission(
|
||||
Permission.ScoAbsChange
|
||||
) and sco_formsemestre.sem_est_courant(context, sem):
|
||||
datelundi = sco_abs.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday()
|
||||
group_id = sco_groups.get_default_group(context, formsemestre_id)
|
||||
group_id = sco_groups.get_default_group(formsemestre_id)
|
||||
H.append(
|
||||
f"""
|
||||
<span class="moduleimpl_abs_link"><a class="stdlink"
|
||||
|
@ -369,7 +363,6 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||
first = True
|
||||
for eval in ModEvals:
|
||||
etat = sco_evaluations.do_evaluation_etat(
|
||||
context,
|
||||
eval["evaluation_id"],
|
||||
partition_id=partition_id,
|
||||
select_first_partition=True,
|
||||
|
@ -654,5 +647,5 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||
scu.icontag("status_visible_img"),
|
||||
)
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "".join(H)
|
||||
|
|
|
@ -31,16 +31,14 @@ import datetime
|
|||
import re
|
||||
import time
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
from io import StringIO
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
from operator import itemgetter
|
||||
import six
|
||||
import PyRSS2Gen # pylint: disable=import-error
|
||||
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
|
@ -83,12 +81,12 @@ scolar_news_list = _scolar_news_editor.list
|
|||
_LAST_NEWS = {} # { (authuser_name, type, object) : time }
|
||||
|
||||
|
||||
def add(context, REQUEST, typ, object=None, text="", url=None, max_frequency=False):
|
||||
def add(typ, object=None, text="", url=None, max_frequency=False):
|
||||
"""Ajoute une nouvelle.
|
||||
Si max_frequency, ne genere pas 2 nouvelles identiques à moins de max_frequency
|
||||
secondes d'intervalle.
|
||||
"""
|
||||
authuser_name = str(REQUEST.AUTHENTICATED_USER)
|
||||
authuser_name = current_user.user_name
|
||||
cnx = ndb.GetDBConnexion()
|
||||
args = {
|
||||
"authenticated_user": authuser_name,
|
||||
|
@ -98,19 +96,19 @@ def add(context, REQUEST, typ, object=None, text="", url=None, max_frequency=Fal
|
|||
"text": text,
|
||||
"url": url,
|
||||
}
|
||||
|
||||
log("news: %s" % args)
|
||||
t = time.time()
|
||||
if max_frequency:
|
||||
last_news_time = _LAST_NEWS.get((authuser_name, typ, object), False)
|
||||
if last_news_time and (t - last_news_time < max_frequency):
|
||||
log("not recording")
|
||||
# log("not recording")
|
||||
return
|
||||
|
||||
log("news: %s" % args)
|
||||
|
||||
_LAST_NEWS[(authuser_name, typ, object)] = t
|
||||
|
||||
_send_news_by_mail(context, args)
|
||||
return scolar_news_create(cnx, args, has_uniq_values=False)
|
||||
_send_news_by_mail(args)
|
||||
return scolar_news_create(cnx, args)
|
||||
|
||||
|
||||
def scolar_news_summary(context, n=5):
|
||||
|
@ -141,7 +139,6 @@ def scolar_news_summary(context, n=5):
|
|||
n["date822"] = n["date"].strftime("%a, %d %b %Y %H:%M:%S %z")
|
||||
# heure
|
||||
n["hm"] = n["date"].strftime("%Hh%M")
|
||||
n["rssdate"] = n["date"].strftime("%d/%m %Hh%M") # pour affichage
|
||||
for k in n.keys():
|
||||
if n[k] is None:
|
||||
n[k] = ""
|
||||
|
@ -198,14 +195,12 @@ def _get_formsemestre_infos_from_news(context, n):
|
|||
return {"formsemestre_id": formsemestre_id, "sem": sem, "descr_sem": descr_sem}
|
||||
|
||||
|
||||
def scolar_news_summary_html(context, n=5, rssicon=None):
|
||||
def scolar_news_summary_html(context, n=5):
|
||||
"""News summary, formated in HTML"""
|
||||
news = scolar_news_summary(context, n=n)
|
||||
if not news:
|
||||
return ""
|
||||
H = ['<div class="news"><span class="newstitle">Dernières opérations']
|
||||
if rssicon: # 2020-12-30 plus utilisé
|
||||
H.append('<a href="rssnews">' + rssicon + "</a>")
|
||||
H.append('</span><ul class="newslist">')
|
||||
|
||||
for n in news:
|
||||
|
@ -231,39 +226,12 @@ def scolar_news_summary_html(context, n=5, rssicon=None):
|
|||
return "\n".join(H)
|
||||
|
||||
|
||||
def scolar_news_summary_rss(context, title, sco_url, n=5):
|
||||
"""rss feed for scolar news"""
|
||||
news = scolar_news_summary(context, n=n)
|
||||
items = []
|
||||
for n in news:
|
||||
text = safehtml.convert_html_to_text(n["text"])
|
||||
items.append(
|
||||
PyRSS2Gen.RSSItem(
|
||||
title=six.text_type("%s %s" % (n["rssdate"], text), SCO_ENCODING),
|
||||
link=sco_url + "/" + n["url"],
|
||||
pubDate=n["date822"],
|
||||
)
|
||||
)
|
||||
rss = PyRSS2Gen.RSS2(
|
||||
title=six.text_type(title, SCO_ENCODING),
|
||||
link=sco_url,
|
||||
description=six.text_type(title, SCO_ENCODING),
|
||||
lastBuildDate=datetime.datetime.now(),
|
||||
items=items,
|
||||
)
|
||||
f = StringIO()
|
||||
rss.write_xml(f, encoding=SCO_ENCODING)
|
||||
f.seek(0)
|
||||
data = f.read()
|
||||
f.close()
|
||||
return data
|
||||
|
||||
|
||||
def _send_news_by_mail(context, n):
|
||||
def _send_news_by_mail(n):
|
||||
"""Notify by email"""
|
||||
context = None # #context
|
||||
infos = _get_formsemestre_infos_from_news(context, n)
|
||||
formsemestre_id = infos.get("formsemestre_id", None)
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id=formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
|
||||
destinations = prefs["emails_notifications"] or ""
|
||||
destinations = [x.strip() for x in destinations.split(",")]
|
||||
destinations = [x for x in destinations if x]
|
||||
|
|
|
@ -279,7 +279,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
|||
alist = []
|
||||
annos = sco_etud.etud_annotations_list(cnx, args={"etudid": etudid})
|
||||
for a in annos:
|
||||
if not sco_permissions_check.can_suppress_annotation(context, a["id"], REQUEST):
|
||||
if not sco_permissions_check.can_suppress_annotation(a["id"]):
|
||||
a["dellink"] = ""
|
||||
else:
|
||||
a[
|
||||
|
@ -355,7 +355,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
|||
|
||||
# Devenir de l'étudiant:
|
||||
has_debouche = True # info['debouche']
|
||||
if sco_permissions_check.can_edit_suivi(context, REQUEST):
|
||||
if sco_permissions_check.can_edit_suivi():
|
||||
suivi_readonly = "0"
|
||||
link_add_suivi = """<li class="adddebouche">
|
||||
<a id="adddebouchelink" class="stdlink" href="#">ajouter une ligne</a>
|
||||
|
@ -478,8 +478,6 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
|||
</div>
|
||||
"""
|
||||
header = html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Fiche étudiant %(prenom)s %(nom)s" % info,
|
||||
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
|
||||
javascripts=[
|
||||
|
@ -491,7 +489,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
|||
"js/etud_debouche.js",
|
||||
],
|
||||
)
|
||||
return header + tmpl % info + html_sco_header.sco_footer(context, REQUEST)
|
||||
return header + tmpl % info + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def menus_etud(context, REQUEST=None):
|
||||
|
@ -547,12 +545,7 @@ def etud_info_html(context, etudid, with_photo="1", REQUEST=None, debug=False):
|
|||
context = context
|
||||
except:
|
||||
pass
|
||||
# log('etud_info_html: %s' % REQUEST.QUERY_STRING)
|
||||
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request(
|
||||
context, REQUEST
|
||||
)
|
||||
# log('etud_info_html: formsemestre_id=%s' % formsemestre_id)
|
||||
|
||||
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
|
||||
with_photo = int(with_photo)
|
||||
etud = sco_etud.get_etud_info(filled=1, REQUEST=REQUEST)[0]
|
||||
photo_html = sco_photos.etud_photo_html(
|
||||
|
|
|
@ -574,7 +574,6 @@ class SituationEtudParcoursGeneric(object):
|
|||
decision.formsemestre_id_utilise_pour_compenser,
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="validate_sem",
|
||||
etudid=self.etudid,
|
||||
|
@ -607,7 +606,6 @@ class SituationEtudParcoursGeneric(object):
|
|||
formsemestre_id_utilise_pour_compenser=fsid,
|
||||
)
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="validate_sem",
|
||||
etudid=self.etudid,
|
||||
|
@ -932,7 +930,6 @@ def formsemestre_validate_ues(
|
|||
|
||||
if REQUEST:
|
||||
logdb(
|
||||
REQUEST,
|
||||
cnx,
|
||||
method="validate_ue",
|
||||
etudid=etudid,
|
||||
|
|
|
@ -31,17 +31,13 @@
|
|||
Tout accès à ReportLab doit donc être précédé d'un PDFLOCK.acquire()
|
||||
et terminé par un PDFLOCK.release()
|
||||
"""
|
||||
import io
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
import unicodedata
|
||||
import traceback
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
|
||||
import reportlab
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||
|
@ -59,7 +55,6 @@ from reportlab.lib.pagesizes import letter, A4, landscape
|
|||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.sco_utils import (
|
||||
CONFIG,
|
||||
SCO_ENCODING,
|
||||
SCODOC_LOGOS_DIR,
|
||||
LOGOS_IMAGES_ALLOWED_TYPES,
|
||||
)
|
||||
|
@ -78,13 +73,15 @@ DEFAULT_PDF_FOOTER_TEMPLATE = CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE
|
|||
|
||||
def SU(s):
|
||||
"convert s from string to string suitable for ReportLab"
|
||||
# A priori inutile en Python 3, mais tester les "combining accents"
|
||||
return s or ""
|
||||
# Remplace caractères composés
|
||||
# eg 'e\xcc\x81' COMBINING ACUTE ACCENT par '\xc3\xa9' LATIN SMALL LETTER E WITH ACUTE
|
||||
# car les "combining accents" ne sont pas traités par ReportLab mais peuvent
|
||||
# nous être envoyés par certains navigateurs ou imports
|
||||
# return unicodedata.normalize("NFC", s)
|
||||
if not s:
|
||||
return ""
|
||||
else:
|
||||
# Remplace caractères composés
|
||||
# eg 'e\xcc\x81' COMBINING ACUTE ACCENT par '\xc3\xa9' LATIN SMALL LETTER E WITH ACUTE
|
||||
# car les "combining accents" ne sont pas traités par ReportLab mais peuvent
|
||||
# nous être envoyés par certains navigateurs ou imports
|
||||
# (on en a dans les bases de données)
|
||||
return unicodedata.normalize("NFC", s)
|
||||
|
||||
|
||||
def _splitPara(txt):
|
||||
|
@ -189,7 +186,10 @@ class ScolarsPageTemplate(PageTemplate):
|
|||
self.server_name = server_name
|
||||
self.filigranne = filigranne
|
||||
self.footer_template = footer_template
|
||||
self.with_page_background = self.preferences["bul_pdf_with_background"]
|
||||
if self.preferences:
|
||||
self.with_page_background = self.preferences["bul_pdf_with_background"]
|
||||
else:
|
||||
self.with_page_background = False
|
||||
self.background_image_filename = None
|
||||
# Our doc is made of a single frame
|
||||
left, top, right, bottom = [float(x) for x in margins]
|
||||
|
@ -229,6 +229,8 @@ class ScolarsPageTemplate(PageTemplate):
|
|||
server_url: URL du serveur ScoDoc
|
||||
|
||||
"""
|
||||
if not self.preferences:
|
||||
return
|
||||
canvas.saveState()
|
||||
# ---- Background image
|
||||
if self.background_image_filename and self.with_page_background:
|
||||
|
@ -308,7 +310,7 @@ def pdf_basic_page(
|
|||
adding a title if specified.
|
||||
"""
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
report = StringIO.StringIO() # in-memory document, no disk file
|
||||
report = io.BytesIO() # in-memory document, no disk file
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
|
|
|
@ -14,7 +14,7 @@ from app.scodoc import sco_exceptions
|
|||
from app.scodoc import sco_moduleimpl
|
||||
|
||||
|
||||
def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
|
||||
def can_edit_notes(authuser, moduleimpl_id, allow_ens=True):
|
||||
"""True if authuser can enter or edit notes in this module.
|
||||
If allow_ens, grant access to all ens in this module
|
||||
|
||||
|
@ -24,6 +24,7 @@ def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
|
|||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc import sco_parcours_dut
|
||||
|
||||
context = None # XXX #context
|
||||
uid = str(authuser)
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
|
||||
|
@ -52,27 +53,26 @@ def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
|
|||
return True
|
||||
|
||||
|
||||
def can_edit_evaluation(context, REQUEST, moduleimpl_id=None):
|
||||
def can_edit_evaluation(moduleimpl_id=None):
|
||||
"""Vérifie que l'on a le droit de modifier, créer ou détruire une
|
||||
évaluation dans ce module.
|
||||
Sinon, lance une exception.
|
||||
(nb: n'implique pas le droit de saisir ou modifier des notes)
|
||||
"""
|
||||
context = None # #context
|
||||
# was _evaluation_check_write_access
|
||||
# AccessDenied("Modification évaluation impossible pour %s" % (uid,))
|
||||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc import sco_moduleimpl
|
||||
|
||||
# acces pour resp. moduleimpl et resp. form semestre (dir etud)
|
||||
if moduleimpl_id is None:
|
||||
raise ValueError("no moduleimpl specified") # bug
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
uid = str(authuser)
|
||||
uid = current_user.user_name
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
|
||||
|
||||
if (
|
||||
authuser.has_permission(Permission.ScoEditAllEvals)
|
||||
current_user.has_permission(Permission.ScoEditAllEvals)
|
||||
or uid == M["responsable_id"]
|
||||
or uid in sem["responsables"]
|
||||
):
|
||||
|
@ -85,7 +85,7 @@ def can_edit_evaluation(context, REQUEST, moduleimpl_id=None):
|
|||
return False
|
||||
|
||||
|
||||
def can_suppress_annotation(context, annotation_id, REQUEST):
|
||||
def can_suppress_annotation(annotation_id):
|
||||
"""True if current user can suppress this annotation
|
||||
Seuls l'auteur de l'annotation et le chef de dept peuvent supprimer
|
||||
une annotation.
|
||||
|
@ -95,77 +95,71 @@ def can_suppress_annotation(context, annotation_id, REQUEST):
|
|||
if len(annos) != 1:
|
||||
raise sco_exceptions.ScoValueError("annotation inexistante !")
|
||||
anno = annos[0]
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
return (
|
||||
str(authuser) == anno["zope_authenticated_user"]
|
||||
) or authuser.has_permission(Permission.ScoEtudAddAnnotations)
|
||||
current_user.user_name == anno["zope_authenticated_user"]
|
||||
) or current_user.has_permission(Permission.ScoEtudAddAnnotations)
|
||||
|
||||
|
||||
def can_edit_suivi(context, REQUEST=None):
|
||||
def can_edit_suivi():
|
||||
"""Vrai si l'utilisateur peut modifier les informations de suivi sur la page etud" """
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
return authuser.has_permission(Permission.ScoEtudChangeAdr)
|
||||
return current_user.has_permission(Permission.ScoEtudChangeAdr)
|
||||
|
||||
|
||||
def can_validate_sem(context, REQUEST, formsemestre_id):
|
||||
def can_validate_sem(formsemestre_id):
|
||||
"Vrai si utilisateur peut saisir decision de jury dans ce semestre"
|
||||
from app.scodoc import sco_formsemestre
|
||||
|
||||
context = None # XXX #context
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if sem["etat"] != "1":
|
||||
return False # semestre verrouillé
|
||||
|
||||
return is_chef_or_diretud(context, REQUEST, sem)
|
||||
return is_chef_or_diretud(sem)
|
||||
|
||||
|
||||
def can_edit_pv(context, REQUEST, formsemestre_id):
|
||||
def can_edit_pv(formsemestre_id):
|
||||
"Vrai si utilisateur peut editer un PV de jury de ce semestre"
|
||||
from app.scodoc import sco_formsemestre
|
||||
|
||||
context = None # XXX #context
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if is_chef_or_diretud(context, REQUEST, sem):
|
||||
if is_chef_or_diretud(sem):
|
||||
return True
|
||||
# Autorise les secrétariats, repérés via la permission ScoEtudChangeAdr
|
||||
# (ceci nous évite d'ajouter une permission Zope aux installations existantes)
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
return authuser.has_permission(Permission.ScoEtudChangeAdr)
|
||||
return current_user.has_permission(Permission.ScoEtudChangeAdr)
|
||||
|
||||
|
||||
def is_chef_or_diretud(context, REQUEST, sem):
|
||||
def is_chef_or_diretud(sem):
|
||||
"Vrai si utilisateur est admin, chef dept ou responsable du semestre"
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
if authuser.has_permission(Permission.ScoImplement):
|
||||
return True # admin, chef dept
|
||||
uid = str(authuser)
|
||||
if uid in sem["responsables"]:
|
||||
if (
|
||||
current_user.has_permission(Permission.ScoImplement)
|
||||
or current_user.user_name in sem["responsables"]
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_access_diretud(
|
||||
context, formsemestre_id, REQUEST, required_permission=Permission.ScoImplement
|
||||
):
|
||||
def check_access_diretud(formsemestre_id, required_permission=Permission.ScoImplement):
|
||||
"""Check if access granted: responsable or ScoImplement
|
||||
Return True|False, HTML_error_page
|
||||
"""
|
||||
from app.scodoc import sco_formsemestre
|
||||
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
context = None # XXX #context
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
header = html_sco_header.sco_header(
|
||||
context, page_title="Accès interdit", REQUEST=REQUEST
|
||||
)
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
if (str(authuser) not in sem["responsables"]) and not authuser.has_permission(
|
||||
required_permission
|
||||
):
|
||||
header = html_sco_header.sco_header(page_title="Accès interdit")
|
||||
footer = html_sco_header.sco_footer()
|
||||
if (
|
||||
current_user.user_name not in sem["responsables"]
|
||||
) and not current_user.has_permission(required_permission):
|
||||
return (
|
||||
False,
|
||||
"\n".join(
|
||||
[
|
||||
header,
|
||||
"<h2>Opération non autorisée pour %s</h2>" % authuser,
|
||||
"<h2>Opération non autorisée pour %s</h2>" % current_user,
|
||||
"<p>Responsable de ce semestre : <b>%s</b></p>"
|
||||
% ", ".join(sem["responsables"]),
|
||||
footer,
|
||||
|
@ -176,18 +170,17 @@ def check_access_diretud(
|
|||
return True, ""
|
||||
|
||||
|
||||
def can_change_groups(context, REQUEST, formsemestre_id):
|
||||
def can_change_groups(formsemestre_id):
|
||||
"Vrai si l'utilisateur peut changer les groupes dans ce semestre"
|
||||
from app.scodoc import sco_formsemestre
|
||||
|
||||
context = None # XXX #context
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if sem["etat"] != "1":
|
||||
return False # semestre verrouillé
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
if authuser.has_permission(Permission.ScoEtudChangeGroups):
|
||||
if current_user.has_permission(Permission.ScoEtudChangeGroups):
|
||||
return True # admin, chef dept
|
||||
uid = str(authuser)
|
||||
if uid in sem["responsables"]:
|
||||
if current_user.user_name in sem["responsables"]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ Les images sont servies par ScoDoc, via la méthode getphotofile?etudid=xxx
|
|||
|
||||
"""
|
||||
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import datetime
|
||||
|
@ -51,10 +52,6 @@ import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
|
|||
import traceback
|
||||
from PIL import Image as PILImage
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
import glob
|
||||
|
||||
from flask import request
|
||||
|
@ -241,7 +238,7 @@ def photo_pathname(context, etud, size="orig"):
|
|||
def store_photo(context, etud, data, REQUEST=None):
|
||||
"""Store image for this etud.
|
||||
If there is an existing photo, it is erased and replaced.
|
||||
data is a string with image raw data.
|
||||
data is a bytes string with image raw data.
|
||||
|
||||
Update database to store filename.
|
||||
|
||||
|
@ -260,8 +257,7 @@ def store_photo(context, etud, data, REQUEST=None):
|
|||
sco_etud.identite_edit_nocheck(cnx, etud)
|
||||
cnx.commit()
|
||||
#
|
||||
if REQUEST:
|
||||
logdb(REQUEST, cnx, method="changePhoto", msg=filename, etudid=etud["etudid"])
|
||||
logdb(cnx, method="changePhoto", msg=filename, etudid=etud["etudid"])
|
||||
#
|
||||
return 1, "ok"
|
||||
|
||||
|
@ -285,9 +281,7 @@ def suppress_photo(context, etud, REQUEST=None):
|
|||
os.remove(filename)
|
||||
# 3- log
|
||||
if REQUEST:
|
||||
logdb(
|
||||
REQUEST, cnx, method="changePhoto", msg="suppression", etudid=etud["etudid"]
|
||||
)
|
||||
logdb(cnx, method="changePhoto", msg="suppression", etudid=etud["etudid"])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
@ -295,11 +289,11 @@ def suppress_photo(context, etud, REQUEST=None):
|
|||
|
||||
|
||||
def save_image(context, etudid, data):
|
||||
"""img_file is a file-like object.
|
||||
"""data is a bytes string.
|
||||
Save image in JPEG in 2 sizes (original and h90).
|
||||
Returns filename (relative to PHOTO_DIR), without extension
|
||||
"""
|
||||
data_file = StringIO()
|
||||
data_file = io.BytesIO()
|
||||
data_file.write(data)
|
||||
data_file.seek(0)
|
||||
img = PILImage.open(data_file)
|
||||
|
@ -355,7 +349,7 @@ def copy_portal_photo_to_fs(context, etud, REQUEST=None):
|
|||
url = photo_portal_url(context, etud)
|
||||
if not url:
|
||||
return None, "%(nomprenom)s: pas de code NIP" % etud
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
f = None
|
||||
try:
|
||||
log("copy_portal_photo_to_fs: getting %s" % url)
|
||||
|
|
|
@ -33,6 +33,8 @@ Contribution M. Salomon, UFC / IUT DE BELFORT-MONTBÉLIARD, 2016
|
|||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
import random
|
||||
|
||||
import flask
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -59,7 +61,7 @@ def do_placement_selectetuds(context, REQUEST):
|
|||
Choisi les étudiants et les infos sur la salle pour leur placement.
|
||||
"""
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not E:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
E = E[0]
|
||||
|
@ -75,7 +77,7 @@ def do_placement_selectetuds(context, REQUEST):
|
|||
# description de l'evaluation
|
||||
H = [
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
),
|
||||
"<h3>Placement et émargement des étudiants</h3>",
|
||||
]
|
||||
|
@ -195,7 +197,7 @@ def do_placement_selectetuds(context, REQUEST):
|
|||
H.append("""<div class="saisienote_etape1">""")
|
||||
return "\n".join(H) + "\n" + tf[1] + "\n</div>"
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"%s/Notes/moduleimpl_status?moduleimpl_id=%s"
|
||||
% (scu.ScoURL(), E["moduleimpl_id"])
|
||||
)
|
||||
|
@ -225,7 +227,7 @@ def do_placement_selectetuds(context, REQUEST):
|
|||
)
|
||||
+ "&".join(gs)
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(scu.NotesURL() + "/do_placement?" + query)
|
||||
return flask.redirect(scu.NotesURL() + "/do_placement?" + query)
|
||||
else:
|
||||
raise ValueError(
|
||||
"invalid placement_method (%s)" % tf[2]["placement_method"]
|
||||
|
@ -244,11 +246,11 @@ def do_placement(context, REQUEST):
|
|||
raise ScoValueError(
|
||||
"Formulaire incomplet ! Vous avez sans doute attendu trop longtemps, veuillez vous reconnecter. Si le problème persiste, contacter l'administrateur. Merci."
|
||||
)
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
|
||||
# Check access
|
||||
# (admin, respformation, and responsable_id)
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
||||
return (
|
||||
"<h2>Génération du placement impossible pour %s</h2>" % authusername
|
||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||
|
@ -278,7 +280,7 @@ def do_placement(context, REQUEST):
|
|||
else:
|
||||
getallstudents = False
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, groups, getallstudents=getallstudents, include_dems=True
|
||||
evaluation_id, groups, getallstudents=getallstudents, include_dems=True
|
||||
)
|
||||
if not etudids:
|
||||
return "<p>Aucun groupe sélectionné !</p>"
|
||||
|
@ -320,11 +322,11 @@ def do_placement(context, REQUEST):
|
|||
maxlines = sem_preferences.get("feuille_placement_positions")
|
||||
|
||||
if placement_method == "xls":
|
||||
filename = "placement_%s_%s.xls" % (evalname, gr_title_filename)
|
||||
filename = f"placement_{evalname}_{gr_title_filename}{scu.XLSX_SUFFIX}"
|
||||
xls = Excel_feuille_placement(
|
||||
E, desceval, listetud, columns, space, maxlines, building, room, numbering
|
||||
)
|
||||
return sco_excel.sendExcelFile(REQUEST, xls, filename)
|
||||
return sco_excel.send_excel_file(REQUEST, xls, filename)
|
||||
else:
|
||||
nbcolumns = int(columns)
|
||||
|
||||
|
@ -392,7 +394,7 @@ def do_placement(context, REQUEST):
|
|||
+ "",
|
||||
pdf_title=pdf_title,
|
||||
# pdf_shorttitle = '',
|
||||
preferences=sco_preferences.SemPreferences(context, M["formsemestre_id"]),
|
||||
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
|
||||
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
|
||||
)
|
||||
t = tab.make_page(
|
||||
|
@ -403,9 +405,7 @@ def do_placement(context, REQUEST):
|
|||
|
||||
def placement_eval_selectetuds(context, evaluation_id, REQUEST=None):
|
||||
"""Dialogue placement etudiants: choix methode et localisation"""
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not evals:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
theeval = evals[0]
|
||||
|
@ -414,7 +414,7 @@ def placement_eval_selectetuds(context, evaluation_id, REQUEST=None):
|
|||
page_title = 'Placement "%s"' % theeval["description"]
|
||||
else:
|
||||
page_title = "Placement des étudiants"
|
||||
H = [html_sco_header.sco_header(context, REQUEST, page_title=page_title)]
|
||||
H = [html_sco_header.sco_header(page_title=page_title)]
|
||||
|
||||
formid = "placementfile"
|
||||
if not REQUEST.form.get("%s-submitted" % formid, False):
|
||||
|
@ -444,7 +444,7 @@ def placement_eval_selectetuds(context, evaluation_id, REQUEST=None):
|
|||
</ul>
|
||||
"""
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -663,8 +663,8 @@ def Excel_feuille_placement(
|
|||
li = 0
|
||||
line = 0
|
||||
dt = time.strftime("%d/%m/%Y a %Hh%M")
|
||||
ws0.write(li, 0, u"Feuille placement etudiants éditée le %s" % dt, style_titres)
|
||||
ws1.write(li, 0, u"Feuille placement etudiants éditée le %s" % dt, style_titres)
|
||||
ws0.write(li, 0, "Feuille placement etudiants éditée le %s" % dt, style_titres)
|
||||
ws1.write(li, 0, "Feuille placement etudiants éditée le %s" % dt, style_titres)
|
||||
for desceval in description:
|
||||
if line % 2 == 0:
|
||||
li += 2
|
||||
|
@ -677,41 +677,39 @@ def Excel_feuille_placement(
|
|||
ws0.write(
|
||||
li,
|
||||
0,
|
||||
u"Date : %s - Horaire : %s à %s"
|
||||
% (E["jour"], E["heure_debut"], E["heure_fin"]),
|
||||
"Date : %s - Horaire : %s à %s" % (E["jour"], E["heure_debut"], E["heure_fin"]),
|
||||
style_titres,
|
||||
)
|
||||
ws1.write(
|
||||
li,
|
||||
0,
|
||||
u"Date : %s - Horaire : %s à %s"
|
||||
% (E["jour"], E["heure_debut"], E["heure_fin"]),
|
||||
"Date : %s - Horaire : %s à %s" % (E["jour"], E["heure_debut"], E["heure_fin"]),
|
||||
style_titres,
|
||||
)
|
||||
li += 1
|
||||
|
||||
# entetes colonnes - feuille0
|
||||
for col in range(nbcolumns):
|
||||
ws0.write(li, col + 1, u"colonne %s" % (col + 1), style2b)
|
||||
ws0.write(li, col + 1, "colonne %s" % (col + 1), style2b)
|
||||
# entetes colonnes - feuille1
|
||||
if numbering == "coordinate":
|
||||
ws1.write(li, 0, u"Nom", style2bi)
|
||||
ws1.write(li, 1, u"Prénom", style2bi)
|
||||
ws1.write(li, 2, u"Colonne", style2bi)
|
||||
ws1.write(li, 3, u"Ligne", style2bi)
|
||||
ws1.write(li, 0, "Nom", style2bi)
|
||||
ws1.write(li, 1, "Prénom", style2bi)
|
||||
ws1.write(li, 2, "Colonne", style2bi)
|
||||
ws1.write(li, 3, "Ligne", style2bi)
|
||||
|
||||
ws1.write(li, 5, u"Nom", style2bi)
|
||||
ws1.write(li, 6, u"Prénom", style2bi)
|
||||
ws1.write(li, 7, u"Colonne", style2bi)
|
||||
ws1.write(li, 8, u"Ligne", style2bi)
|
||||
ws1.write(li, 5, "Nom", style2bi)
|
||||
ws1.write(li, 6, "Prénom", style2bi)
|
||||
ws1.write(li, 7, "Colonne", style2bi)
|
||||
ws1.write(li, 8, "Ligne", style2bi)
|
||||
else:
|
||||
ws1.write(li, 0, u"Nom", style2bi)
|
||||
ws1.write(li, 1, u"Prénom", style2bi)
|
||||
ws1.write(li, 2, u"Place", style2bi)
|
||||
ws1.write(li, 0, "Nom", style2bi)
|
||||
ws1.write(li, 1, "Prénom", style2bi)
|
||||
ws1.write(li, 2, "Place", style2bi)
|
||||
|
||||
ws1.write(li, 4, u"Nom", style2bi)
|
||||
ws1.write(li, 5, u"Prénom", style2bi)
|
||||
ws1.write(li, 6, u"Place", style2bi)
|
||||
ws1.write(li, 4, "Nom", style2bi)
|
||||
ws1.write(li, 5, "Prénom", style2bi)
|
||||
ws1.write(li, 6, "Place", style2bi)
|
||||
|
||||
# etudiants
|
||||
line = 1
|
||||
|
@ -751,7 +749,7 @@ def Excel_feuille_placement(
|
|||
ws0.write(li0 + 2, col, " ", style1bb)
|
||||
else:
|
||||
ws0.write(
|
||||
li0 + 2, col, u"place %s" % (col + (line - 1) * nbcolumns), style1bb
|
||||
li0 + 2, col, "place %s" % (col + (line - 1) * nbcolumns), style1bb
|
||||
)
|
||||
# ws0.write(li+3,col, ' ', style1bm )
|
||||
# ws0.write(li+4,col, ' ', style1bb )
|
||||
|
@ -793,21 +791,21 @@ def Excel_feuille_placement(
|
|||
nbcol = 0
|
||||
col = 0
|
||||
if numbering == "coordinate":
|
||||
ws1.write(li, 0, u"Nom", style2bi)
|
||||
ws1.write(li, 1, u"Prénom", style2bi)
|
||||
ws1.write(li, 2, u"Colonne", style2bi)
|
||||
ws1.write(li, 3, u"Ligne", style2bi)
|
||||
ws1.write(li, 0, "Nom", style2bi)
|
||||
ws1.write(li, 1, "Prénom", style2bi)
|
||||
ws1.write(li, 2, "Colonne", style2bi)
|
||||
ws1.write(li, 3, "Ligne", style2bi)
|
||||
|
||||
ws1.write(li, 5, u"Nom", style2bi)
|
||||
ws1.write(li, 6, u"Prénom", style2bi)
|
||||
ws1.write(li, 7, u"Colonne", style2bi)
|
||||
ws1.write(li, 8, u"Ligne", style2bi)
|
||||
ws1.write(li, 5, "Nom", style2bi)
|
||||
ws1.write(li, 6, "Prénom", style2bi)
|
||||
ws1.write(li, 7, "Colonne", style2bi)
|
||||
ws1.write(li, 8, "Ligne", style2bi)
|
||||
else:
|
||||
ws1.write(li, 0, u"Nom", style2bi)
|
||||
ws1.write(li, 1, u"Prénom", style2bi)
|
||||
ws1.write(li, 2, u"Place", style2bi)
|
||||
ws1.write(li, 0, "Nom", style2bi)
|
||||
ws1.write(li, 1, "Prénom", style2bi)
|
||||
ws1.write(li, 2, "Place", style2bi)
|
||||
|
||||
ws1.write(li, 4, u"Nom", style2bi)
|
||||
ws1.write(li, 5, u"Prénom", style2bi)
|
||||
ws1.write(li, 6, u"Place", style2bi)
|
||||
ws1.write(li, 4, "Nom", style2bi)
|
||||
ws1.write(li, 5, "Prénom", style2bi)
|
||||
ws1.write(li, 6, "Place", style2bi)
|
||||
return wb.savetostr()
|
||||
|
|
|
@ -56,7 +56,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_portal_url(self, context):
|
||||
"URL of portal"
|
||||
portal_url = sco_preferences.get_preference(context, "portal_url")
|
||||
portal_url = sco_preferences.get_preference("portal_url")
|
||||
if not self.warning:
|
||||
if portal_url:
|
||||
log("Portal URL=%s" % portal_url)
|
||||
|
@ -67,7 +67,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_etapes_url(self, context):
|
||||
"Full URL of service giving list of etapes (in XML)"
|
||||
etapes_url = sco_preferences.get_preference(context, "etapes_url")
|
||||
etapes_url = sco_preferences.get_preference("etapes_url")
|
||||
if not etapes_url:
|
||||
# Default:
|
||||
portal_url = self.get_portal_url(context)
|
||||
|
@ -82,7 +82,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_etud_url(self, context):
|
||||
"Full URL of service giving list of students (in XML)"
|
||||
etud_url = sco_preferences.get_preference(context, "etud_url")
|
||||
etud_url = sco_preferences.get_preference("etud_url")
|
||||
if not etud_url:
|
||||
# Default:
|
||||
portal_url = self.get_portal_url(context)
|
||||
|
@ -97,7 +97,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_photo_url(self, context):
|
||||
"Full URL of service giving photo of student"
|
||||
photo_url = sco_preferences.get_preference(context, "photo_url")
|
||||
photo_url = sco_preferences.get_preference("photo_url")
|
||||
if not photo_url:
|
||||
# Default:
|
||||
portal_url = self.get_portal_url(context)
|
||||
|
@ -112,7 +112,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_maquette_url(self, context):
|
||||
"""Full URL of service giving Apogee maquette pour une étape (fichier "CSV")"""
|
||||
maquette_url = sco_preferences.get_preference(context, "maquette_url")
|
||||
maquette_url = sco_preferences.get_preference("maquette_url")
|
||||
if not maquette_url:
|
||||
# Default:
|
||||
portal_url = self.get_portal_url(context)
|
||||
|
@ -123,7 +123,7 @@ class PortalInterface(object):
|
|||
|
||||
def get_portal_api_version(self, context):
|
||||
"API version of the portal software"
|
||||
api_ver = sco_preferences.get_preference(context, "portal_api")
|
||||
api_ver = sco_preferences.get_preference("portal_api")
|
||||
if not api_ver:
|
||||
# Default:
|
||||
api_ver = 1
|
||||
|
@ -152,7 +152,7 @@ def get_inscrits_etape(context, code_etape, anneeapogee=None, ntrials=2):
|
|||
api_ver = get_portal_api_version(context)
|
||||
if not etud_url:
|
||||
return []
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
if api_ver > 1:
|
||||
req = (
|
||||
etud_url
|
||||
|
@ -208,7 +208,7 @@ def query_apogee_portal(context, **args):
|
|||
# Ne fonctionne pas avec l'API 2 sur nom et prenom
|
||||
# XXX TODO : va poser problème pour la page modif données étudiants : A VOIR
|
||||
return []
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
req = etud_url + "?" + six.moves.urllib.parse.urlencode(list(args.items()))
|
||||
doc = scu.query_portal(req, timeout=portal_timeout) # sco_utils
|
||||
return xml_to_list_of_dicts(doc, req=req)
|
||||
|
@ -267,20 +267,14 @@ def xml_to_list_of_dicts(doc, req=None):
|
|||
def get_infos_apogee_allaccents(context, nom, prenom):
|
||||
"essai recup infos avec differents codages des accents"
|
||||
if nom:
|
||||
unom = six.text_type(nom, scu.SCO_ENCODING)
|
||||
nom_noaccents = scu.suppress_accents(unom)
|
||||
nom_utf8 = unom.encode("utf-8")
|
||||
nom_noaccents = scu.suppress_accents(nom)
|
||||
else:
|
||||
nom_noaccents = nom
|
||||
nom_utf8 = nom
|
||||
|
||||
if prenom:
|
||||
uprenom = six.text_type(prenom, scu.SCO_ENCODING)
|
||||
prenom_noaccents = scu.suppress_accents(uprenom)
|
||||
prenom_utf8 = uprenom.encode("utf-8")
|
||||
prenom_noaccents = scu.suppress_accents(prenom)
|
||||
else:
|
||||
prenom_noaccents = prenom
|
||||
prenom_utf8 = prenom
|
||||
|
||||
# avec accents
|
||||
infos = query_apogee_portal(context, nom=nom, prenom=prenom)
|
||||
|
@ -289,9 +283,6 @@ def get_infos_apogee_allaccents(context, nom, prenom):
|
|||
infos += query_apogee_portal(
|
||||
context, nom=nom_noaccents, prenom=prenom_noaccents
|
||||
)
|
||||
# avec accents en UTF-8
|
||||
if nom_utf8 != nom_noaccents or prenom_utf8 != prenom_noaccents:
|
||||
infos += query_apogee_portal(context, nom=nom_utf8, prenom=prenom_utf8)
|
||||
return infos
|
||||
|
||||
|
||||
|
@ -330,7 +321,7 @@ def get_etud_apogee(context, code_nip):
|
|||
etud_url = get_etud_url(context)
|
||||
if not etud_url:
|
||||
return {}
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
req = etud_url + "?" + six.moves.urllib.parse.urlencode((("nip", code_nip),))
|
||||
doc = scu.query_portal(req, timeout=portal_timeout)
|
||||
d = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req))
|
||||
|
@ -363,7 +354,7 @@ def _parse_etapes_from_xml(context, doc):
|
|||
"""
|
||||
may raise exception if invalid xml doc
|
||||
"""
|
||||
xml_etapes_by_dept = sco_preferences.get_preference(context, "xml_etapes_by_dept")
|
||||
xml_etapes_by_dept = sco_preferences.get_preference("xml_etapes_by_dept")
|
||||
# parser XML
|
||||
dom = xml.dom.minidom.parseString(doc)
|
||||
infos = {}
|
||||
|
@ -391,7 +382,7 @@ def get_etapes_apogee(context):
|
|||
etapes_url = get_etapes_url(context)
|
||||
infos = {}
|
||||
if etapes_url:
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
log(
|
||||
"get_etapes_apogee: requesting '%s' with timeout=%s"
|
||||
% (etapes_url, portal_timeout)
|
||||
|
@ -439,9 +430,9 @@ def get_etapes_apogee_dept(context):
|
|||
|
||||
Returns [ ( code, intitule) ], ordonnée
|
||||
"""
|
||||
xml_etapes_by_dept = sco_preferences.get_preference(context, "xml_etapes_by_dept")
|
||||
xml_etapes_by_dept = sco_preferences.get_preference("xml_etapes_by_dept")
|
||||
if xml_etapes_by_dept:
|
||||
portal_dept_name = sco_preferences.get_preference(context, "portal_dept_name")
|
||||
portal_dept_name = sco_preferences.get_preference("portal_dept_name")
|
||||
log('get_etapes_apogee_dept: portal_dept_name="%s"' % portal_dept_name)
|
||||
else:
|
||||
portal_dept_name = ""
|
||||
|
@ -565,7 +556,7 @@ def get_maquette_apogee(context, etape="", annee_scolaire=""):
|
|||
maquette_url = get_maquette_url(context)
|
||||
if not maquette_url:
|
||||
return None
|
||||
portal_timeout = sco_preferences.get_preference(context, "portal_timeout")
|
||||
portal_timeout = sco_preferences.get_preference("portal_timeout")
|
||||
req = (
|
||||
maquette_url
|
||||
+ "?"
|
||||
|
|
|
@ -170,7 +170,7 @@ def formsemestre_poursuite_report(
|
|||
"""Table avec informations "poursuite" """
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
etuds = _getEtudInfoGroupes(
|
||||
context, [sco_groups.get_default_group(context, formsemestre_id)]
|
||||
context, [sco_groups.get_default_group(formsemestre_id)]
|
||||
)
|
||||
|
||||
infos = []
|
||||
|
@ -206,7 +206,7 @@ def formsemestre_poursuite_report(
|
|||
html_sortable=True,
|
||||
html_class="table_leftalign table_listegroupe",
|
||||
pdf_link=False, # pas d'export pdf
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
tab.filename = scu.make_filename("poursuite " + sem["titreannee"])
|
||||
|
||||
|
|
|
@ -68,18 +68,18 @@ des tuples (name, value, formsemestre_id).
|
|||
Si formsemestre_id est NULL, la valeur concerne tous les semestres,
|
||||
sinon, elle ne concerne que le semestre indiqué.
|
||||
|
||||
* Utilisation dans ScoDoc7
|
||||
* Utilisation dans ScoDoc8
|
||||
- lire une valeur:
|
||||
get_preference(context, name, formsemestre_id)
|
||||
get_preference(name, formsemestre_id)
|
||||
nb: les valeurs sont des chaines, sauf:
|
||||
. si le type est spécfié (float ou int)
|
||||
. les boolcheckbox qui sont des entiers 0 ou 1
|
||||
- avoir un mapping (read only) de toutes les valeurs:
|
||||
sco_preferences.SemPreferences(context,formsemestre_id)
|
||||
sco_preferences.SemPreferences(formsemestre_id)
|
||||
- editer les preferences globales:
|
||||
sco_preferences.get_base_preferences(self).edit(REQUEST=REQUEST)
|
||||
- editer les preferences d'un semestre:
|
||||
SemPreferences(context,formsemestre_id).edit()
|
||||
SemPreferences(formsemestre_id).edit()
|
||||
|
||||
* Implémentation: sco_preferences.py
|
||||
|
||||
|
@ -98,7 +98,7 @@ Une instance unique par site (département, repéré par URL).
|
|||
.deleteformsemestre_id, name)
|
||||
.edit() (HTML dialog)
|
||||
|
||||
class SemPreferences(context,formsemestre_id)
|
||||
class SemPreferences(formsemestre_id)
|
||||
Une instance par semestre, et une instance pour prefs globales.
|
||||
L'attribut .base_prefs point sur BasePreferences.
|
||||
.__getitem__ [name]
|
||||
|
@ -106,10 +106,11 @@ L'attribut .base_prefs point sur BasePreferences.
|
|||
.edit(categories=[])
|
||||
|
||||
|
||||
get_base_preferences(context, formsemestre_id)
|
||||
Return base preferences for this context (instance BasePreferences)
|
||||
get_base_preferences(formsemestre_id)
|
||||
Return base preferences for current scodoc_dept (instance BasePreferences)
|
||||
|
||||
"""
|
||||
import flask
|
||||
from flask import g
|
||||
|
||||
from app.scodoc import sco_cache
|
||||
|
@ -122,20 +123,20 @@ import app.scodoc.sco_utils as scu
|
|||
_SCO_BASE_PREFERENCES = {} # { URL: BasePreferences instance }
|
||||
|
||||
|
||||
def get_base_preferences(context):
|
||||
def get_base_preferences():
|
||||
"""Return global preferences for the current department"""
|
||||
dept = g.scodoc_dept
|
||||
if not dept in _SCO_BASE_PREFERENCES:
|
||||
_SCO_BASE_PREFERENCES[dept] = BasePreferences(context)
|
||||
_SCO_BASE_PREFERENCES[dept] = BasePreferences()
|
||||
return _SCO_BASE_PREFERENCES[dept]
|
||||
|
||||
|
||||
def get_preference(context, name, formsemestre_id=None):
|
||||
def get_preference(name, formsemestre_id=None):
|
||||
"""Returns value of named preference.
|
||||
All preferences have a sensible default value, so this
|
||||
function always returns a usable value for all defined preferences names.
|
||||
"""
|
||||
return get_base_preferences(context).get(formsemestre_id, name)
|
||||
return get_base_preferences().get(formsemestre_id, name)
|
||||
|
||||
|
||||
PREF_CATEGORIES = (
|
||||
|
@ -205,8 +206,7 @@ class BasePreferences(object):
|
|||
filter_nulls=False,
|
||||
)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
def __init__(self):
|
||||
self.init()
|
||||
self.load()
|
||||
|
||||
|
@ -1957,8 +1957,9 @@ class BasePreferences(object):
|
|||
"""HTML dialog: edit global preferences"""
|
||||
from app.scodoc import html_sco_header
|
||||
|
||||
context = None # XXX TO REMOVE #context
|
||||
H = [
|
||||
html_sco_header.sco_header(self.context, REQUEST, page_title="Préférences"),
|
||||
html_sco_header.sco_header(page_title="Préférences"),
|
||||
"<h2>Préférences globales pour %s</h2>" % scu.ScoURL(),
|
||||
"""<p class="help">Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.</p>
|
||||
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
||||
|
@ -1973,18 +1974,14 @@ class BasePreferences(object):
|
|||
submitlabel="Enregistrer les modifications",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H) + tf[1] + html_sco_header.sco_footer(self.context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(scu.ScoURL()) # cancel
|
||||
return flask.redirect(scu.ScoURL()) # cancel
|
||||
else:
|
||||
for pref in self.prefs_definition:
|
||||
self.prefs[None][pref[0]] = tf[2][pref[0]]
|
||||
self.save()
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
scu.ScoURL() + "?head_message=Préférences modifiées"
|
||||
)
|
||||
return flask.redirect(scu.ScoURL() + "?head_message=Préférences modifiées")
|
||||
|
||||
def build_tf_form(self, categories=[], formsemestre_id=None):
|
||||
"""Build list of elements for TrivialFormulator.
|
||||
|
@ -2058,10 +2055,9 @@ class BasePreferences(object):
|
|||
class SemPreferences(object):
|
||||
"""Preferences for a formsemestre"""
|
||||
|
||||
def __init__(self, context, formsemestre_id=None):
|
||||
self.context = context
|
||||
def __init__(self, formsemestre_id=None):
|
||||
self.formsemestre_id = formsemestre_id
|
||||
self.base_prefs = get_base_preferences(self.context)
|
||||
self.base_prefs = get_base_preferences()
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.base_prefs.get(self.formsemestre_id, name)
|
||||
|
@ -2091,10 +2087,11 @@ class SemPreferences(object):
|
|||
raise ScoValueError(
|
||||
"sem_preferences.edit doit etre appele sur un semestre !"
|
||||
) # a bug !
|
||||
sem = sco_formsemestre.get_formsemestre(self.context, self.formsemestre_id)
|
||||
context = None # XXX TO REMOVE
|
||||
sem = sco_formsemestre.get_formsemestre(context, self.formsemestre_id)
|
||||
H = [
|
||||
html_sco_header.html_sem_header(
|
||||
self.context, REQUEST, "Préférences du semestre", sem
|
||||
context, REQUEST, "Préférences du semestre", sem
|
||||
),
|
||||
"""
|
||||
<p class="help">Les paramètres définis ici ne s'appliqueront qu'à ce semestre.</p>
|
||||
|
@ -2149,14 +2146,11 @@ function set_global_pref(el, pref_name) {
|
|||
scu.NotesURL()
|
||||
+ "/formsemestre_status?formsemestre_id=%s" % self.formsemestre_id
|
||||
)
|
||||
context = None # XXX TO REMOVE
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H) + tf[1] + html_sco_header.sco_footer(self.context, REQUEST)
|
||||
)
|
||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
dest_url + "&head_message=Annulé"
|
||||
) # cancel
|
||||
return flask.redirect(dest_url + "&head_message=Annulé") # cancel
|
||||
else:
|
||||
# Supprime pref locale du semestre (retour à la valeur globale)
|
||||
if tf[2]["suppress"]:
|
||||
|
@ -2190,19 +2184,17 @@ function set_global_pref(el, pref_name) {
|
|||
# done: change prefs and redirect to semestre status
|
||||
destination = tf[2]["destination"]
|
||||
if destination == "done" or destination == "":
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
dest_url + "&head_message=Préférences modifiées"
|
||||
)
|
||||
return flask.redirect(dest_url + "&head_message=Préférences modifiées")
|
||||
elif destination == "again":
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
REQUEST.URL0 + "?formsemestre_id=" + self.formsemestre_id
|
||||
)
|
||||
elif destination == "global":
|
||||
return REQUEST.RESPONSE.redirect(scu.ScoURL() + "/edit_preferences")
|
||||
return flask.redirect(scu.ScoURL() + "/edit_preferences")
|
||||
|
||||
|
||||
#
|
||||
def doc_preferences(context):
|
||||
def doc_preferences():
|
||||
""" Liste les preferences en MarkDown, pour la documentation"""
|
||||
L = []
|
||||
for cat, cat_descr in PREF_CATEGORIES:
|
||||
|
@ -2211,7 +2203,7 @@ def doc_preferences(context):
|
|||
L.append([""])
|
||||
L.append(["Nom", " ", " "])
|
||||
L.append(["----", "----", "----"])
|
||||
for pref_name, pref in get_base_preferences(context).prefs_definition:
|
||||
for pref_name, pref in get_base_preferences().prefs_definition:
|
||||
if pref["category"] == cat:
|
||||
L.append(
|
||||
["`" + pref_name + "`", pref["title"], pref.get("explanation", "")]
|
||||
|
|
|
@ -40,6 +40,7 @@ from app.scodoc import sco_codes_parcours
|
|||
from app.scodoc import VERSION
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc.sco_excel import ScoExcelSheet
|
||||
|
||||
|
||||
def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
|
@ -59,7 +60,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
prev_ue_acro = {} # ue_code_s : acronyme (à afficher)
|
||||
prev_moy = {} # moyennes gen sem prec
|
||||
moy_ue = scu.DictDefault(defaultvalue={}) # ue_acro : moyennes { etudid : moy ue }
|
||||
ue_acro = {} # ue_code_s : acronyme (à afficher)
|
||||
ue_acro = {} # ue_code_s : acronyme (à afficher)
|
||||
moy = {} # moyennes gen
|
||||
moy_inter = {} # moyenne gen. sur les 2 derniers semestres
|
||||
code = {} # decision existantes s'il y en a
|
||||
|
@ -129,9 +130,9 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
main_partition_id, ""
|
||||
)
|
||||
# absences:
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs[etudid] = nbabs
|
||||
nbabsjust[etudid] = nbabs - nbabsjust
|
||||
e_nbabs, e_nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs[etudid] = e_nbabs
|
||||
nbabsjust[etudid] = e_nbabs - e_nbabsjust
|
||||
|
||||
# Codes des UE "semestre précédent":
|
||||
ue_prev_codes = list(prev_moy_ue.keys())
|
||||
|
@ -153,14 +154,30 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
if prev_moy: # si qq chose dans precedent
|
||||
sp = "S%s" % (sid - 1)
|
||||
|
||||
L = sco_excel.ScoExcelSheet(sheet_name="Prepa Jury %s" % sn)
|
||||
L.append(["Feuille préparation Jury %s" % scu.unescape_html(sem["titreannee"])])
|
||||
L.append([]) # empty line
|
||||
ws = sco_excel.ScoExcelSheet(sheet_name="Prepa Jury %s" % sn)
|
||||
# génération des styles
|
||||
style_bold = sco_excel.excel_make_style(size=10, bold=True)
|
||||
style_center = sco_excel.excel_make_style(halign="center")
|
||||
style_boldcenter = sco_excel.excel_make_style(bold=True, halign="center")
|
||||
style_moy = sco_excel.excel_make_style(
|
||||
bold=True, halign="center", bgcolor=sco_excel.COLORS.LIGHT_YELLOW
|
||||
)
|
||||
style_note = sco_excel.excel_make_style(halign="right", format_number="General")
|
||||
style_note_bold = sco_excel.excel_make_style(
|
||||
halign="right", bold=True, format_number="General"
|
||||
)
|
||||
|
||||
# Première ligne
|
||||
ws.append_single_cell_row(
|
||||
"Feuille préparation Jury %s" % scu.unescape_html(sem["titreannee"]), style_bold
|
||||
)
|
||||
ws.append_blank_row()
|
||||
|
||||
# Ligne de titre
|
||||
titles = ["Rang"]
|
||||
if sco_preferences.get_preference(context, "prepa_jury_nip"):
|
||||
if sco_preferences.get_preference("prepa_jury_nip"):
|
||||
titles.append("NIP")
|
||||
if sco_preferences.get_preference(context, "prepa_jury_ine"):
|
||||
if sco_preferences.get_preference("prepa_jury_ine"):
|
||||
titles.append("INE")
|
||||
titles += [
|
||||
"etudid",
|
||||
|
@ -174,7 +191,6 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
"Parcours",
|
||||
"Groupe",
|
||||
]
|
||||
|
||||
if prev_moy: # si qq chose dans precedent
|
||||
titles += [prev_ue_acro[x][1] for x in ue_prev_codes] + [
|
||||
"Moy %s" % sp,
|
||||
|
@ -189,15 +205,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
if autorisations:
|
||||
titles.append("Autorisations")
|
||||
# titles.append('Assidu')
|
||||
L.append(titles)
|
||||
style_bold = sco_excel.Excel_MakeStyle(bold=True)
|
||||
style_center = sco_excel.Excel_MakeStyle(halign="center")
|
||||
style_boldcenter = sco_excel.Excel_MakeStyle(bold=True, halign="center")
|
||||
style_moy = sco_excel.Excel_MakeStyle(
|
||||
bold=True, halign="center", bgcolor="lightyellow"
|
||||
)
|
||||
style_note = sco_excel.Excel_MakeStyle(halign="right")
|
||||
style_note_bold = sco_excel.Excel_MakeStyle(halign="right", bold=True)
|
||||
ws.append_row(ws.make_row(titles, style_boldcenter))
|
||||
if prev_moy:
|
||||
tit_prev_moy = "Moy " + sp
|
||||
col_prev_moy = titles.index(tit_prev_moy)
|
||||
|
@ -205,9 +213,6 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
col_moy = titles.index(tit_moy)
|
||||
col_abs = titles.index("Abs")
|
||||
|
||||
L.set_style(style_bold, li=0)
|
||||
L.set_style(style_boldcenter, li=2)
|
||||
|
||||
def fmt(x):
|
||||
"reduit les notes a deux chiffres"
|
||||
x = scu.fmt_note(x, keep_numeric=False)
|
||||
|
@ -218,101 +223,100 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
|||
|
||||
i = 1 # numero etudiant
|
||||
for etudid in etudids:
|
||||
cells = []
|
||||
etud = nt.identdict[etudid]
|
||||
l = [str(i)]
|
||||
if sco_preferences.get_preference(context, "prepa_jury_nip"):
|
||||
l.append(etud["code_nip"])
|
||||
if sco_preferences.get_preference(context, "prepa_jury_ine"):
|
||||
l.append(etud["code_ine"])
|
||||
l += [
|
||||
etudid,
|
||||
etud["civilite_str"],
|
||||
sco_etud.format_nom(etud["nom"]),
|
||||
sco_etud.format_prenom(etud["prenom"]),
|
||||
etud["date_naissance"],
|
||||
etud["bac"],
|
||||
etud["specialite"],
|
||||
etud["classement"],
|
||||
parcours[etudid],
|
||||
groupestd[etudid],
|
||||
]
|
||||
co = len(l)
|
||||
cells.append(ws.make_cell(str(i)))
|
||||
if sco_preferences.get_preference("prepa_jury_nip"):
|
||||
cells.append(ws.make_cell(etud["code_nip"]))
|
||||
if sco_preferences.get_preference("prepa_jury_ine"):
|
||||
cells.append(ws.make_cell(["code_ine"]))
|
||||
cells += ws.make_row(
|
||||
[
|
||||
etudid,
|
||||
etud["civilite_str"],
|
||||
sco_etud.format_nom(etud["nom"]),
|
||||
sco_etud.format_prenom(etud["prenom"]),
|
||||
etud["date_naissance"],
|
||||
etud["bac"],
|
||||
etud["specialite"],
|
||||
etud["classement"],
|
||||
parcours[etudid],
|
||||
groupestd[etudid],
|
||||
]
|
||||
)
|
||||
co = len(cells)
|
||||
if prev_moy:
|
||||
for ue_acro in ue_prev_codes:
|
||||
l.append(fmt(prev_moy_ue.get(ue_acro, {}).get(etudid, "")))
|
||||
L.set_style(style_note, li=i + 2, co=co)
|
||||
cells.append(
|
||||
ws.make_cell(
|
||||
fmt(prev_moy_ue.get(ue_acro, {}).get(etudid, "")), style_note
|
||||
)
|
||||
)
|
||||
co += 1
|
||||
l.append(fmt(prev_moy.get(etudid, "")))
|
||||
l.append(prev_code.get(etudid, ""))
|
||||
# L.set_style(style_bold, li=i+2, co=col_prev_moy+1) # moy gen prev
|
||||
# L.set_style(style_moy, li=i+2, co=col_prev_moy+2) # decision prev
|
||||
L.set_style(style_bold, li=i + 2, co=col_prev_moy) # moy gen prev
|
||||
L.set_style(style_moy, li=i + 2, co=col_prev_moy + 1) # decision prev
|
||||
cells.append(
|
||||
ws.make_cell(fmt(prev_moy.get(etudid, "")), style_bold)
|
||||
) # moy gen prev
|
||||
cells.append(
|
||||
ws.make_cell(fmt(prev_code.get(etudid, "")), style_moy)
|
||||
) # decision prev
|
||||
co += 2
|
||||
|
||||
for ue_acro in ue_codes:
|
||||
l.append(fmt(moy_ue.get(ue_acro, {}).get(etudid, "")))
|
||||
L.set_style(style_note, li=i + 2, co=co)
|
||||
cells.append(
|
||||
ws.make_cell(fmt(moy_ue.get(ue_acro, {}).get(etudid, "")), style_note)
|
||||
)
|
||||
co += 1
|
||||
l.append(fmt(moy.get(etudid, "")))
|
||||
# L.set_style(style_note_bold, li=i+2, co=col_moy+1) # moy gen
|
||||
L.set_style(style_note_bold, li=i + 2, co=col_moy) # moy gen
|
||||
cells.append(ws.make_cell(fmt(moy.get(etudid, "")), style_note_bold)) # moy gen
|
||||
co += 1
|
||||
if moy_inter:
|
||||
l.append(fmt(moy_inter.get(etudid, "")))
|
||||
L.set_style(style_note, li=i + 2, co=co)
|
||||
l.append(fmt(str(nbabs.get(etudid, ""))))
|
||||
l.append(fmt(str(nbabsjust.get(etudid, ""))))
|
||||
cells.append(ws.make_cell(fmt(moy_inter.get(etudid, "")), style_note))
|
||||
cells.append(ws.make_cell(str(nbabs.get(etudid, "")), style_center))
|
||||
cells.append(ws.make_cell(str(nbabsjust.get(etudid, "")), style_center))
|
||||
if code:
|
||||
l.append(code.get(etudid, ""))
|
||||
if autorisations:
|
||||
l.append(autorisations.get(etudid, ""))
|
||||
cells.append(ws.make_cell(code.get(etudid, ""), style_moy))
|
||||
cells.append(ws.make_cell(autorisations.get(etudid, ""), style_moy))
|
||||
# l.append(assidu.get(etudid, ''))
|
||||
L.append(l)
|
||||
ws.append_row(cells)
|
||||
i += 1
|
||||
L.set_style(style_center, li=i + 1, co=col_abs) # absences
|
||||
L.set_style(style_center, li=i + 1, co=col_abs + 1) # absences injustifiées
|
||||
L.set_style(style_moy, li=i + 1, co=col_abs + 2) # décision semestre
|
||||
L.set_style(style_center, li=i + 1, co=col_abs + 3) # Autorisations
|
||||
#
|
||||
L.append([""])
|
||||
ws.append_blank_row()
|
||||
# Explications des codes
|
||||
codes = list(sco_codes_parcours.CODES_EXPL.keys())
|
||||
codes.sort()
|
||||
L.append(["Explication des codes"])
|
||||
ws.append_single_cell_row("Explication des codes")
|
||||
for code in codes:
|
||||
L.append(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
|
||||
L.append(
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"ADM+",
|
||||
"indique que le semestre a déjà servi à en compenser un autre",
|
||||
]
|
||||
ws.append_row(
|
||||
ws.make_row(["", "", "", code, sco_codes_parcours.CODES_EXPL[code]])
|
||||
)
|
||||
ws.append_row(
|
||||
ws.make_row(
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"ADM+",
|
||||
"indique que le semestre a déjà servi à en compenser un autre",
|
||||
]
|
||||
)
|
||||
)
|
||||
# UE : Correspondances acronyme et titre complet
|
||||
L.append([""])
|
||||
L.append(["Titre des UE"])
|
||||
ws.append_blank_row()
|
||||
ws.append_single_cell_row("Titre des UE")
|
||||
if prev_moy:
|
||||
for ue in ntp.get_ues(filter_sport=True):
|
||||
L.append(["", "", "", ue["acronyme"], ue["titre"]])
|
||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||
for ue in nt.get_ues(filter_sport=True):
|
||||
L.append(["", "", "", ue["acronyme"], ue["titre"]])
|
||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||
#
|
||||
L.append([""])
|
||||
L.append(
|
||||
[
|
||||
"Préparé par %s le %s sur %s pour %s"
|
||||
% (
|
||||
VERSION.SCONAME,
|
||||
time.strftime("%d/%m/%Y"),
|
||||
REQUEST.BASE0,
|
||||
REQUEST.AUTHENTICATED_USER,
|
||||
)
|
||||
]
|
||||
ws.append_blank_row()
|
||||
ws.append_single_cell_row(
|
||||
"Préparé par %s le %s sur %s pour %s"
|
||||
% (
|
||||
VERSION.SCONAME,
|
||||
time.strftime("%d/%m/%Y"),
|
||||
REQUEST.BASE0,
|
||||
REQUEST.AUTHENTICATED_USER,
|
||||
)
|
||||
)
|
||||
|
||||
xls = L.gen_workbook()
|
||||
|
||||
return sco_excel.sendExcelFile(REQUEST, xls, "PrepaJury%s.xls" % sn)
|
||||
xls = ws.generate_standalone()
|
||||
return sco_excel.send_excel_file(REQUEST, xls, f"PrepaJury{sn}{scu.XLSX_SUFFIX}")
|
||||
|
|
|
@ -51,6 +51,7 @@ from operator import itemgetter
|
|||
from reportlab.platypus import Paragraph
|
||||
from reportlab.lib import styles
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -419,10 +420,10 @@ def pvjury_table(
|
|||
columns_ids += ["prev_decision"]
|
||||
|
||||
columns_ids += ["decision"]
|
||||
if sco_preferences.get_preference(context, "bul_show_mention", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_mention", formsemestre_id):
|
||||
columns_ids += ["mention"]
|
||||
columns_ids += ["ue_cap"]
|
||||
if sco_preferences.get_preference(context, "bul_show_ects", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_ects", formsemestre_id):
|
||||
columns_ids += ["ects"]
|
||||
|
||||
# XXX if not dpv["semestre_non_terminal"]:
|
||||
|
@ -459,13 +460,13 @@ def pvjury_table(
|
|||
if with_paragraph_nom:
|
||||
cell_style = styles.ParagraphStyle({})
|
||||
cell_style.fontSize = sco_preferences.get_preference(
|
||||
context, "SCOLAR_FONT_SIZE", formsemestre_id
|
||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||
)
|
||||
cell_style.fontName = sco_preferences.get_preference(
|
||||
context, "PV_FONTNAME", formsemestre_id
|
||||
"PV_FONTNAME", formsemestre_id
|
||||
)
|
||||
cell_style.leading = 1.0 * sco_preferences.get_preference(
|
||||
context, "SCOLAR_FONT_SIZE", formsemestre_id
|
||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||
) # vertical space
|
||||
i = e["identite"]
|
||||
l["nomprenom"] = [
|
||||
|
@ -510,13 +511,13 @@ def formsemestre_pvjury(
|
|||
"""Page récapitulant les décisions de jury
|
||||
dpv: result of dict_pvjury
|
||||
"""
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
footer = html_sco_header.sco_footer()
|
||||
|
||||
dpv = dict_pvjury(context, formsemestre_id, with_prev=True)
|
||||
if not dpv:
|
||||
if format == "html":
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "<h2>Aucune information disponible !</h2>"
|
||||
+ footer
|
||||
)
|
||||
|
@ -540,7 +541,7 @@ def formsemestre_pvjury(
|
|||
caption="Décisions jury pour " + sem["titreannee"],
|
||||
html_class="table_leftalign",
|
||||
html_sortable=True,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
if format != "html":
|
||||
return tab.make_page(
|
||||
|
@ -602,7 +603,7 @@ def formsemestre_pvjury(
|
|||
columns_ids=("code", "count", "expl"),
|
||||
html_class="table_leftalign",
|
||||
html_sortable=True,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
).html()
|
||||
)
|
||||
H.append("<p></p>") # force space at bottom
|
||||
|
@ -634,7 +635,7 @@ def formsemestre_pvjury_pdf(
|
|||
etuddescr = ""
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(context, formsemestre_id)]
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
|
@ -659,7 +660,7 @@ def formsemestre_pvjury_pdf(
|
|||
F = [
|
||||
"""<p><em>Voir aussi si besoin les réglages sur la page "Paramétrage" (accessible à l'administrateur du département).</em>
|
||||
</p>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
descr = descrform_pvjury(context, sem)
|
||||
if etudid:
|
||||
|
@ -687,7 +688,7 @@ def formsemestre_pvjury_pdf(
|
|||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + "\n".join(F)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_pvjury?formsemestre_id=%s" % (formsemestre_id)
|
||||
)
|
||||
else:
|
||||
|
@ -818,7 +819,7 @@ def formsemestre_lettres_individuelles(
|
|||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if not group_ids:
|
||||
# tous les inscrits du semestre
|
||||
group_ids = [sco_groups.get_default_group(context, formsemestre_id)]
|
||||
group_ids = [sco_groups.get_default_group(formsemestre_id)]
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
|
@ -839,7 +840,7 @@ def formsemestre_lettres_individuelles(
|
|||
"""
|
||||
% formsemestre_id,
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
descr = descrform_lettres_individuelles()
|
||||
menu_choix_groupe = (
|
||||
"""<div class="group_ids_sel_menu">Groupes d'étudiants à lister: """
|
||||
|
@ -861,7 +862,7 @@ def formsemestre_lettres_individuelles(
|
|||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_pvjury?formsemestre_id=%s" % (formsemestre_id)
|
||||
)
|
||||
else:
|
||||
|
@ -881,7 +882,7 @@ def formsemestre_lettres_individuelles(
|
|||
finally:
|
||||
PDFLOCK.release()
|
||||
if not pdfdoc:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id={}&head_message=Aucun%20%C3%A9tudiant%20n%27a%20de%20d%C3%A9cision%20de%20jury".format(
|
||||
formsemestre_id
|
||||
)
|
||||
|
|
|
@ -349,7 +349,7 @@ def pdf_lettres_individuelles(
|
|||
sco_etud.fill_etuds_info(etuds)
|
||||
#
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(context, formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||
params = {
|
||||
"date_jury": date_jury,
|
||||
"date_commission": date_commission,
|
||||
|
@ -358,10 +358,8 @@ def pdf_lettres_individuelles(
|
|||
"htab2": "1cm",
|
||||
}
|
||||
# copie preferences
|
||||
for name in sco_preferences.get_base_preferences(context).prefs_name:
|
||||
params[name] = sco_preferences.get_preference(
|
||||
context, name, sem["formsemestre_id"]
|
||||
)
|
||||
for name in sco_preferences.get_base_preferences().prefs_name:
|
||||
params[name] = sco_preferences.get_preference(name, sem["formsemestre_id"])
|
||||
|
||||
bookmarks = {}
|
||||
objects = [] # list of PLATYPUS objects
|
||||
|
@ -432,9 +430,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
|||
objects = []
|
||||
style = reportlab.lib.styles.ParagraphStyle({})
|
||||
style.fontSize = 14
|
||||
style.fontName = sco_preferences.get_preference(
|
||||
context, "PV_FONTNAME", formsemestre_id
|
||||
)
|
||||
style.fontName = sco_preferences.get_preference("PV_FONTNAME", formsemestre_id)
|
||||
style.leading = 18
|
||||
style.alignment = TA_JUSTIFY
|
||||
|
||||
|
@ -449,7 +445,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
|||
params["decisions_ue_descr_plural"] = ""
|
||||
|
||||
params["INSTITUTION_CITY"] = sco_preferences.get_preference(
|
||||
context, "INSTITUTION_CITY", formsemestre_id
|
||||
"INSTITUTION_CITY", formsemestre_id
|
||||
)
|
||||
if decision["prev_decision_sem"]:
|
||||
params["prev_semestre_id"] = decision["prev"]["semestre_id"]
|
||||
|
@ -517,9 +513,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
|||
# Corps de la lettre:
|
||||
objects += sco_bulletins_pdf.process_field(
|
||||
context,
|
||||
sco_preferences.get_preference(
|
||||
context, "PV_LETTER_TEMPLATE", sem["formsemestre_id"]
|
||||
),
|
||||
sco_preferences.get_preference("PV_LETTER_TEMPLATE", sem["formsemestre_id"]),
|
||||
params,
|
||||
style,
|
||||
suppress_empty_pars=True,
|
||||
|
@ -531,7 +525,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
|||
if Se.semestre_non_terminal:
|
||||
sig = (
|
||||
sco_preferences.get_preference(
|
||||
context, "PV_LETTER_PASSAGE_SIGNATURE", formsemestre_id
|
||||
"PV_LETTER_PASSAGE_SIGNATURE", formsemestre_id
|
||||
)
|
||||
% params
|
||||
)
|
||||
|
@ -548,7 +542,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
|||
else:
|
||||
sig = (
|
||||
sco_preferences.get_preference(
|
||||
context, "PV_LETTER_DIPLOMA_SIGNATURE", formsemestre_id
|
||||
"PV_LETTER_DIPLOMA_SIGNATURE", formsemestre_id
|
||||
)
|
||||
% params
|
||||
)
|
||||
|
@ -592,16 +586,14 @@ def _make_signature_image(signature, leftindent, formsemestre_id, context=None):
|
|||
width, height = im.size
|
||||
pdfheight = (
|
||||
1.0
|
||||
* sco_preferences.get_preference(
|
||||
context, "pv_sig_image_height", formsemestre_id
|
||||
)
|
||||
* sco_preferences.get_preference("pv_sig_image_height", formsemestre_id)
|
||||
* mm
|
||||
)
|
||||
f.seek(0, 0)
|
||||
|
||||
style = styles.ParagraphStyle({})
|
||||
style.leading = 1.0 * sco_preferences.get_preference(
|
||||
context, "SCOLAR_FONT_SIZE", formsemestre_id
|
||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||
) # vertical space
|
||||
style.leftIndent = leftindent
|
||||
return Table(
|
||||
|
@ -681,7 +673,7 @@ def pvjury_pdf(
|
|||
author="%s %s (E. Viennet)" % (VERSION.SCONAME, VERSION.SCOVERSION),
|
||||
title=SU("PV du jury de %s" % sem["titre_num"]),
|
||||
subject="PV jury",
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -719,9 +711,7 @@ def _pvjury_pdf_type(
|
|||
|
||||
style = reportlab.lib.styles.ParagraphStyle({})
|
||||
style.fontSize = 12
|
||||
style.fontName = sco_preferences.get_preference(
|
||||
context, "PV_FONTNAME", formsemestre_id
|
||||
)
|
||||
style.fontName = sco_preferences.get_preference("PV_FONTNAME", formsemestre_id)
|
||||
style.leading = 18
|
||||
style.alignment = TA_JUSTIFY
|
||||
|
||||
|
@ -729,7 +719,7 @@ def _pvjury_pdf_type(
|
|||
bulletStyle = reportlab.lib.styles.ParagraphStyle({})
|
||||
bulletStyle.fontSize = 12
|
||||
bulletStyle.fontName = sco_preferences.get_preference(
|
||||
context, "PV_FONTNAME", formsemestre_id
|
||||
"PV_FONTNAME", formsemestre_id
|
||||
)
|
||||
bulletStyle.leading = 12
|
||||
bulletStyle.alignment = TA_JUSTIFY
|
||||
|
@ -748,7 +738,7 @@ def _pvjury_pdf_type(
|
|||
"""
|
||||
% (
|
||||
titre_jury,
|
||||
sco_preferences.get_preference(context, "DeptName", formsemestre_id),
|
||||
sco_preferences.get_preference("DeptName", formsemestre_id),
|
||||
sem["anneescolaire"],
|
||||
),
|
||||
style,
|
||||
|
@ -766,7 +756,7 @@ def _pvjury_pdf_type(
|
|||
objects += sco_pdf.makeParas(
|
||||
"""<para align="center"><b>Semestre: %s</b></para>""" % sem["titre"], style
|
||||
)
|
||||
if sco_preferences.get_preference(context, "PV_TITLE_WITH_VDI", formsemestre_id):
|
||||
if sco_preferences.get_preference("PV_TITLE_WITH_VDI", formsemestre_id):
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para align="center">VDI et Code: %s</para>""" % (VDICode or ""), style
|
||||
)
|
||||
|
@ -778,13 +768,11 @@ def _pvjury_pdf_type(
|
|||
|
||||
objects += sco_pdf.makeParas(
|
||||
"<para>"
|
||||
+ sco_preferences.get_preference(context, "PV_INTRO", formsemestre_id)
|
||||
+ sco_preferences.get_preference("PV_INTRO", formsemestre_id)
|
||||
% {
|
||||
"Decnum": numeroArrete,
|
||||
"VDICode": VDICode,
|
||||
"UnivName": sco_preferences.get_preference(
|
||||
context, "UnivName", formsemestre_id
|
||||
),
|
||||
"UnivName": sco_preferences.get_preference("UnivName", formsemestre_id),
|
||||
"Type": titre_jury,
|
||||
"Date": date_commission, # deprecated
|
||||
"date_commission": date_commission,
|
||||
|
@ -811,13 +799,11 @@ def _pvjury_pdf_type(
|
|||
# Make a new cell style and put all cells in paragraphs
|
||||
cell_style = styles.ParagraphStyle({})
|
||||
cell_style.fontSize = sco_preferences.get_preference(
|
||||
context, "SCOLAR_FONT_SIZE", formsemestre_id
|
||||
)
|
||||
cell_style.fontName = sco_preferences.get_preference(
|
||||
context, "PV_FONTNAME", formsemestre_id
|
||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||
)
|
||||
cell_style.fontName = sco_preferences.get_preference("PV_FONTNAME", formsemestre_id)
|
||||
cell_style.leading = 1.0 * sco_preferences.get_preference(
|
||||
context, "SCOLAR_FONT_SIZE", formsemestre_id
|
||||
"SCOLAR_FONT_SIZE", formsemestre_id
|
||||
) # vertical space
|
||||
LINEWIDTH = 0.5
|
||||
table_style = [
|
||||
|
@ -825,7 +811,7 @@ def _pvjury_pdf_type(
|
|||
"FONTNAME",
|
||||
(0, 0),
|
||||
(-1, 0),
|
||||
sco_preferences.get_preference(context, "PV_FONTNAME", formsemestre_id),
|
||||
sco_preferences.get_preference("PV_FONTNAME", formsemestre_id),
|
||||
),
|
||||
("LINEBELOW", (0, 0), (-1, 0), LINEWIDTH, Color(0, 0, 0)),
|
||||
("GRID", (0, 0), (-1, -1), LINEWIDTH, Color(0, 0, 0)),
|
||||
|
@ -844,7 +830,7 @@ def _pvjury_pdf_type(
|
|||
widths = [6 * cm, 2.8 * cm, 2.8 * cm, None, None, None, None]
|
||||
if dpv["has_prev"]:
|
||||
widths[2:2] = [2.8 * cm]
|
||||
if sco_preferences.get_preference(context, "bul_show_mention", formsemestre_id):
|
||||
if sco_preferences.get_preference("bul_show_mention", formsemestre_id):
|
||||
widths += [None]
|
||||
objects.append(Table(Pt, repeatRows=1, colWidths=widths, style=table_style))
|
||||
|
||||
|
@ -853,10 +839,8 @@ def _pvjury_pdf_type(
|
|||
"""<para spaceBefore="10mm" align="right">
|
||||
%s, %s</para>"""
|
||||
% (
|
||||
sco_preferences.get_preference(context, "DirectorName", formsemestre_id)
|
||||
or "",
|
||||
sco_preferences.get_preference(context, "DirectorTitle", formsemestre_id)
|
||||
or "",
|
||||
sco_preferences.get_preference("DirectorName", formsemestre_id) or "",
|
||||
sco_preferences.get_preference("DirectorTitle", formsemestre_id) or "",
|
||||
),
|
||||
style,
|
||||
)
|
||||
|
@ -877,7 +861,7 @@ def _pvjury_pdf_type(
|
|||
"FONTNAME",
|
||||
(0, 0),
|
||||
(-1, 0),
|
||||
sco_preferences.get_preference(context, "PV_FONTNAME", formsemestre_id),
|
||||
sco_preferences.get_preference("PV_FONTNAME", formsemestre_id),
|
||||
),
|
||||
("LINEBELOW", (0, 0), (-1, -1), LINEWIDTH, Color(0, 0, 0)),
|
||||
("LINEABOVE", (0, 0), (-1, -1), LINEWIDTH, Color(0, 0, 0)),
|
||||
|
|
|
@ -85,9 +85,7 @@ def formsemestre_recapcomplet(
|
|||
) # cache les colonnes des modules
|
||||
pref_override = int(pref_override)
|
||||
if pref_override:
|
||||
hidebac = int(
|
||||
sco_preferences.get_preference(context, "recap_hidebac", formsemestre_id)
|
||||
)
|
||||
hidebac = int(sco_preferences.get_preference("recap_hidebac", formsemestre_id))
|
||||
else:
|
||||
hidebac = int(hidebac)
|
||||
xml_with_decisions = int(xml_with_decisions)
|
||||
|
@ -97,8 +95,6 @@ def formsemestre_recapcomplet(
|
|||
if not isFile:
|
||||
H += [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Récapitulatif",
|
||||
no_side_bar=True,
|
||||
init_qtip=True,
|
||||
|
@ -175,7 +171,7 @@ def formsemestre_recapcomplet(
|
|||
"""<p><a class="stdlink" href="formsemestre_pvjury?formsemestre_id=%s">Voir les décisions du jury</a></p>"""
|
||||
% formsemestre_id
|
||||
)
|
||||
if sco_permissions_check.can_validate_sem(context, REQUEST, formsemestre_id):
|
||||
if sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||
H.append("<p>")
|
||||
if modejury:
|
||||
H.append(
|
||||
|
@ -188,13 +184,13 @@ def formsemestre_recapcomplet(
|
|||
% formsemestre_id
|
||||
)
|
||||
H.append("</p>")
|
||||
if sco_preferences.get_preference(context, "use_ue_coefs", formsemestre_id):
|
||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
||||
H.append(
|
||||
"""
|
||||
<p class="infop">utilise les coefficients d'UE pour calculer la moyenne générale.</p>
|
||||
"""
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "".join(H) # HTML or binary data...
|
||||
|
||||
|
||||
|
@ -220,7 +216,7 @@ def do_formsemestre_recapcomplet(
|
|||
elif format == "csv":
|
||||
return scu.sendCSVFile(REQUEST, data, filename)
|
||||
elif format[:3] == "xls":
|
||||
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
||||
return sco_excel.send_excel_file(REQUEST, data, filename)
|
||||
elif format == "json":
|
||||
return scu.sendJSON(REQUEST, data)
|
||||
else:
|
||||
|
@ -497,9 +493,7 @@ def make_formsemestre_recapcomplet(
|
|||
if key == "nb_valid_evals":
|
||||
l.append("")
|
||||
elif key == "coef":
|
||||
if sco_preferences.get_preference(
|
||||
context, "use_ue_coefs", formsemestre_id
|
||||
):
|
||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
||||
l.append("%2.3f" % ue["coefficient"])
|
||||
else:
|
||||
l.append("")
|
||||
|
@ -782,15 +776,15 @@ def make_formsemestre_recapcomplet(
|
|||
semname = sem["titre_num"].replace(" ", "_")
|
||||
date = time.strftime("%d-%m-%Y")
|
||||
if format == "xls":
|
||||
filename = "notes_modules-%s-%s.xls" % (semname, date)
|
||||
filename = "notes_modules-%s-%s%s" % (semname, date, scu.XLSX_SUFFIX)
|
||||
else:
|
||||
filename = "notes_modules_evals-%s-%s.xls" % (semname, date)
|
||||
xls = sco_excel.Excel_SimpleTable(
|
||||
filename = "notes_modules_evals-%s-%s%s" % (semname, date, scu.XLSX_SUFFIX)
|
||||
xls = sco_excel.excel_simple_table(
|
||||
titles=["etudid", "code_nip"] + F[0][:-2],
|
||||
lines=[
|
||||
[x[-1], x[-2]] + x[:-2] for x in F[1:]
|
||||
], # reordonne cols (etudid et nip en 1er)
|
||||
SheetName="notes %s %s" % (semname, date),
|
||||
sheet_name="notes %s %s" % (semname, date),
|
||||
)
|
||||
return xls, filename, "xls"
|
||||
else:
|
||||
|
@ -808,9 +802,7 @@ def _list_notes_evals(context, evals, etudid):
|
|||
or e["etat"]["evalattente"]
|
||||
or e["publish_incomplete"]
|
||||
):
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, e["evaluation_id"]
|
||||
)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(e["evaluation_id"])
|
||||
if etudid in NotesDB:
|
||||
val = NotesDB[etudid]["value"]
|
||||
else:
|
||||
|
@ -880,7 +872,7 @@ def _formsemestre_recapcomplet_xml(
|
|||
doc = ElementTree.Element(
|
||||
"recapsemestre", formsemestre_id=formsemestre_id, date=docdate
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(context, formsemestre_id)
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(formsemestre_id)
|
||||
doc.append(
|
||||
ElementTree.Element(
|
||||
"evals_info",
|
||||
|
@ -924,7 +916,7 @@ def _formsemestre_recapcomplet_json(
|
|||
docdate = ""
|
||||
else:
|
||||
docdate = datetime.datetime.now().isoformat()
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(context, formsemestre_id)
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(formsemestre_id)
|
||||
J = {
|
||||
"docdate": docdate,
|
||||
"formsemestre_id": formsemestre_id,
|
||||
|
|
|
@ -38,6 +38,7 @@ import datetime
|
|||
from operator import itemgetter
|
||||
|
||||
from flask import url_for, g
|
||||
import pydot
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc import notesdb as ndb
|
||||
|
@ -201,7 +202,7 @@ def _results_by_category(
|
|||
bottom_titles=bottom_titles,
|
||||
html_col_width="4em",
|
||||
html_sortable=True,
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
|
||||
|
||||
|
@ -364,7 +365,7 @@ def formsemestre_report_counts(
|
|||
if format != "html":
|
||||
return t
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title=title),
|
||||
html_sco_header.sco_header(page_title=title),
|
||||
t,
|
||||
"\n".join(F),
|
||||
"""<p class="help">Le tableau affiche le nombre d'étudiants de ce semestre dans chacun
|
||||
|
@ -372,7 +373,7 @@ def formsemestre_report_counts(
|
|||
pour les lignes et les colonnes. Le <tt>codedecision</tt> est le code de la décision
|
||||
du jury.
|
||||
</p>""",
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -654,7 +655,7 @@ def table_suivi_cohorte(
|
|||
caption="Suivi cohorte " + pp + sem["titreannee"] + dbac,
|
||||
page_title="Suivi cohorte " + sem["titreannee"],
|
||||
html_class="table_cohorte",
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
# Explication: liste des semestres associés à chaque date
|
||||
if not P:
|
||||
|
@ -755,7 +756,7 @@ def formsemestre_suivi_cohorte(
|
|||
)
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(context, REQUEST, page_title=tab.page_title),
|
||||
html_sco_header.sco_header(page_title=tab.page_title),
|
||||
"""<h2 class="formsemestre">Suivi cohorte: devenir des étudiants de ce semestre</h2>""",
|
||||
_gen_form_selectetuds(
|
||||
formsemestre_id,
|
||||
|
@ -776,7 +777,7 @@ def formsemestre_suivi_cohorte(
|
|||
t,
|
||||
help,
|
||||
expl,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -1167,7 +1168,7 @@ def table_suivi_parcours(
|
|||
"nb": len(etuds),
|
||||
"codeparcours": len(etuds),
|
||||
},
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
)
|
||||
return tab
|
||||
|
||||
|
@ -1228,8 +1229,6 @@ def formsemestre_suivi_parcours(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=tab.page_title,
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
|
@ -1237,7 +1236,7 @@ def formsemestre_suivi_parcours(
|
|||
"""<h2 class="formsemestre">Parcours suivis par les étudiants de ce semestre</h2>""",
|
||||
"\n".join(F),
|
||||
t,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
@ -1255,8 +1254,6 @@ def graph_parcours(
|
|||
statut="",
|
||||
):
|
||||
""""""
|
||||
if not scu.WITH_PYDOT:
|
||||
raise ScoValueError("pydot module is not installed")
|
||||
etuds, bacs, bacspecialites, annee_bacs, civilites, statuts = tsp_etud_list(
|
||||
context,
|
||||
formsemestre_id,
|
||||
|
@ -1342,10 +1339,10 @@ def graph_parcours(
|
|||
edges[(s["formsemestre_id"], nid)].add(etudid)
|
||||
diploma_nodes.append(nid)
|
||||
#
|
||||
g = scu.pydot.graph_from_edges(list(edges.keys()))
|
||||
g = scu.graph_from_edges(list(edges.keys()))
|
||||
for fid in isolated_nodes:
|
||||
if not fid in connected_nodes:
|
||||
n = scu.pydot.Node(name=fid)
|
||||
n = pydot.Node(name=fid)
|
||||
g.add_node(n)
|
||||
g.set("rankdir", "LR") # left to right
|
||||
g.set_fontname("Helvetica")
|
||||
|
@ -1353,7 +1350,7 @@ def graph_parcours(
|
|||
g.set_bgcolor("#fffff0") # ou 'transparent'
|
||||
# titres des semestres:
|
||||
for s in sems.values():
|
||||
n = scu.pydot_get_node(g, s["formsemestre_id"])
|
||||
n = g.get_node(s["formsemestre_id"])[0]
|
||||
log("s['formsemestre_id'] = %s" % s["formsemestre_id"])
|
||||
log("n=%s" % n)
|
||||
log("get=%s" % g.get_node(s["formsemestre_id"]))
|
||||
|
@ -1378,31 +1375,31 @@ def graph_parcours(
|
|||
n.set_shape("box")
|
||||
n.set_URL("formsemestre_status?formsemestre_id=" + s["formsemestre_id"])
|
||||
# semestre de depart en vert
|
||||
n = scu.pydot_get_node(g, formsemestre_id)
|
||||
n = g.get_node(formsemestre_id)[0]
|
||||
n.set_color("green")
|
||||
# demissions en rouge, octagonal
|
||||
for nid in dem_nodes.values():
|
||||
n = scu.pydot_get_node(g, nid)
|
||||
n = g.get_node(nid)[0]
|
||||
n.set_color("red")
|
||||
n.set_shape("octagon")
|
||||
n.set("label", "Dem.")
|
||||
|
||||
# NAR en rouge, Mcircle
|
||||
for nid in nar_nodes.values():
|
||||
n = scu.pydot_get_node(g, nid)
|
||||
n = g.get_node(nid)[0]
|
||||
n.set_color("red")
|
||||
n.set_shape("Mcircle")
|
||||
n.set("label", sco_codes_parcours.NAR)
|
||||
# diplomes:
|
||||
for nid in diploma_nodes:
|
||||
n = scu.pydot_get_node(g, nid)
|
||||
n = g.get_node(nid)[0]
|
||||
n.set_color("red")
|
||||
n.set_shape("ellipse")
|
||||
n.set("label", "Diplome") # bug si accent (pas compris pourquoi)
|
||||
# Arètes:
|
||||
bubbles = {} # substitue titres pour bulle aides: src_id:dst_id : etud_descr
|
||||
for (src_id, dst_id) in edges.keys():
|
||||
e = g.get_edge(src_id, dst_id)
|
||||
e = g.get_edge(src_id, dst_id)[0]
|
||||
e.set("arrowhead", "normal")
|
||||
e.set("arrowsize", 1)
|
||||
e.set_label(len(edges[(src_id, dst_id)]))
|
||||
|
@ -1416,7 +1413,7 @@ def graph_parcours(
|
|||
# Genere graphe
|
||||
_, path = tempfile.mkstemp(".gr")
|
||||
g.write(path=path, format=format)
|
||||
data = open(path, "r").read()
|
||||
data = open(path, "rb").read()
|
||||
log("dot generated %d bytes in %s format" % (len(data), format))
|
||||
if not data:
|
||||
log("graph.to_string=%s" % g.to_string())
|
||||
|
@ -1426,7 +1423,8 @@ def graph_parcours(
|
|||
os.unlink(path)
|
||||
if format == "svg":
|
||||
# dot génère un document XML complet, il faut enlever l'en-tête
|
||||
data = "<svg" + "<svg".join(data.split("<svg")[1:])
|
||||
data_str = data.decode("utf-8")
|
||||
data = "<svg" + "<svg".join(data_str.split("<svg")[1:])
|
||||
# Substitution des titres des URL des aretes pour bulles aide
|
||||
def repl(m):
|
||||
return '<a title="%s"' % bubbles[m.group("sd")]
|
||||
|
@ -1528,14 +1526,16 @@ def formsemestre_graph_parcours(
|
|||
REQUEST.RESPONSE.setHeader("content-type", "image/png")
|
||||
return doc
|
||||
elif format == "html":
|
||||
url_kw = {
|
||||
"scodoc_dept": g.scodoc_dept,
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"bac": bac,
|
||||
"specialite": bacspecialite,
|
||||
"civilite": civilite,
|
||||
"statut": statut,
|
||||
}
|
||||
if only_primo:
|
||||
op = "only_primo=on&"
|
||||
else:
|
||||
op = ""
|
||||
url = six.moves.urllib.parse.quote(
|
||||
"formsemestre_graph_parcours?formsemestre_id=%s&%sbac=%s&bacspecialite=%s&civilite=%s&statut=%s&format="
|
||||
% (formsemestre_id, op, bac, bacspecialite, civilite, statut)
|
||||
)
|
||||
url_kw["only_primo"] = "on"
|
||||
(
|
||||
doc,
|
||||
etuds,
|
||||
|
@ -1557,8 +1557,6 @@ def formsemestre_graph_parcours(
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Parcours étudiants de %(titreannee)s" % sem,
|
||||
no_side_bar=True,
|
||||
),
|
||||
|
@ -1583,12 +1581,11 @@ def formsemestre_graph_parcours(
|
|||
),
|
||||
"""<p>Origine et devenir des étudiants inscrits dans %(titreannee)s"""
|
||||
% sem,
|
||||
# En Debian 4, dot ne genere pas du pdf, et epstopdf ne marche pas sur le .ps ou ps2 générés par dot
|
||||
# mais c'est OK en Debian 5
|
||||
"""(<a href="%spdf">version pdf</a>""" % url,
|
||||
""", <a href="%spng">image PNG</a>)""" % url,
|
||||
"""(<a href="%s">version pdf</a>"""
|
||||
% url_for("notes.formsemestre_graph_parcours", format="pdf", **url_kw),
|
||||
""", <a href="%s">image PNG</a>)"""
|
||||
% url_for("notes.formsemestre_graph_parcours", format="png", **url_kw),
|
||||
"""</p>""",
|
||||
"""<p class="help">Cette page ne s'affiche correctement que sur les navigateurs récents.</p>""",
|
||||
"""<p class="help">Le graphe permet de suivre les étudiants inscrits dans le semestre
|
||||
sélectionné (dessiné en vert). Chaque rectangle représente un semestre (cliquez dedans
|
||||
pour afficher son tableau de bord). Les flèches indiquent le nombre d'étudiants passant
|
||||
|
@ -1596,7 +1593,7 @@ def formsemestre_graph_parcours(
|
|||
passant la souris sur le chiffre).
|
||||
</p>"""
|
||||
% MAX_ETUD_IN_DESCR,
|
||||
html_sco_header.sco_footer(context, REQUEST),
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
return "\n".join(H)
|
||||
else:
|
||||
|
|
|
@ -29,10 +29,14 @@
|
|||
|
||||
Formulaire revu en juillet 2016
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
import datetime
|
||||
import psycopg2
|
||||
|
||||
import flask
|
||||
from flask_login import current_user
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -165,18 +169,17 @@ def do_evaluation_upload_xls(context, REQUEST):
|
|||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
comment = REQUEST.form["comment"]
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||
context, moduleimpl_id=E["moduleimpl_id"]
|
||||
)[0]
|
||||
# Check access
|
||||
# (admin, respformation, and responsable_id)
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
||||
# XXX imaginer un redirect + msg erreur
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
||||
#
|
||||
data = REQUEST.form["notefile"].read()
|
||||
diag, lines = sco_excel.Excel_to_list(data)
|
||||
diag, lines = sco_excel.excel_file_to_list(REQUEST.form["notefile"])
|
||||
try:
|
||||
if not lines:
|
||||
raise InvalidNoteValue()
|
||||
|
@ -221,7 +224,7 @@ def do_evaluation_upload_xls(context, REQUEST):
|
|||
ni += 1
|
||||
except:
|
||||
diag.append(
|
||||
'Erreur: feuille invalide ! (erreur ligne %d)<br/>"%s"'
|
||||
'Erreur: Ligne invalide ! (erreur ligne %d)<br/>"%s"'
|
||||
% (ni, str(lines[ni]))
|
||||
)
|
||||
raise InvalidNoteValue()
|
||||
|
@ -243,9 +246,7 @@ def do_evaluation_upload_xls(context, REQUEST):
|
|||
context, authuser, evaluation_id, L, comment
|
||||
)
|
||||
# news
|
||||
E = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(
|
||||
context, moduleimpl_id=E["moduleimpl_id"]
|
||||
)[0]
|
||||
|
@ -255,8 +256,6 @@ def do_evaluation_upload_xls(context, REQUEST):
|
|||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=M["moduleimpl_id"],
|
||||
text='Chargement notes dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||
|
@ -284,25 +283,23 @@ def do_evaluation_upload_xls(context, REQUEST):
|
|||
return 0, msg + "<p>(pas de notes modifiées)</p>"
|
||||
|
||||
|
||||
def do_evaluation_set_missing(
|
||||
context, evaluation_id, value, REQUEST=None, dialog_confirmed=False
|
||||
):
|
||||
def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
||||
"""Initialisation des notes manquantes"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
# ? evaluation_id = REQUEST.form["evaluation_id"]
|
||||
context = None # XXX #context
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||
context, moduleimpl_id=E["moduleimpl_id"]
|
||||
)[0]
|
||||
# Check access
|
||||
# (admin, respformation, and responsable_id)
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
||||
# XXX imaginer un redirect + msg erreur
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % current_user)
|
||||
#
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True, include_dems=False
|
||||
evaluation_id, getallstudents=True, include_dems=False
|
||||
)
|
||||
notes = []
|
||||
for etudid in etudids: # pour tous les inscrits
|
||||
|
@ -315,15 +312,14 @@ def do_evaluation_set_missing(
|
|||
diag = "Valeur %s invalide" % value
|
||||
if diag:
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ '<h2>%s</h2><p><a href="saisie_notes?evaluation_id=%s">Recommencer</a>'
|
||||
% (diag, evaluation_id)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
# Confirm action
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Mettre toutes les notes manquantes de l'évaluation
|
||||
à la valeur %s ?</h2>
|
||||
<p>Seuls les étudiants pour lesquels aucune note (ni valeur, ni ABS, ni EXC)
|
||||
|
@ -333,28 +329,25 @@ def do_evaluation_set_missing(
|
|||
"""
|
||||
% (value, len(L)),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url="saisie_notes?evaluation_id=%s" % evaluation_id,
|
||||
parameters={"evaluation_id": evaluation_id, "value": value},
|
||||
)
|
||||
# ok
|
||||
comment = "Initialisation notes manquantes"
|
||||
nb_changed, _, _ = _notes_add(context, authuser, evaluation_id, L, comment)
|
||||
nb_changed, _, _ = _notes_add(context, current_user, evaluation_id, L, comment)
|
||||
# news
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
|
||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=M["moduleimpl_id"],
|
||||
text='Initialisation notes dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||
url=mod["url"],
|
||||
)
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ """<h2>%d notes changées</h2>
|
||||
<ul>
|
||||
<li><a class="stdlink" href="saisie_notes?evaluation_id=%s">
|
||||
|
@ -364,45 +357,43 @@ def do_evaluation_set_missing(
|
|||
</ul>
|
||||
"""
|
||||
% (nb_changed, evaluation_id, M["moduleimpl_id"])
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
|
||||
def evaluation_suppress_alln(context, evaluation_id, REQUEST, dialog_confirmed=False):
|
||||
def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
||||
"suppress all notes in this eval"
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
context = None # XXX #context
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
|
||||
if sco_permissions_check.can_edit_notes(
|
||||
context, authuser, E["moduleimpl_id"], allow_ens=False
|
||||
current_user, E["moduleimpl_id"], allow_ens=False
|
||||
):
|
||||
# On a le droit de modifier toutes les notes
|
||||
# recupere les etuds ayant une note
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
||||
elif sco_permissions_check.can_edit_notes(
|
||||
context, authuser, E["moduleimpl_id"], allow_ens=True
|
||||
current_user, E["moduleimpl_id"], allow_ens=True
|
||||
):
|
||||
# Enseignant associé au module: ne peut supprimer que les notes qu'il a saisi
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, evaluation_id, by_uid=str(authuser)
|
||||
evaluation_id, by_uid=current_user.user_name
|
||||
)
|
||||
else:
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % current_user)
|
||||
|
||||
notes = [(etudid, scu.NOTES_SUPPRESS) for etudid in NotesDB.keys()]
|
||||
|
||||
if not dialog_confirmed:
|
||||
nb_changed, nb_suppress, existing_decisions = _notes_add(
|
||||
context, authuser, evaluation_id, notes, do_it=False
|
||||
context, current_user, evaluation_id, notes, do_it=False
|
||||
)
|
||||
msg = "<p>Confirmer la suppression des %d notes ?</p>" % nb_suppress
|
||||
if existing_decisions:
|
||||
msg += """<p class="warning">Important: il y a déjà des décisions de jury enregistrées, qui seront potentiellement à revoir suite à cette modification !</p>"""
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
msg,
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
OK="Supprimer les notes",
|
||||
cancel_url="moduleimpl_status?moduleimpl_id=%s" % E["moduleimpl_id"],
|
||||
parameters={"evaluation_id": evaluation_id},
|
||||
|
@ -410,7 +401,7 @@ def evaluation_suppress_alln(context, evaluation_id, REQUEST, dialog_confirmed=F
|
|||
|
||||
# modif
|
||||
nb_changed, nb_suppress, existing_decisions = _notes_add(
|
||||
context, authuser, evaluation_id, notes, comment="effacer tout"
|
||||
context, current_user, evaluation_id, notes, comment="effacer tout"
|
||||
)
|
||||
assert nb_changed == nb_suppress
|
||||
H = ["<p>%s notes supprimées</p>" % nb_suppress]
|
||||
|
@ -428,8 +419,6 @@ def evaluation_suppress_alln(context, evaluation_id, REQUEST, dialog_confirmed=F
|
|||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=M["moduleimpl_id"],
|
||||
text='Suppression des notes d\'une évaluation dans <a href="%(url)s">%(titre)s</a>'
|
||||
|
@ -437,11 +426,7 @@ def evaluation_suppress_alln(context, evaluation_id, REQUEST, dialog_confirmed=F
|
|||
url=mod["url"],
|
||||
)
|
||||
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
+ "\n".join(H)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
)
|
||||
return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def _notes_add(context, uid, evaluation_id, notes, comment=None, do_it=True):
|
||||
|
@ -461,7 +446,7 @@ def _notes_add(context, uid, evaluation_id, notes, comment=None, do_it=True):
|
|||
# Verifie inscription et valeur note
|
||||
_ = {}.fromkeys(
|
||||
sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True, include_dems=True
|
||||
evaluation_id, getallstudents=True, include_dems=True
|
||||
)
|
||||
)
|
||||
for (etudid, value) in notes:
|
||||
|
@ -470,13 +455,13 @@ def _notes_add(context, uid, evaluation_id, notes, comment=None, do_it=True):
|
|||
"etudiant %s: valeur de note invalide (%s)" % (etudid, value)
|
||||
)
|
||||
# Recherche notes existantes
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
||||
# Met a jour la base
|
||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
nb_changed = 0
|
||||
nb_suppress = 0
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
existing_decisions = (
|
||||
[]
|
||||
|
@ -578,24 +563,22 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
"""Saisie des notes via un fichier Excel"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
authusername = str(authuser)
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not evals:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
E = evals[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "<h2>Modification des notes impossible pour %s</h2>" % authusername
|
||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||
avez l'autorisation d'effectuer cette opération)</p>
|
||||
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
||||
"""
|
||||
% E["moduleimpl_id"]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
if E["description"]:
|
||||
|
@ -615,15 +598,13 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=page_title,
|
||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||
cssstyles=sco_groups_view.CSSSTYLES,
|
||||
init_qtip=True,
|
||||
),
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
),
|
||||
"""<span class="eval_title">Saisie des notes par fichier</span>""",
|
||||
]
|
||||
|
@ -648,7 +629,7 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
|
||||
H.append(
|
||||
"""<div class="saisienote_etape2">
|
||||
<span class="titredivsaisienote">Etape 2 : chargement d'un fichier de notes</span>""" #'
|
||||
<span class="titredivsaisienote">Etape 2 : chargement d'un fichier de notes</span>""" # '
|
||||
)
|
||||
|
||||
nf = TrivialFormulator(
|
||||
|
@ -706,12 +687,12 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
#
|
||||
H.append("""</div><h3>Autres opérations</h3><ul>""")
|
||||
if sco_permissions_check.can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
):
|
||||
H.append(
|
||||
"""
|
||||
<li>
|
||||
<form action="do_evaluation_set_missing" method="get">
|
||||
<form action="do_evaluation_set_missing" method="GET">
|
||||
Mettre toutes les notes manquantes à <input type="text" size="5" name="value"/>
|
||||
<input type="submit" value="OK"/>
|
||||
<input type="hidden" name="evaluation_id" value="%s"/>
|
||||
|
@ -721,7 +702,7 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
<li><a class="stdlink" href="evaluation_suppress_alln?evaluation_id=%s">Effacer toutes les notes de cette évaluation</a> (ceci permet ensuite de supprimer l'évaluation si besoin)
|
||||
</li>"""
|
||||
% (evaluation_id, evaluation_id)
|
||||
) #'
|
||||
) # '
|
||||
H.append(
|
||||
"""<li><a class="stdlink" href="moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s">Revenir au module</a></li>
|
||||
<li><a class="stdlink" href="saisie_notes?evaluation_id=%(evaluation_id)s">Revenir au formulaire de saisie</a></li>
|
||||
|
@ -750,15 +731,13 @@ def saisie_notes_tableur(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
</ol>
|
||||
"""
|
||||
)
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def feuille_saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
||||
"""Document Excel pour saisie notes dans l'évaluation et les groupes indiqués"""
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not evals:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
E = evals[0]
|
||||
|
@ -801,7 +780,7 @@ def feuille_saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
else:
|
||||
getallstudents = False
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, groups, getallstudents=getallstudents, include_dems=True
|
||||
evaluation_id, groups, getallstudents=getallstudents, include_dems=True
|
||||
)
|
||||
|
||||
# une liste de liste de chaines: lignes de la feuille de calcul
|
||||
|
@ -825,9 +804,9 @@ def feuille_saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
]
|
||||
)
|
||||
|
||||
filename = "notes_%s_%s.xls" % (evalname, gr_title_filename)
|
||||
xls = sco_excel.Excel_feuille_saisie(E, sem["titreannee"], description, lines=L)
|
||||
return sco_excel.sendExcelFile(REQUEST, xls, filename)
|
||||
filename = "notes_%s_%s.xlsx" % (evalname, gr_title_filename)
|
||||
xls = sco_excel.excel_feuille_saisie(E, sem["titreannee"], description, lines=L)
|
||||
return sco_excel.send_excel_file(REQUEST, xls, filename)
|
||||
|
||||
|
||||
def has_existing_decision(context, M, E, etudid):
|
||||
|
@ -859,9 +838,7 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
authusername = str(authuser)
|
||||
|
||||
evals = sco_evaluations.do_evaluation_list(
|
||||
context, {"evaluation_id": evaluation_id}
|
||||
)
|
||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not evals:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
E = evals[0]
|
||||
|
@ -871,16 +848,16 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
formsemestre_id = M["formsemestre_id"]
|
||||
# Check access
|
||||
# (admin, respformation, and responsable_id)
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
html_sco_header.sco_header()
|
||||
+ "<h2>Modification des notes impossible pour %s</h2>" % authusername
|
||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||
avez l'autorisation d'effectuer cette opération)</p>
|
||||
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
||||
"""
|
||||
% E["moduleimpl_id"]
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
# Informations sur les groupes à afficher:
|
||||
|
@ -901,15 +878,13 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
# HTML page:
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=page_title,
|
||||
javascripts=sco_groups_view.JAVASCRIPTS + ["js/saisie_notes.js"],
|
||||
cssstyles=sco_groups_view.CSSSTYLES,
|
||||
init_qtip=True,
|
||||
),
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
),
|
||||
'<div id="saisie_notes"><span class="eval_title">Saisie des notes</span>',
|
||||
]
|
||||
|
@ -954,7 +929,7 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
context, E, M, groups_infos.group_ids, destination=destination, REQUEST=REQUEST
|
||||
)
|
||||
if form is None:
|
||||
return REQUEST.RESPONSE.redirect(destination)
|
||||
return flask.redirect(destination)
|
||||
H.append(form)
|
||||
#
|
||||
H.append("</div>") # /saisie_notes
|
||||
|
@ -972,14 +947,14 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
|||
</div>"""
|
||||
)
|
||||
|
||||
H.append(html_sco_header.sco_footer(context, REQUEST))
|
||||
H.append(html_sco_header.sco_footer())
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def _get_sorted_etuds(context, E, etudids, formsemestre_id):
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, E["evaluation_id"]
|
||||
E["evaluation_id"]
|
||||
) # Notes existantes
|
||||
cnx = ndb.GetDBConnexion()
|
||||
etuds = []
|
||||
|
@ -1053,7 +1028,7 @@ def _form_saisie_notes(context, E, M, group_ids, destination="", REQUEST=None):
|
|||
formsemestre_id = M["formsemestre_id"]
|
||||
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True, include_dems=True
|
||||
evaluation_id, getallstudents=True, include_dems=True
|
||||
)
|
||||
if not etudids:
|
||||
return '<div class="ue_warning"><span>Aucun étudiant sélectionné !</span></div>'
|
||||
|
@ -1200,7 +1175,7 @@ def _form_saisie_notes(context, E, M, group_ids, destination="", REQUEST=None):
|
|||
H.append(
|
||||
"""
|
||||
<div>
|
||||
<form action="do_evaluation_set_missing" method="get">
|
||||
<form action="do_evaluation_set_missing" method="GET">
|
||||
Mettre <em>toutes</em> les notes manquantes à <input type="text" size="5" name="value"/>
|
||||
<input type="submit" value="OK"/>
|
||||
<input type="hidden" name="evaluation_id" value="%s"/>
|
||||
|
@ -1227,13 +1202,13 @@ def save_note(
|
|||
"save_note: evaluation_id=%s etudid=%s uid=%s value=%s"
|
||||
% (evaluation_id, etudid, authuser, value)
|
||||
)
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
Mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
|
||||
Mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % M
|
||||
result = {"nbchanged": 0} # JSON
|
||||
# Check access: admin, respformation, or responsable_id
|
||||
if not sco_permissions_check.can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
||||
result["status"] = "unauthorized"
|
||||
else:
|
||||
L, _, _, _, _ = _check_notes([(etudid, value)], E, Mod)
|
||||
|
@ -1242,8 +1217,6 @@ def save_note(
|
|||
context, authuser, evaluation_id, L, comment=comment, do_it=True
|
||||
)
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_NOTE,
|
||||
object=M["moduleimpl_id"],
|
||||
text='Chargement notes dans <a href="%(url)s">%(titre)s</a>' % Mod,
|
||||
|
|
|
@ -39,6 +39,8 @@ sem_set_list(context)
|
|||
|
||||
"""
|
||||
|
||||
import flask
|
||||
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_etape_apogee
|
||||
|
@ -86,7 +88,6 @@ class SemSet(dict):
|
|||
self["annee_scolaire"] = L[0]["annee_scolaire"]
|
||||
self["sem_id"] = L[0]["sem_id"]
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT formsemestre_id FROM notes_semset_formsemestre WHERE semset_id = %(semset_id)s",
|
||||
{"semset_id": semset_id},
|
||||
)
|
||||
|
@ -136,9 +137,9 @@ class SemSet(dict):
|
|||
self["semlinks"] = [(pattern % sem) for sem in self.sems]
|
||||
self["semtitles_str"] = "<br/>".join(self["semlinks"])
|
||||
|
||||
def fill_formsemestres(self, REQUEST):
|
||||
def fill_formsemestres(self):
|
||||
for sem in self.sems:
|
||||
sco_formsemestre_status.fill_formsemestre(self.context, sem, REQUEST)
|
||||
sco_formsemestre_status.fill_formsemestre(sem)
|
||||
ets = sco_etape_apogee.apo_get_sem_etapes(self.context, sem)
|
||||
sem["etapes_apo_str"] = sco_formsemestre.etapes_apo_str(sorted(list(ets)))
|
||||
|
||||
|
@ -354,7 +355,7 @@ def do_semset_create(context, title="", annee_scolaire=None, sem_id=None, REQUES
|
|||
% (title, annee_scolaire, sem_id)
|
||||
)
|
||||
SemSet(context, title=title, annee_scolaire=annee_scolaire, sem_id=sem_id)
|
||||
return REQUEST.RESPONSE.redirect("semset_page")
|
||||
return flask.redirect("semset_page")
|
||||
|
||||
|
||||
def do_semset_delete(context, semset_id, dialog_confirmed=False, REQUEST=None):
|
||||
|
@ -364,15 +365,13 @@ def do_semset_delete(context, semset_id, dialog_confirmed=False, REQUEST=None):
|
|||
s = SemSet(context, semset_id=semset_id)
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"<h2>Suppression de l'ensemble %(title)s ?</h2>" % s,
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
parameters={"semset_id": semset_id},
|
||||
cancel_url="semset_page",
|
||||
)
|
||||
s.delete()
|
||||
return REQUEST.RESPONSE.redirect("semset_page")
|
||||
return flask.redirect("semset_page")
|
||||
|
||||
|
||||
def edit_semset_set_title(context, id=None, value=None, REQUEST=None):
|
||||
|
@ -396,7 +395,7 @@ def do_semset_add_sem(context, semset_id, formsemestre_id, REQUEST=None):
|
|||
|
||||
s.add(formsemestre_id)
|
||||
|
||||
return REQUEST.RESPONSE.redirect("apo_semset_maq_status?semset_id=%s" % semset_id)
|
||||
return flask.redirect("apo_semset_maq_status?semset_id=%s" % semset_id)
|
||||
|
||||
|
||||
def do_semset_remove_sem(context, semset_id, formsemestre_id, REQUEST=None):
|
||||
|
@ -407,7 +406,7 @@ def do_semset_remove_sem(context, semset_id, formsemestre_id, REQUEST=None):
|
|||
|
||||
s.remove(formsemestre_id)
|
||||
|
||||
return REQUEST.RESPONSE.redirect("apo_semset_maq_status?semset_id=%s" % semset_id)
|
||||
return flask.redirect("apo_semset_maq_status?semset_id=%s" % semset_id)
|
||||
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -460,9 +459,7 @@ def semset_page(context, format="html", REQUEST=None):
|
|||
html_sortable=True,
|
||||
html_class="table_leftalign",
|
||||
filename="semsets",
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
if format != "html":
|
||||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||
|
@ -470,8 +467,6 @@ def semset_page(context, format="html", REQUEST=None):
|
|||
page_title = "Ensembles de semestres"
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title=page_title,
|
||||
init_qtip=True,
|
||||
javascripts=["libjs/jinplace-1.2.1.min.js"],
|
||||
|
@ -484,7 +479,7 @@ def semset_page(context, format="html", REQUEST=None):
|
|||
]
|
||||
H.append(tab.html())
|
||||
|
||||
annee_courante = int(scu.AnneeScolaire(REQUEST))
|
||||
annee_courante = int(scu.AnneeScolaire())
|
||||
menu_annee = "\n".join(
|
||||
[
|
||||
'<option value="%s">%s</option>' % (i, i)
|
||||
|
@ -530,4 +525,4 @@ def semset_page(context, format="html", REQUEST=None):
|
|||
"""
|
||||
)
|
||||
|
||||
return "\n".join(H) + html_sco_header.sco_footer(context, REQUEST)
|
||||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
|
|
@ -107,10 +107,8 @@ def formsemestre_synchro_etuds(
|
|||
"""
|
||||
% sem
|
||||
)
|
||||
header = html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Synchronisation étudiants"
|
||||
)
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
header = html_sco_header.sco_header(page_title="Synchronisation étudiants")
|
||||
footer = html_sco_header.sco_footer()
|
||||
base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
||||
if anneeapogee:
|
||||
base_url += "&anneeapogee=%s" % anneeapogee
|
||||
|
@ -145,7 +143,7 @@ def formsemestre_synchro_etuds(
|
|||
base_url=base_url,
|
||||
read_only=read_only,
|
||||
)
|
||||
return sco_excel.sendExcelFile(REQUEST, xls, filename + ".xls")
|
||||
return sco_excel.send_excel_file(REQUEST, xls, filename + scu.XLSX_SUFFIX)
|
||||
|
||||
H = [header]
|
||||
if not submitted:
|
||||
|
@ -210,13 +208,11 @@ def formsemestre_synchro_etuds(
|
|||
|
||||
H.append(
|
||||
scu.confirm_dialog(
|
||||
context,
|
||||
dest_url="formsemestre_synchro_etuds",
|
||||
add_headers=False,
|
||||
cancel_url="formsemestre_synchro_etuds?formsemestre_id="
|
||||
+ formsemestre_id,
|
||||
OK="Effectuer l'opération",
|
||||
REQUEST=REQUEST,
|
||||
parameters={
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"etuds": ",".join(etuds),
|
||||
|
@ -522,9 +518,7 @@ def list_all(context, etudsapo_set):
|
|||
|
||||
|
||||
def formsemestre_synchro_etuds_help(context, sem):
|
||||
sem["default_group_id"] = sco_groups.get_default_group(
|
||||
context, sem["formsemestre_id"]
|
||||
)
|
||||
sem["default_group_id"] = sco_groups.get_default_group(sem["formsemestre_id"])
|
||||
return (
|
||||
"""<div class="pas_help pas_help_left"><h3><a name="help">Explications</a></h3>
|
||||
<p>Cette page permet d'importer dans le semestre destination
|
||||
|
@ -676,8 +670,6 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES
|
|||
raise
|
||||
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=sco_news.NEWS_INSCR,
|
||||
text="Import Apogée de %d étudiants en " % len(created_etudids),
|
||||
object=sem["formsemestre_id"],
|
||||
|
@ -701,7 +693,7 @@ def do_import_etud_admission(
|
|||
"codelycee": get_opt_str(etud, "lycee"),
|
||||
"boursier": get_opt_str(etud, "bourse"),
|
||||
}
|
||||
log("do_import_etud_admission: etud=%s" % pprint.pformat(etud))
|
||||
# log("do_import_etud_admission: etud=%s" % pprint.pformat(etud))
|
||||
al = sco_etud.admission_list(cnx, args={"etudid": etudid})
|
||||
if not al:
|
||||
sco_etud.admission_create(cnx, args) # -> adm_id
|
||||
|
|
|
@ -73,7 +73,6 @@ class ScoTag(object):
|
|||
if not self.title:
|
||||
raise ScoValueError("invalid empty tag")
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM " + self.tag_table + " WHERE title = %(title)s",
|
||||
{"title": self.title},
|
||||
)
|
||||
|
@ -81,13 +80,12 @@ class ScoTag(object):
|
|||
self.tag_id = r[0]["tag_id"]
|
||||
else:
|
||||
# Create new tag:
|
||||
log("creating new tag: %s" % self.title)
|
||||
# log("creating new tag: %s" % self.title)
|
||||
cnx = ndb.GetDBConnexion()
|
||||
oid = ndb.DBInsertDict(
|
||||
cnx, self.tag_table, {"title": self.title}, commit=True
|
||||
)
|
||||
self.tag_id = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT tag_id FROM " + self.tag_table + " WHERE oid=%(oid)s",
|
||||
{"oid": oid},
|
||||
)[0]["tag_id"]
|
||||
|
@ -123,7 +121,7 @@ class ScoTag(object):
|
|||
args,
|
||||
)
|
||||
if not r:
|
||||
log("tag %s with %s" % (object_id, self.title))
|
||||
# log("tag %s with %s" % (object_id, self.title))
|
||||
cnx = ndb.GetDBConnexion()
|
||||
ndb.DBInsertDict(cnx, self.assoc_table, args, commit=True)
|
||||
|
||||
|
@ -132,7 +130,7 @@ class ScoTag(object):
|
|||
If no more modules tagged with this tag, delete it.
|
||||
Return True if Tag still exists.
|
||||
"""
|
||||
log("removing tag %s from %s" % (self.title, object_id))
|
||||
# log("removing tag %s from %s" % (self.title, object_id))
|
||||
args = {"object_id": object_id, "tag_id": self.tag_id}
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
|
@ -206,7 +204,6 @@ def module_tag_search(context, term, REQUEST=None):
|
|||
data = []
|
||||
else:
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT title FROM notes_tags WHERE title LIKE %(term)s",
|
||||
{"term": term + "%"},
|
||||
)
|
||||
|
@ -218,7 +215,6 @@ def module_tag_search(context, term, REQUEST=None):
|
|||
def module_tag_list(context, module_id=""):
|
||||
"""les noms de tags associés à ce module"""
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT t.title
|
||||
FROM notes_modules_tags mt, notes_tags t
|
||||
WHERE mt.tag_id = t.tag_id
|
||||
|
@ -229,26 +225,17 @@ def module_tag_list(context, module_id=""):
|
|||
return [x["title"] for x in r]
|
||||
|
||||
|
||||
def module_tag_set(context, module_id="", taglist=[], REQUEST=None):
|
||||
def module_tag_set(context, module_id="", taglist=None):
|
||||
"""taglist may either be:
|
||||
a string with tag names separated by commas ("un;deux")
|
||||
or a list of strings (["un", "deux"])
|
||||
"""
|
||||
# We check permission here to allow old Admins (with only ScoChangeFormation perm)
|
||||
if REQUEST: # called from Web
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
tag_editable = authuser.has_permission(
|
||||
Permission.ScoEditFormationTags
|
||||
) or authuser.has_permission(Permission.ScoChangeFormation)
|
||||
if not tag_editable:
|
||||
raise AccessDenied("Modification des tags impossible pour %s" % authuser)
|
||||
#
|
||||
if not taglist:
|
||||
taglist = []
|
||||
elif isinstance(taglist, str):
|
||||
taglist = taglist.split(",")
|
||||
taglist = [t.strip() for t in taglist]
|
||||
log("module_tag_set: module_id=%s taglist=%s" % (module_id, taglist))
|
||||
# log("module_tag_set: module_id=%s taglist=%s" % (module_id, taglist))
|
||||
# Sanity check:
|
||||
Mod = sco_edit_module.do_module_list(context, args={"module_id": module_id})
|
||||
if not Mod:
|
||||
|
|
|
@ -28,10 +28,7 @@
|
|||
"""Photos: trombinoscopes
|
||||
"""
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
import io
|
||||
from zipfile import ZipFile, BadZipfile
|
||||
import reportlab
|
||||
from reportlab.lib.units import cm, mm
|
||||
|
@ -46,6 +43,7 @@ from reportlab.lib.colors import Color
|
|||
from reportlab.lib import colors
|
||||
from PIL import Image as PILImage
|
||||
|
||||
import flask
|
||||
from flask import url_for, g
|
||||
|
||||
from app.scodoc.notes_log import log
|
||||
|
@ -100,11 +98,11 @@ def trombino(
|
|||
return _listeappel_photos_pdf(context, groups_infos, REQUEST)
|
||||
else:
|
||||
raise Exception("invalid format")
|
||||
# return _trombino_html_header(context, REQUEST) + trombino_html(context, group, members, REQUEST=REQUEST) + html_sco_header.sco_footer(context, REQUEST)
|
||||
# return _trombino_html_header(context, REQUEST) + trombino_html(context, group, members, REQUEST=REQUEST) + html_sco_header.sco_footer( REQUEST)
|
||||
|
||||
|
||||
def _trombino_html_header(context, REQUEST):
|
||||
return html_sco_header.sco_header(context, REQUEST, javascripts=["js/trombino.js"])
|
||||
return html_sco_header.sco_header(javascripts=["js/trombino.js"])
|
||||
|
||||
|
||||
def trombino_html(context, groups_infos, REQUEST=None):
|
||||
|
@ -204,7 +202,6 @@ def check_local_photos_availability(context, groups_infos, REQUEST, format=""):
|
|||
return (
|
||||
False,
|
||||
scu.confirm_dialog(
|
||||
context,
|
||||
"""<p>Attention: %d photos ne sont pas disponibles et ne peuvent pas être exportées.</p><p>Vous pouvez <a class="stdlink" href="%s">exporter seulement les photos existantes</a>"""
|
||||
% (
|
||||
nb_missing,
|
||||
|
@ -214,7 +211,6 @@ def check_local_photos_availability(context, groups_infos, REQUEST, format=""):
|
|||
OK="Exporter seulement les photos existantes",
|
||||
cancel_url="groups_view?curtab=tab-photos&"
|
||||
+ groups_infos.groups_query_args,
|
||||
REQUEST=REQUEST,
|
||||
parameters=parameters,
|
||||
),
|
||||
)
|
||||
|
@ -224,7 +220,7 @@ def check_local_photos_availability(context, groups_infos, REQUEST, format=""):
|
|||
|
||||
def _trombino_zip(context, groups_infos, REQUEST):
|
||||
"Send photos as zip archive"
|
||||
data = StringIO()
|
||||
data = io.BytesIO()
|
||||
Z = ZipFile(data, "w")
|
||||
# assume we have the photos (or the user acknowledged the fact)
|
||||
# Archive originals (not reduced) images, in JPEG
|
||||
|
@ -232,7 +228,7 @@ def _trombino_zip(context, groups_infos, REQUEST):
|
|||
im_path = sco_photos.photo_pathname(context, t, size="orig")
|
||||
if not im_path:
|
||||
continue
|
||||
img = open(im_path).read()
|
||||
img = open(im_path, "rb").read()
|
||||
code_nip = t["code_nip"]
|
||||
if code_nip:
|
||||
filename = code_nip + ".jpg"
|
||||
|
@ -260,10 +256,8 @@ def trombino_copy_photos(context, group_ids=[], REQUEST=None, dialog_confirmed=F
|
|||
back_url = "groups_view?%s&curtab=tab-photos" % groups_infos.groups_query_args
|
||||
|
||||
portal_url = sco_portal_apogee.get_portal_url(context)
|
||||
header = html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Chargement des photos"
|
||||
)
|
||||
footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
header = html_sco_header.sco_header(page_title="Chargement des photos")
|
||||
footer = html_sco_header.sco_footer()
|
||||
if not portal_url:
|
||||
return (
|
||||
header
|
||||
|
@ -273,14 +267,12 @@ def trombino_copy_photos(context, group_ids=[], REQUEST=None, dialog_confirmed=F
|
|||
)
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
context,
|
||||
"""<h2>Copier les photos du portail vers ScoDoc ?</h2>
|
||||
<p>Les photos du groupe %s présentes dans ScoDoc seront remplacées par celles du portail (si elles existent).</p>
|
||||
<p>(les photos sont normalement automatiquement copiées lors de leur première utilisation, l'usage de cette fonction n'est nécessaire que si les photos du portail ont été modifiées)</p>
|
||||
"""
|
||||
% (groups_infos.groups_titles),
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url=back_url,
|
||||
parameters={"group_ids": group_ids},
|
||||
)
|
||||
|
@ -340,7 +332,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
|
|||
N_PER_ROW = 5 # XXX should be in ScoDoc preferences
|
||||
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
report = io.BytesIO() # in-memory document, no disk file
|
||||
objects = [
|
||||
Paragraph(
|
||||
SU("Trombinoscope " + sem["titreannee"] + " " + groups_infos.groups_titles),
|
||||
|
@ -394,7 +386,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
|
|||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
preferences=sco_preferences.SemPreferences(context, sem["formsemestre_id"]),
|
||||
preferences=sco_preferences.SemPreferences(sem["formsemestre_id"]),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
@ -414,7 +406,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
|||
# ROWS_PER_PAGE = 26 # XXX should be in ScoDoc preferences
|
||||
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
report = io.BytesIO() # in-memory document, no disk file
|
||||
objects = [
|
||||
Paragraph(
|
||||
SU(
|
||||
|
@ -471,7 +463,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
|||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
context,
|
||||
preferences=sco_preferences.SemPreferences(context, sem["formsemestre_id"]),
|
||||
preferences=sco_preferences.SemPreferences(sem["formsemestre_id"]),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
@ -499,7 +491,7 @@ def photos_generate_excel_sample(context, group_ids=[], REQUEST=None):
|
|||
extra_cols=["fichier_photo"],
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
return sco_excel.sendExcelFile(REQUEST, data, "ImportPhotos.xls")
|
||||
return sco_excel.send_excel_file(REQUEST, data, "ImportPhotos" + scu.XLSX_SUFFIX)
|
||||
|
||||
|
||||
def photos_import_files_form(context, group_ids=[], REQUEST=None):
|
||||
|
@ -510,9 +502,7 @@ def photos_import_files_form(context, group_ids=[], REQUEST=None):
|
|||
back_url = "groups_view?%s&curtab=tab-photos" % groups_infos.groups_query_args
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context, REQUEST, page_title="Import des photos des étudiants"
|
||||
),
|
||||
html_sco_header.sco_header(page_title="Import des photos des étudiants"),
|
||||
"""<h2 class="formsemestre">Téléchargement des photos des étudiants</h2>
|
||||
<p><b>Vous pouvez aussi charger les photos individuellement via la fiche de chaque étudiant (menu "Etudiant" / "Changer la photo").</b></p>
|
||||
<p class="help">Cette page permet de charger en une seule fois les photos de plusieurs étudiants.<br/>
|
||||
|
@ -530,7 +520,7 @@ def photos_import_files_form(context, group_ids=[], REQUEST=None):
|
|||
"""
|
||||
% groups_infos.groups_query_args,
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
REQUEST.form["group_ids"] = groups_infos.group_ids
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
|
@ -545,7 +535,7 @@ def photos_import_files_form(context, group_ids=[], REQUEST=None):
|
|||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + "</li></ol>" + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(back_url)
|
||||
return flask.redirect(back_url)
|
||||
else:
|
||||
return photos_import_files(
|
||||
context,
|
||||
|
@ -573,7 +563,7 @@ def photos_import_files(
|
|||
zip_excel_import_files(
|
||||
context, xlsfile, zipfile, REQUEST, callback, filename_title, page_title
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(back_url + "&head_message=photos%20 importees")
|
||||
return flask.redirect(back_url + "&head_message=photos%20 importees")
|
||||
|
||||
|
||||
def zip_excel_import_files(
|
||||
|
|
|
@ -30,10 +30,7 @@
|
|||
Modification Jérome Billoue,Vincent Grimaud, IUT de Tours, 2017
|
||||
"""
|
||||
|
||||
try:
|
||||
from io import StringIO # for Python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO # for Python 2
|
||||
import io
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib import pagesizes
|
||||
|
@ -68,10 +65,10 @@ def pdf_trombino_tours(
|
|||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
|
||||
DeptName = sco_preferences.get_preference(context, "DeptName")
|
||||
DeptFullName = sco_preferences.get_preference(context, "DeptFullName")
|
||||
UnivName = sco_preferences.get_preference(context, "UnivName")
|
||||
InstituteName = sco_preferences.get_preference(context, "InstituteName")
|
||||
DeptName = sco_preferences.get_preference("DeptName")
|
||||
DeptFullName = sco_preferences.get_preference("DeptFullName")
|
||||
UnivName = sco_preferences.get_preference("UnivName")
|
||||
InstituteName = sco_preferences.get_preference("InstituteName")
|
||||
# Generate PDF page
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
objects = []
|
||||
|
@ -268,16 +265,14 @@ def pdf_trombino_tours(
|
|||
# Réduit sur une page
|
||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||
# Build document
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
report = io.BytesIO() # in-memory document, no disk file
|
||||
filename = "trombino-%s-%s.pdf" % (DeptName, groups_infos.groups_filename)
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
@ -297,10 +292,10 @@ def pdf_feuille_releve_absences(
|
|||
):
|
||||
"""Generation de la feuille d'absence en fichier PDF, avec photos"""
|
||||
|
||||
NB_CELL_AM = sco_preferences.get_preference(context, "feuille_releve_abs_AM")
|
||||
NB_CELL_PM = sco_preferences.get_preference(context, "feuille_releve_abs_PM")
|
||||
NB_CELL_AM = sco_preferences.get_preference("feuille_releve_abs_AM")
|
||||
NB_CELL_PM = sco_preferences.get_preference("feuille_releve_abs_PM")
|
||||
COLWIDTH = 0.85 * cm
|
||||
if sco_preferences.get_preference(context, "feuille_releve_abs_samedi"):
|
||||
if sco_preferences.get_preference("feuille_releve_abs_samedi"):
|
||||
days = sco_abs.DAYNAMES[:6] # Lundi, ..., Samedi
|
||||
else:
|
||||
days = sco_abs.DAYNAMES[:5] # Lundi, ..., Vendredi
|
||||
|
@ -311,10 +306,10 @@ def pdf_feuille_releve_absences(
|
|||
context, group_ids, formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||
)
|
||||
|
||||
DeptName = sco_preferences.get_preference(context, "DeptName")
|
||||
DeptFullName = sco_preferences.get_preference(context, "DeptFullName")
|
||||
UnivName = sco_preferences.get_preference(context, "UnivName")
|
||||
InstituteName = sco_preferences.get_preference(context, "InstituteName")
|
||||
DeptName = sco_preferences.get_preference("DeptName")
|
||||
DeptFullName = sco_preferences.get_preference("DeptFullName")
|
||||
UnivName = sco_preferences.get_preference("UnivName")
|
||||
InstituteName = sco_preferences.get_preference("InstituteName")
|
||||
# Generate PDF page
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
objects = [
|
||||
|
@ -459,16 +454,13 @@ def pdf_feuille_releve_absences(
|
|||
# Réduit sur une page
|
||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||
# Build document
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
report = io.BytesIO() # in-memory document, no disk file
|
||||
filename = "absences-%s-%s.pdf" % (DeptName, groups_infos.groups_filename)
|
||||
if sco_preferences.get_preference(context, "feuille_releve_abs_taille") == "A3":
|
||||
if sco_preferences.get_preference("feuille_releve_abs_taille") == "A3":
|
||||
taille = A3
|
||||
elif sco_preferences.get_preference(context, "feuille_releve_abs_taille") == "A4":
|
||||
elif sco_preferences.get_preference("feuille_releve_abs_taille") == "A4":
|
||||
taille = A4
|
||||
if (
|
||||
sco_preferences.get_preference(context, "feuille_releve_abs_format")
|
||||
== "Paysage"
|
||||
):
|
||||
if sco_preferences.get_preference("feuille_releve_abs_format") == "Paysage":
|
||||
document = BaseDocTemplate(report, pagesize=landscape(taille))
|
||||
else:
|
||||
document = BaseDocTemplate(report, pagesize=taille)
|
||||
|
@ -476,9 +468,7 @@ def pdf_feuille_releve_absences(
|
|||
ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
preferences=sco_preferences.SemPreferences(
|
||||
context,
|
||||
),
|
||||
preferences=sco_preferences.SemPreferences(),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
|
|
|
@ -53,6 +53,7 @@ Solution proposée (nov 2014):
|
|||
- seront aussi présentées (à part) sur la page "Voir les inscriptions aux modules"
|
||||
|
||||
"""
|
||||
import flask
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -108,11 +109,10 @@ def external_ue_create(
|
|||
"ects": ects,
|
||||
"is_external": 1,
|
||||
},
|
||||
REQUEST,
|
||||
)
|
||||
|
||||
matiere_id = sco_edit_matiere.do_matiere_create(
|
||||
context, {"ue_id": ue_id, "titre": titre or acronyme, "numero": 1}, REQUEST
|
||||
context, {"ue_id": ue_id, "titre": titre or acronyme, "numero": 1}
|
||||
)
|
||||
|
||||
module_id = sco_edit_module.do_module_create(
|
||||
|
@ -126,7 +126,6 @@ def external_ue_create(
|
|||
"formation_id": formation_id,
|
||||
"semestre_id": sem["semestre_id"],
|
||||
},
|
||||
REQUEST,
|
||||
)
|
||||
|
||||
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(
|
||||
|
@ -152,19 +151,21 @@ def external_ue_inscrit_et_note(
|
|||
)
|
||||
# Inscription des étudiants
|
||||
sco_moduleimpl.do_moduleimpl_inscrit_etuds(
|
||||
context, moduleimpl_id, formsemestre_id, list(notes_etuds.keys()), REQUEST=REQUEST
|
||||
context,
|
||||
moduleimpl_id,
|
||||
formsemestre_id,
|
||||
list(notes_etuds.keys()),
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
|
||||
# Création d'une évaluation si il n'y en a pas déjà:
|
||||
ModEvals = sco_evaluations.do_evaluation_list(
|
||||
context, args={"moduleimpl_id": moduleimpl_id}
|
||||
)
|
||||
ModEvals = sco_evaluations.do_evaluation_list(args={"moduleimpl_id": moduleimpl_id})
|
||||
if len(ModEvals):
|
||||
# met la note dans le première évaluation existante:
|
||||
evaluation_id = ModEvals[0]["evaluation_id"]
|
||||
else:
|
||||
# crée une évaluation:
|
||||
evaluation_id = sco_evaluations.do_evaluation_create(context,
|
||||
evaluation_id = sco_evaluations.do_evaluation_create(
|
||||
REQUEST=REQUEST,
|
||||
moduleimpl_id=moduleimpl_id,
|
||||
note_max=20.0,
|
||||
|
@ -194,7 +195,6 @@ def get_existing_external_ue(context, formation_id):
|
|||
def get_external_moduleimpl_id(context, formsemestre_id, ue_id):
|
||||
"moduleimpl correspondant à l'UE externe indiquée de ce formsemestre"
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""
|
||||
SELECT moduleimpl_id FROM notes_moduleimpl mi, notes_modules mo
|
||||
WHERE mi.formsemestre_id = %(formsemestre_id)s
|
||||
|
@ -246,7 +246,7 @@ def external_ue_create_form(context, formsemestre_id, etudid, REQUEST=None):
|
|||
</p>
|
||||
""",
|
||||
]
|
||||
html_footer = html_sco_header.sco_footer(context, REQUEST)
|
||||
html_footer = html_sco_header.sco_footer()
|
||||
Fo = sco_formations.formation_list(
|
||||
context, args={"formation_id": sem["formation_id"]}
|
||||
)[0]
|
||||
|
@ -342,7 +342,7 @@ def external_ue_create_form(context, formsemestre_id, etudid, REQUEST=None):
|
|||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + html_footer
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(bull_url)
|
||||
return flask.redirect(bull_url)
|
||||
else:
|
||||
note = tf[2]["note"].strip().upper()
|
||||
note_value, invalid = sco_saisie_notes.convert_note_from_string(note, 20.0)
|
||||
|
@ -384,4 +384,4 @@ def external_ue_create_form(context, formsemestre_id, etudid, REQUEST=None):
|
|||
{etudid: note_value},
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(bull_url + "&head_message=Ajout%20effectué")
|
||||
return flask.redirect(bull_url + "&head_message=Ajout%20effectué")
|
||||
|
|
|
@ -104,12 +104,12 @@ def list_operations(context, evaluation_id):
|
|||
"""returns list of NotesOperation for this evaluation"""
|
||||
notes = list(
|
||||
sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, evaluation_id, filter_suppressed=False
|
||||
evaluation_id, filter_suppressed=False
|
||||
).values()
|
||||
)
|
||||
notes_log = list(
|
||||
sco_evaluations.do_evaluation_get_all_notes(
|
||||
context, evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||
).values()
|
||||
)
|
||||
dt = OPERATION_DATE_TOLERANCE
|
||||
|
@ -146,7 +146,7 @@ def list_operations(context, evaluation_id):
|
|||
|
||||
def evaluation_list_operations(context, REQUEST, evaluation_id):
|
||||
"""Page listing operations on evaluation"""
|
||||
E = sco_evaluations.do_evaluation_list(context, {"evaluation_id": evaluation_id})[0]
|
||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
|
||||
Ops = list_operations(context, evaluation_id)
|
||||
|
@ -165,7 +165,7 @@ def evaluation_list_operations(context, REQUEST, evaluation_id):
|
|||
html_sortable=False,
|
||||
html_title="<h2>Opérations sur l'évaluation %s du %s</h2>"
|
||||
% (E["description"], E["jour"]),
|
||||
preferences=sco_preferences.SemPreferences(context, M["formsemestre_id"]),
|
||||
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
|
||||
)
|
||||
return tab.make_page(context, REQUEST=REQUEST)
|
||||
|
||||
|
@ -176,7 +176,6 @@ def formsemestre_list_saisies_notes(
|
|||
"""Table listant toutes les operations de saisies de notes, dans toutes les evaluations du semestre."""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""select i.nom, n.*, mod.titre, e.description, e.jour from notes_notes n, notes_evaluation e, notes_moduleimpl m, notes_modules mod, identite i where m.moduleimpl_id = e.moduleimpl_id and m.module_id = mod.module_id and e.evaluation_id=n.evaluation_id and i.etudid=n.etudid and m.formsemestre_id=%(formsemestre_id)s order by date desc""",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
)
|
||||
|
@ -208,7 +207,7 @@ def formsemestre_list_saisies_notes(
|
|||
html_class="table_leftalign table_coldate",
|
||||
html_sortable=True,
|
||||
caption="Saisies de notes dans %s" % sem["titreannee"],
|
||||
preferences=sco_preferences.SemPreferences(context, formsemestre_id),
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
)
|
||||
|
|
|
@ -87,21 +87,16 @@ def index_html(context, REQUEST, all_depts=False, with_inactives=False, format="
|
|||
with_inactives = int(with_inactives)
|
||||
|
||||
H = [html_sco_header.html_sem_header(context, REQUEST, "Gestion des utilisateurs")]
|
||||
H.append("<h2>Gestion des utilisateurs</h2>")
|
||||
|
||||
if current_user.has_permission(Permission.ScoUsersAdmin, g.scodoc_dept):
|
||||
H.append(
|
||||
'<p><a href="{}" class="stdlink">Ajouter un utilisateur</a>'.format(
|
||||
url_for("users.create_user_form", scodoc_dept=g.scodoc_dept).encode(
|
||||
scu.SCO_ENCODING
|
||||
) # sco8
|
||||
url_for("users.create_user_form", scodoc_dept=g.scodoc_dept)
|
||||
)
|
||||
)
|
||||
H.append(
|
||||
' <a href="{}" class="stdlink">Importer des utilisateurs</a></p>'.format(
|
||||
url_for("users.import_users_form", scodoc_dept=g.scodoc_dept).encode(
|
||||
scu.SCO_ENCODING
|
||||
) # sco8
|
||||
url_for("users.import_users_form", scodoc_dept=g.scodoc_dept)
|
||||
)
|
||||
)
|
||||
if all_depts:
|
||||
|
@ -133,7 +128,7 @@ def index_html(context, REQUEST, all_depts=False, with_inactives=False, format="
|
|||
return L
|
||||
H.append(L)
|
||||
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
return "\n".join(H) + F
|
||||
|
||||
|
||||
|
@ -151,7 +146,7 @@ def list_users(
|
|||
|
||||
if dept and not all_depts:
|
||||
users = get_user_list(dept=dept, with_inactives=with_inactives)
|
||||
comm = "dept. %s" % dept.encode(scu.SCO_ENCODING) # sco8
|
||||
comm = "dept. %s" % dept
|
||||
else:
|
||||
users = get_user_list(with_inactives=with_inactives)
|
||||
comm = "tous"
|
||||
|
@ -170,9 +165,7 @@ def list_users(
|
|||
if with_links and can_modify:
|
||||
target = url_for(
|
||||
"users.user_info_page", scodoc_dept=dept, user_name=u.user_name
|
||||
).encode(
|
||||
scu.SCO_ENCODING
|
||||
) # sco8
|
||||
)
|
||||
d["_user_name_target"] = target
|
||||
d["_nom_target"] = target
|
||||
d["_prenom_target"] = target
|
||||
|
@ -305,12 +298,10 @@ def user_info_page(context, user_name=None, REQUEST=None):
|
|||
raise ScoValueError("invalid user_name")
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
context,
|
||||
REQUEST,
|
||||
page_title="Utilisateur %s" % user.user_name.encode("utf-8"), # sco8
|
||||
page_title="Utilisateur %s" % user.user_name,
|
||||
)
|
||||
]
|
||||
F = html_sco_header.sco_footer(context, REQUEST)
|
||||
F = html_sco_header.sco_footer()
|
||||
H.append("<h2>Utilisateur: %s" % user.user_name)
|
||||
info = user.to_dict()
|
||||
if info:
|
||||
|
|
|
@ -36,6 +36,7 @@ import json
|
|||
from hashlib import md5
|
||||
import numbers
|
||||
import os
|
||||
import pydot
|
||||
import re
|
||||
import six
|
||||
import six.moves._thread
|
||||
|
@ -51,7 +52,7 @@ STRING_TYPES = six.string_types
|
|||
|
||||
from PIL import Image as PILImage
|
||||
|
||||
from flask import g, url_for
|
||||
from flask import g, url_for, request
|
||||
|
||||
from scodoc_manager import sco_mgr
|
||||
|
||||
|
@ -300,6 +301,8 @@ CSV_FIELDSEP = ";"
|
|||
CSV_LINESEP = "\n"
|
||||
CSV_MIMETYPE = "text/comma-separated-values"
|
||||
XLS_MIMETYPE = "application/vnd.ms-excel"
|
||||
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
XLSX_SUFFIX = ".xlsx"
|
||||
PDF_MIMETYPE = "application/pdf"
|
||||
XML_MIMETYPE = "text/xml"
|
||||
JSON_MIMETYPE = "application/json"
|
||||
|
@ -321,8 +324,8 @@ def get_dept_id():
|
|||
raise sco_exceptions.ScoInvalidDept("département invalide: %s" % g.scodoc_dept)
|
||||
|
||||
|
||||
def get_db_cnx_string():
|
||||
return "dbname=SCO" + g.scodoc_dept
|
||||
def get_db_cnx_string(scodoc_dept=None):
|
||||
return "dbname=SCO" + (scodoc_dept or g.scodoc_dept)
|
||||
|
||||
|
||||
def ScoURL():
|
||||
|
@ -372,15 +375,6 @@ def UsersURL():
|
|||
return url_for("users.index_html", scodoc_dept=g.scodoc_dept)[: -len("/index_html")]
|
||||
|
||||
|
||||
def get_current_user_name(REQUEST):
|
||||
"""return a displayable string identifying the current user.
|
||||
XXX For now, the login, but will be the name. #sco8
|
||||
"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
uid = str(authuser)
|
||||
return uid
|
||||
|
||||
|
||||
# ---- Simple python utilities
|
||||
|
||||
|
||||
|
@ -673,39 +667,27 @@ def sem_decale_str(sem):
|
|||
return ""
|
||||
|
||||
|
||||
# Graphes (optionnel pour ne pas accroitre les dependances de ScoDoc)
|
||||
try:
|
||||
import pydot
|
||||
|
||||
WITH_PYDOT = True
|
||||
except:
|
||||
WITH_PYDOT = False
|
||||
|
||||
if WITH_PYDOT:
|
||||
# check API (incompatible change after pydot version 0.9.10: scodoc install may use old or new version)
|
||||
junk_graph = pydot.Dot("junk")
|
||||
junk_graph.add_node(pydot.Node("a"))
|
||||
n = junk_graph.get_node("a")
|
||||
if type(n) == type([]): # "modern" pydot
|
||||
|
||||
def pydot_get_node(g, name):
|
||||
r = g.get_node(name)
|
||||
if not r:
|
||||
return r
|
||||
else:
|
||||
return r[0]
|
||||
|
||||
else: # very old pydot
|
||||
|
||||
def pydot_get_node(g, name):
|
||||
return g.get_node(name)
|
||||
|
||||
|
||||
def is_valid_mail(email):
|
||||
"""True if well-formed email address"""
|
||||
return re.match(r"^.+@.+\..{2,3}$", email)
|
||||
|
||||
|
||||
def graph_from_edges(edges, graph_name="mygraph"):
|
||||
"""Crée un graph pydot
|
||||
à partir d'une liste d'arêtes [ (n1, n2), (n2, n3), ... ]
|
||||
où n1, n2, ... sont des chaînes donnant l'id des nœuds.
|
||||
|
||||
Fonction remplaçant celle de pydot qui est buggée.
|
||||
"""
|
||||
nodes = set([it for tup in edges for it in tup])
|
||||
graph = pydot.Dot(graph_name)
|
||||
for n in nodes:
|
||||
graph.add_node(pydot.Node(n))
|
||||
for e in edges:
|
||||
graph.add_edge(pydot.Edge(src=e[0], dst=e[1]))
|
||||
return graph
|
||||
|
||||
|
||||
ICONSIZES = {} # name : (width, height) cache image sizes
|
||||
|
||||
|
||||
|
@ -782,16 +764,16 @@ def query_portal(req, msg="Portail Apogee", timeout=3):
|
|||
return data
|
||||
|
||||
|
||||
def AnneeScolaire(REQUEST=None): # TODO remplacer REQUEST #sco8
|
||||
def AnneeScolaire(sco_year=None):
|
||||
"annee de debut de l'annee scolaire courante"
|
||||
if REQUEST and "sco_year" in REQUEST.form:
|
||||
year = REQUEST.form["sco_year"]
|
||||
if sco_year:
|
||||
year = sco_year
|
||||
try:
|
||||
year = int(year)
|
||||
if year > 1900 and year < 2999:
|
||||
return year
|
||||
except:
|
||||
pass
|
||||
raise sco_exceptions.ScoValueError("invalid sco_year")
|
||||
t = time.localtime()
|
||||
year, month = t[0], t[1]
|
||||
if month < 8: # le "pivot" est le 1er aout
|
||||
|
@ -799,7 +781,7 @@ def AnneeScolaire(REQUEST=None): # TODO remplacer REQUEST #sco8
|
|||
return year
|
||||
|
||||
|
||||
def log_unknown_etud(context, REQUEST=None, format="html"):
|
||||
def log_unknown_etud(REQUEST=None, format="html"):
|
||||
"""Log request: cas ou getEtudInfo n'a pas ramene de resultat"""
|
||||
etudid = REQUEST.form.get("etudid", "?")
|
||||
code_nip = REQUEST.form.get("code_nip", "?")
|
||||
|
@ -808,13 +790,11 @@ def log_unknown_etud(context, REQUEST=None, format="html"):
|
|||
"unknown student: etudid=%s code_nip=%s code_ine=%s"
|
||||
% (etudid, code_nip, code_ine)
|
||||
)
|
||||
return _sco_error_response(
|
||||
context, "unknown student", format=format, REQUEST=REQUEST
|
||||
)
|
||||
return _sco_error_response("unknown student", format=format, REQUEST=REQUEST)
|
||||
|
||||
|
||||
# XXX #sco8 à tester ou ré-écrire
|
||||
def _sco_error_response(context, msg, format="html", REQUEST=None):
|
||||
def _sco_error_response(msg, format="html", REQUEST=None):
|
||||
"""Send an error message to the client, in html or xml format."""
|
||||
REQUEST.RESPONSE.setStatus(404, reason=msg)
|
||||
if format == "html" or format == "pdf":
|
||||
|
@ -841,7 +821,6 @@ def return_text_if_published(val, REQUEST):
|
|||
|
||||
|
||||
def confirm_dialog(
|
||||
context,
|
||||
message="<p>Confirmer ?</p>",
|
||||
OK="OK",
|
||||
Cancel="Annuler",
|
||||
|
@ -850,7 +829,6 @@ def confirm_dialog(
|
|||
target_variable="dialog_confirmed",
|
||||
parameters={},
|
||||
add_headers=True, # complete page
|
||||
REQUEST=None, # required
|
||||
helpmsg=None,
|
||||
):
|
||||
from app.scodoc import html_sco_header
|
||||
|
@ -860,7 +838,7 @@ def confirm_dialog(
|
|||
# Attention: la page a pu etre servie en GET avec des parametres
|
||||
# si on laisse l'url "action" vide, les parametres restent alors que l'on passe en POST...
|
||||
if not dest_url:
|
||||
dest_url = REQUEST.URL
|
||||
dest_url = request.base_url
|
||||
# strip remaining parameters from destination url:
|
||||
dest_url = six.moves.urllib.parse.splitquery(dest_url)[0]
|
||||
H = [
|
||||
|
@ -888,11 +866,9 @@ def confirm_dialog(
|
|||
H.append("</form>")
|
||||
if helpmsg:
|
||||
H.append('<p class="help">' + helpmsg + "</p>")
|
||||
if add_headers and REQUEST:
|
||||
if add_headers:
|
||||
return (
|
||||
html_sco_header.sco_header(context, REQUEST)
|
||||
+ "\n".join(H)
|
||||
+ html_sco_header.sco_footer(context, REQUEST)
|
||||
html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
|
||||
)
|
||||
else:
|
||||
return "\n".join(H)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
from xml.etree import ElementTree
|
||||
import xml.sax.saxutils
|
||||
from xml.dom import minidom
|
||||
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
|
@ -44,7 +45,7 @@ def quote_xml_attr(data):
|
|||
|
||||
|
||||
# ScoDoc7 legacy function:
|
||||
def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
||||
def simple_dictlist2xml(dictlist, tagname=None, quote=False, pretty=True):
|
||||
"""Represent a dict as XML data.
|
||||
All keys with string or numeric values are attributes (numbers converted to strings).
|
||||
All list values converted to list of childs (recursively).
|
||||
|
@ -64,9 +65,21 @@ def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
|||
if not tagname:
|
||||
raise ValueError("invalid empty tagname !")
|
||||
elements = _dictlist2xml(dictlist, root=[], tagname=tagname, quote=quote)
|
||||
return XML_HEADER + b"\n".join([ElementTree.tostring(x) for x in elements]).decode(
|
||||
ans = XML_HEADER + b"\n".join([ElementTree.tostring(x) for x in elements]).decode(
|
||||
scu.SCO_ENCODING
|
||||
)
|
||||
if pretty:
|
||||
# solution peu satisfaisante car on doit reparser le XML
|
||||
# de plus, on encode/decode pour avoir le tag <?xml version="1.0" encoding="utf-8"?>
|
||||
try:
|
||||
ans = (
|
||||
minidom.parseString(ans)
|
||||
.toprettyxml(indent="\t", encoding="utf-8")
|
||||
.decode("utf-8")
|
||||
)
|
||||
except xml.parsers.expat.ExpatError:
|
||||
pass
|
||||
return ans
|
||||
|
||||
|
||||
def _dictlist2xml(dictlist, root=None, tagname=None, quote=False):
|
||||
|
|
|
@ -28,23 +28,21 @@
|
|||
"""Logging des opérations en base de données
|
||||
"""
|
||||
|
||||
from flask import request
|
||||
from flask_login import current_user
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import retreive_request
|
||||
|
||||
|
||||
def logdb(REQUEST=None, cnx=None, method=None, etudid=None, msg=None, commit=True):
|
||||
def logdb(cnx=None, method=None, etudid=None, msg=None, commit=True):
|
||||
"Add entry"
|
||||
if not cnx:
|
||||
raise ValueError("logdb: cnx is None")
|
||||
if not REQUEST:
|
||||
REQUEST = retreive_request(skip=1)
|
||||
if REQUEST:
|
||||
args = {
|
||||
"authenticated_user": str(REQUEST.AUTHENTICATED_USER),
|
||||
"remote_addr": REQUEST.REMOTE_ADDR,
|
||||
}
|
||||
else:
|
||||
args = {"authenticated_user": None, "remote_addr": None}
|
||||
|
||||
args = {
|
||||
"authenticated_user": current_user.user_name,
|
||||
"remote_addr": request.remote_addr,
|
||||
}
|
||||
|
||||
args.update({"method": method, "etudid": etudid, "msg": msg})
|
||||
ndb.quote_dict(args)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{% extends 'base.html' %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
|
||||
<h2>Erreur !</h2>
|
||||
|
||||
<p>{{ exc }}</p>
|
||||
|
||||
<p>
|
||||
{% if g.scodoc_dept %}
|
||||
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
|
||||
{% else %}
|
||||
<a href="{{ exc.dest_url or url_for('scodoc.index') }}">continuer</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
|
@ -20,12 +20,14 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<form action="table_etud_in_accessible_depts" method="POST">
|
||||
<b>Chercher étudiant:</b>
|
||||
<input type="text" name="expnom" width="12" spellcheck="false" value="">
|
||||
<input type="submit" value="Chercher">
|
||||
<br />(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<div style="margin-top: 1cm; font-size: 120%;">
|
||||
<p><a href="/ScoDoc/static/mobile">Version mobile (expérimentale, à vos risques et périls)</a></p>
|
||||
|
|
|
@ -41,14 +41,22 @@ def import_scodoc7_user_db(scodoc7_db="dbname=SCOUSERS"):
|
|||
)
|
||||
# Set roles:
|
||||
# ScoDoc7 roles are stored as 'AdminRT,EnsRT'
|
||||
for role_dept in u7["roles"].split(","):
|
||||
m = re.match(r"^([A-Za-z0-9]+?)([A-Z][A-Za-z0-9]*?)$", role_dept)
|
||||
if u7["roles"]:
|
||||
roles7 = u7["roles"].split(",")
|
||||
else:
|
||||
roles7 = []
|
||||
for role_dept in roles7:
|
||||
m = re.match(r"^-?([A-Za-z0-9]+?)([A-Z][A-Za-z0-9]*?)$", role_dept)
|
||||
if not m:
|
||||
current_app.logger.warning(
|
||||
"User {}: ignoring role {}".format(u7["user_name"], role_dept)
|
||||
)
|
||||
else:
|
||||
role_name = m.group(1)
|
||||
if role_name.startswith("-"):
|
||||
# disabled users in ScoDoc7
|
||||
role_name = role_name[1:]
|
||||
assert not u.active
|
||||
dept = m.group(2)
|
||||
role = Role.query.filter_by(name=role_name).first()
|
||||
if not role:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue