forked from ScoDoc/ScoDoc
Compare commits
125 Commits
master
...
dyn_fields
Author | SHA1 | Date | |
---|---|---|---|
53aea89560 | |||
671ef6a7fa | |||
edc6da3005 | |||
b015cf3f88 | |||
a2c16207cb | |||
1aa39c72fd | |||
00dbd25b42 | |||
4e59b9597b | |||
f1660e12e1 | |||
cb03cc962c | |||
81df68b491 | |||
bd6e3e6648 | |||
cd06a780d5 | |||
1741e75f72 | |||
c41726c4a8 | |||
7879c176dd | |||
75f43bbdde | |||
3f86d9b380 | |||
37303df74c | |||
0a50edc9f0 | |||
373feece76 | |||
e4c9e5f9e8 | |||
1af6f79da9 | |||
6d1ffb122b | |||
92c401f17c | |||
36c7358eed | |||
9c5408f503 | |||
2add3e12cc | |||
d0ab9dc66a | |||
beeca54a94 | |||
73cf9a6f4d | |||
fede1ae7af | |||
845152afdd | |||
a4d091fa2d | |||
ffa7e07cd3 | |||
865192bc0d | |||
b56f205e89 | |||
eded2fffe9 | |||
13f1539282 | |||
ae51e4c17a | |||
7214627994 | |||
6cc1b60da4 | |||
4297d36dad | |||
2999199b19 | |||
f516ccdfe7 | |||
2c97349acf | |||
5dfc64a62d | |||
9dd8198c7b | |||
b05aea95b6 | |||
f18a9c7559 | |||
985c6df3b6 | |||
286e9cdc2f | |||
0381576750 | |||
7a0a04bdb3 | |||
35f23995aa | |||
29221666a4 | |||
d7e6a7d714 | |||
179be1baa0 | |||
a5ed9b815f | |||
b552588c1c | |||
13c027fc19 | |||
2dbc1ca695 | |||
9383a53569 | |||
31505e1330 | |||
0621cb1d0f | |||
9a9dc4a483 | |||
11ba73d264 | |||
7daa49f2aa | |||
f7961a135a | |||
c955870e1e | |||
80f5536de5 | |||
2519d08e40 | |||
987800c30e | |||
ae1feba96c | |||
2a72fb881b | |||
87ecd09f0e | |||
6e7a104fb0 | |||
b03eee12a1 | |||
44117fb0e2 | |||
42ef9f795f | |||
bd2e0ccde5 | |||
5f0f437f2e | |||
b6cc251c94 | |||
5f6c434497 | |||
45352d9248 | |||
b3225e07f7 | |||
0ef822cfd8 | |||
a23ae38014 | |||
7d59b52018 | |||
80238545f3 | |||
72e075530c | |||
91cc421ef8 | |||
8b6a569a31 | |||
c8949e870f | |||
30481e4729 | |||
085aff657a | |||
3666f8b1ec | |||
bec7deb581 | |||
6dbbcde454 | |||
9578c789dc | |||
0fedb7771c | |||
6dba8933c4 | |||
5efc493542 | |||
a34dd656be | |||
2ec2be4234 | |||
49609fa657 | |||
8a16216d4b | |||
96f457260f | |||
0f9b52bc9b | |||
83174f2f5e | |||
3fbda90a2f | |||
de206674d9 | |||
b06f37b18e | |||
3496cc7beb | |||
01c264c3c7 | |||
c44aa808df | |||
c8872bd220 | |||
7f63ab222b | |||
ed07e42222 | |||
35768e9241 | |||
050e54de3e | |||
37484b7fc9 | |||
f828134ea2 | |||
a4d0205cc7 | |||
770ccb4d6e |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -170,3 +170,4 @@ Thumbs.db
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
|
|
||||||
|
|
||||||
|
copy
|
||||||
|
|
327
README.md
327
README.md
|
@ -1,163 +1,164 @@
|
||||||
|
|
||||||
# ScoDoc - Gestion de la scolarité - Version ScoDoc 9
|
|
||||||
|
# ScoDoc - Gestion de la scolarité - Version ScoDoc 9
|
||||||
(c) Emmanuel Viennet 1999 - 2021 (voir LICENCE.txt)
|
|
||||||
|
(c) Emmanuel Viennet 1999 - 2021 (voir LICENCE.txt)\r
|
||||||
VERSION EXPERIMENTALE - NE PAS DEPLOYER - TESTS EN COURS
|
|
||||||
|
VERSION EXPERIMENTALE - NE PAS DEPLOYER - TESTS EN COURS
|
||||||
Installation: voir instructions à jour sur <https://scodoc.org/GuideInstallDebian11>
|
|
||||||
|
Installation: voir instructions à jour sur <https://scodoc.org/GuideInstallDebian11>
|
||||||
Documentation utilisateur: <https://scodoc.org>
|
|
||||||
|
Documentation utilisateur: <https://scodoc.org>
|
||||||
## Version ScoDoc 9
|
|
||||||
|
## Version ScoDoc 9
|
||||||
N'utiliser que pour les développements et tests.
|
|
||||||
|
N'utiliser que pour les développements et tests.
|
||||||
La version ScoDoc 9 est basée sur Flask (au lieu de Zope) et sur
|
|
||||||
**python 3.9+**.
|
La version ScoDoc 9 est basée sur Flask (au lieu de Zope) et sur
|
||||||
|
**python 3.9+**.
|
||||||
La version 9.0 s'efforce de reproduire presque à l'identique le fonctionnement
|
|
||||||
de ScoDoc7, avec des composants logiciels différents (Debian 11, Python 3,
|
La version 9.0 s'efforce de reproduire presque à l'identique le fonctionnement
|
||||||
Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
|
de ScoDoc7, avec des composants logiciels différents (Debian 11, Python 3,
|
||||||
|
Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
|
||||||
|
|
||||||
|
|
||||||
### État actuel (27 août 21)
|
|
||||||
|
### État actuel (27 août 21)
|
||||||
- Tests en cours, notamment système d'installation et de migration.
|
|
||||||
|
- Tests en cours, notamment système d'installation et de migration.
|
||||||
**Fonctionnalités non intégrées:**
|
|
||||||
|
**Fonctionnalités non intégrées:**
|
||||||
- feuille "placement" (en cours)
|
|
||||||
|
- feuille "placement" (en cours)
|
||||||
- ancien module "Entreprises" (obsolete)
|
|
||||||
|
- ancien module "Entreprises" (obsolete)
|
||||||
|
|
||||||
### Lignes de commandes
|
|
||||||
|
### Lignes de commandes
|
||||||
Voir [https://scodoc.org/GuideConfig](le guide de configuration).
|
|
||||||
|
Voir [https://scodoc.org/GuideConfig](le guide de configuration).
|
||||||
|
|
||||||
## Organisation des fichiers
|
|
||||||
|
## Organisation des fichiers
|
||||||
L'installation comporte les fichiers de l'application, sous `/opt/scodoc/`, et
|
|
||||||
les fichiers locaux (archives, photos, configurations, logs) sous
|
L'installation comporte les fichiers de l'application, sous `/opt/scodoc/`, et
|
||||||
`/opt/scodoc-data`. Par ailleurs, il y a évidemment les bases de données
|
les fichiers locaux (archives, photos, configurations, logs) sous
|
||||||
postgresql et la configuration du système Linux.
|
`/opt/scodoc-data`. Par ailleurs, il y a évidemment les bases de données
|
||||||
|
postgresql et la configuration du système Linux.
|
||||||
### Fichiers locaux
|
|
||||||
Sous `/opt/scodoc-data`, fichiers et répertoires appartienant à l'utilisateur `scodoc`.
|
### Fichiers locaux
|
||||||
Ils ne doivent pas être modifiés à la main, sauf certains fichiers de configuration sous
|
Sous `/opt/scodoc-data`, fichiers et répertoires appartienant à l'utilisateur `scodoc`.
|
||||||
`/opt/scodoc-data/config`.
|
Ils ne doivent pas être modifiés à la main, sauf certains fichiers de configuration sous
|
||||||
|
`/opt/scodoc-data/config`.
|
||||||
Le répertoire `/opt/scodoc-data` doit être régulièrement sauvegardé.
|
|
||||||
|
Le répertoire `/opt/scodoc-data` doit être régulièrement sauvegardé.
|
||||||
Principaux contenus:
|
|
||||||
|
Principaux contenus:
|
||||||
/opt/scodoc-data
|
|
||||||
/opt/scodoc-data/log # Fichiers de log ScoDoc
|
/opt/scodoc-data
|
||||||
/opt/scodoc-data/config # Fichiers de configuration
|
/opt/scodoc-data/log # Fichiers de log ScoDoc
|
||||||
.../config/logos # Logos de l'établissement
|
/opt/scodoc-data/config # Fichiers de configuration
|
||||||
.../config/depts # un fichier par département
|
.../config/logos # Logos de l'établissement
|
||||||
/opt/scodoc-data/photos # Photos des étudiants
|
.../config/depts # un fichier par département
|
||||||
/opt/scodoc-data/archives # Archives: PV de jury, maquettes Apogée, fichiers étudiants
|
/opt/scodoc-data/photos # Photos des étudiants
|
||||||
|
/opt/scodoc-data/archives # Archives: PV de jury, maquettes Apogée, fichiers étudiants
|
||||||
## Pour les développeurs
|
|
||||||
|
## Pour les développeurs
|
||||||
### Installation du code
|
|
||||||
|
### Installation du code
|
||||||
Installer ScoDoc 9 normalement ([voir la doc](https://scodoc.org/GuideInstallDebian11)).
|
|
||||||
|
Installer ScoDoc 9 normalement ([voir la doc](https://scodoc.org/GuideInstallDebian11)).
|
||||||
Puis remplacer `/opt/scodoc` par un clone du git.
|
|
||||||
|
Puis remplacer `/opt/scodoc` par un clone du git.
|
||||||
sudo su
|
|
||||||
mv /opt/scodoc /opt/off-scodoc # ou ce que vous voulez
|
sudo su
|
||||||
apt-get install git # si besoin
|
mv /opt/scodoc /opt/off-scodoc # ou ce que vous voulez
|
||||||
cd /opt
|
apt-get install git # si besoin
|
||||||
git clone https://scodoc.org/git/viennet/ScoDoc.git
|
cd /opt
|
||||||
# (ou bien utiliser votre clone gitea si vous l'avez déjà créé !)
|
git clone https://scodoc.org/git/viennet/ScoDoc.git
|
||||||
mv ScoDoc scodoc # important !
|
# (ou bien utiliser votre clone gitea si vous l'avez déjà créé !)
|
||||||
|
mv ScoDoc scodoc # important !
|
||||||
Il faut ensuite installer l'environnement et le fichier de configuration:
|
|
||||||
|
Il faut ensuite installer l'environnement et le fichier de configuration:
|
||||||
# Le plus simple est de piquer le virtualenv configuré par l'installeur:
|
|
||||||
mv /opt/off-scodoc/venv /opt/scodoc
|
# Le plus simple est de piquer le virtualenv configuré par l'installeur:
|
||||||
|
mv /opt/off-scodoc/venv /opt/scodoc
|
||||||
Et la config:
|
|
||||||
|
Et la config:
|
||||||
ln -s /opt/scodoc-data/.env /opt/scodoc
|
|
||||||
|
ln -s /opt/scodoc-data/.env /opt/scodoc
|
||||||
Cette dernière commande utilise le `.env` crée lors de l'install, ce qui
|
|
||||||
n'est pas toujours le plus judicieux: vous pouvez modifier son contenu, par
|
Cette dernière commande utilise le `.env` crée lors de l'install, ce qui
|
||||||
exemple pour travailler en mode "développement" avec `FLASK_ENV=development`.
|
n'est pas toujours le plus judicieux: vous pouvez modifier son contenu, par
|
||||||
|
exemple pour travailler en mode "développement" avec `FLASK_ENV=development`.
|
||||||
### Tests unitaires
|
|
||||||
|
### Tests unitaires
|
||||||
Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
|
|
||||||
scripts de tests:
|
Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
|
||||||
Lancer au préalable:
|
scripts de tests:
|
||||||
|
Lancer au préalable:
|
||||||
flask sco-delete-dept TEST00 && flask sco-create-dept TEST00
|
|
||||||
|
flask sco-delete-dept TEST00 && flask sco-create-dept TEST00
|
||||||
Puis dérouler les tests unitaires:
|
|
||||||
|
Puis dérouler les tests unitaires:
|
||||||
pytest tests/unit
|
|
||||||
|
pytest tests/unit
|
||||||
Ou avec couverture (`pip install pytest-cov`)
|
|
||||||
|
Ou avec couverture (`pip install pytest-cov`)
|
||||||
pytest --cov=app --cov-report=term-missing --cov-branch tests/unit/*
|
|
||||||
|
pytest --cov=app --cov-report=term-missing --cov-branch tests/unit/*
|
||||||
|
|
||||||
#### Utilisation des tests unitaires pour initialiser la base de dev
|
|
||||||
On peut aussi utiliser les tests unitaires pour mettre la base
|
#### Utilisation des tests unitaires pour initialiser la base de dev
|
||||||
de données de développement dans un état connu, par exemple pour éviter de recréer à la main étudianst et semestres quand on développe.
|
On peut aussi utiliser les tests unitaires pour mettre la base
|
||||||
|
de données de développement dans un état connu, par exemple pour éviter de recréer à la main étudianst et semestres quand on développe.
|
||||||
Il suffit de positionner une variable d'environnement indiquant la BD utilisée par les tests:
|
|
||||||
|
Il suffit de positionner une variable d'environnement indiquant la BD utilisée par les tests:
|
||||||
export SCODOC_TEST_DATABASE_URI=postgresql:///SCODOC_DEV
|
|
||||||
|
export SCODOC_TEST_DATABASE_URI=postgresql:///SCODOC_DEV
|
||||||
puis de les lancer normalement, par exemple:
|
|
||||||
|
puis de les lancer normalement, par exemple:
|
||||||
pytest tests/unit/test_sco_basic.py
|
|
||||||
|
pytest tests/unit/test_sco_basic.py
|
||||||
Il est en général nécessaire d'affecter ensuite un mot de passe à (au moins)
|
|
||||||
un utilisateur:
|
Il est en général nécessaire d'affecter ensuite un mot de passe à (au moins)
|
||||||
|
un utilisateur:
|
||||||
flask user-password admin
|
|
||||||
|
flask user-password admin
|
||||||
**Attention:** les tests unitaires **effacent** complètement le contenu de la
|
|
||||||
base de données (tous les départements, et les utilisateurs) avant de commencer !
|
**Attention:** les tests unitaires **effacent** complètement le contenu de la
|
||||||
|
base de données (tous les départements, et les utilisateurs) avant de commencer !
|
||||||
#### Modification du schéma de la base
|
|
||||||
|
#### Modification du schéma de la base
|
||||||
On utilise SQLAlchemy avec Alembic et Flask-Migrate.
|
|
||||||
|
On utilise SQLAlchemy avec Alembic et Flask-Migrate.
|
||||||
flask db migrate -m "ScoDoc 9.0.x: ..." # ajuster le message !
|
|
||||||
flask db upgrade
|
flask db migrate -m "ScoDoc 9.0.x: ..." # ajuster le message !
|
||||||
|
flask db upgrade
|
||||||
Ne pas oublier de commiter les migrations (`git add migrations` ...).
|
|
||||||
|
Ne pas oublier de commiter les migrations (`git add migrations` ...).
|
||||||
Mémo pour développeurs: séquence re-création d'une base:
|
|
||||||
|
Mémo pour développeurs: séquence re-création d'une base:
|
||||||
dropdb SCODOC_DEV
|
|
||||||
tools/create_database.sh SCODOC_DEV # créé base SQL
|
dropdb SCODOC_DEV
|
||||||
flask db upgrade # créé les tables à partir des migrations
|
tools/create_database.sh SCODOC_DEV # créé base SQL
|
||||||
flask sco-db-init # ajoute au besoin les constantes (fait en migration 0)
|
flask db upgrade # créé les tables à partir des migrations
|
||||||
|
flask sco-db-init # ajoute au besoin les constantes (fait en migration 0)
|
||||||
# puis imports:
|
|
||||||
flask import-scodoc7-users
|
# puis imports:
|
||||||
flask import-scodoc7-dept STID SCOSTID
|
flask import-scodoc7-users
|
||||||
|
flask import-scodoc7-dept STID SCOSTID
|
||||||
Si la base utilisée pour les dev n'est plus en phase avec les scripts de
|
|
||||||
migration, utiliser les commandes `flask db history`et `flask db stamp`pour se
|
Si la base utilisée pour les dev n'est plus en phase avec les scripts de
|
||||||
positionner à la bonne étape.
|
migration, utiliser les commandes `flask db history`et `flask db stamp`pour se
|
||||||
|
positionner à la bonne étape.
|
||||||
# Paquet debian 11
|
|
||||||
|
# Paquet debian 11
|
||||||
Les scripts associés au paquet Debian (.deb) sont dans `tools/debian`. Le plus
|
|
||||||
important est `postinst`qui se charge de configurer le système (install ou
|
Les scripts associés au paquet Debian (.deb) sont dans `tools/debian`. Le plus
|
||||||
upgrade de scodoc9).
|
important est `postinst`qui se charge de configurer le système (install ou
|
||||||
|
upgrade de scodoc9).
|
||||||
La préparation d'une release se fait à l'aide du script
|
|
||||||
`tools/build_release.sh`.
|
La préparation d'une release se fait à l'aide du script
|
||||||
|
`tools/build_release.sh`.
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -17,14 +18,14 @@ from flask import render_template
|
||||||
from flask.logging import default_handler
|
from flask.logging import default_handler
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
from flask_login import LoginManager
|
from flask_login import LoginManager, current_user
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from flask_bootstrap import Bootstrap
|
from flask_bootstrap import Bootstrap
|
||||||
from flask_moment import Moment
|
from flask_moment import Moment
|
||||||
from flask_caching import Cache
|
from flask_caching import Cache
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from app.scodoc.sco_exceptions import ScoValueError, APIInvalidParams
|
from app.scodoc.sco_exceptions import ScoGenError, ScoValueError, APIInvalidParams
|
||||||
from config import DevConfig
|
from config import DevConfig
|
||||||
import sco_version
|
import sco_version
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ def postgresql_server_error(e):
|
||||||
return render_raw_html("error_503.html", SCOVERSION=sco_version.SCOVERSION), 503
|
return render_raw_html("error_503.html", SCOVERSION=sco_version.SCOVERSION), 503
|
||||||
|
|
||||||
|
|
||||||
class RequestFormatter(logging.Formatter):
|
class LogRequestFormatter(logging.Formatter):
|
||||||
"""Ajoute URL et remote_addr for logging"""
|
"""Ajoute URL et remote_addr for logging"""
|
||||||
|
|
||||||
def format(self, record):
|
def format(self, record):
|
||||||
|
@ -92,6 +93,33 @@ class RequestFormatter(logging.Formatter):
|
||||||
else:
|
else:
|
||||||
record.url = None
|
record.url = None
|
||||||
record.remote_addr = None
|
record.remote_addr = None
|
||||||
|
record.sco_user = current_user
|
||||||
|
|
||||||
|
return super().format(record)
|
||||||
|
|
||||||
|
|
||||||
|
class LogExceptionFormatter(logging.Formatter):
|
||||||
|
"""Formatteur pour les exceptions: ajoute détails"""
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
if has_request_context():
|
||||||
|
record.url = request.url
|
||||||
|
record.remote_addr = request.environ.get(
|
||||||
|
"HTTP_X_FORWARDED_FOR", request.remote_addr
|
||||||
|
)
|
||||||
|
record.http_referrer = request.referrer
|
||||||
|
record.http_method = request.method
|
||||||
|
if request.method == "GET":
|
||||||
|
record.http_params = str(request.args)
|
||||||
|
else:
|
||||||
|
record.http_params = "(post data not loggued)"
|
||||||
|
else:
|
||||||
|
record.url = None
|
||||||
|
record.remote_addr = None
|
||||||
|
record.http_referrer = None
|
||||||
|
record.http_method = None
|
||||||
|
record.http_params = None
|
||||||
|
record.sco_user = current_user
|
||||||
|
|
||||||
return super().format(record)
|
return super().format(record)
|
||||||
|
|
||||||
|
@ -105,8 +133,24 @@ class ScoSMTPHandler(SMTPHandler):
|
||||||
return subject
|
return subject
|
||||||
|
|
||||||
|
|
||||||
|
class ReverseProxied(object):
|
||||||
|
"""Adaptateur wsgi qui nous permet d'avoir toutes les URL calculées en https
|
||||||
|
sauf quand on est en dev.
|
||||||
|
La variable HTTP_X_FORWARDED_PROTO est positionnée par notre config nginx"""
|
||||||
|
|
||||||
|
def __init__(self, app):
|
||||||
|
self.app = app
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
scheme = environ.get("HTTP_X_FORWARDED_PROTO")
|
||||||
|
if scheme:
|
||||||
|
environ["wsgi.url_scheme"] = scheme # ou forcer à https ici ?
|
||||||
|
return self.app(environ, start_response)
|
||||||
|
|
||||||
|
|
||||||
def create_app(config_class=DevConfig):
|
def create_app(config_class=DevConfig):
|
||||||
app = Flask(__name__, static_url_path="/ScoDoc/static", static_folder="static")
|
app = Flask(__name__, static_url_path="/ScoDoc/static", static_folder="static")
|
||||||
|
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||||
app.logger.setLevel(logging.DEBUG)
|
app.logger.setLevel(logging.DEBUG)
|
||||||
app.config.from_object(config_class)
|
app.config.from_object(config_class)
|
||||||
|
|
||||||
|
@ -119,6 +163,7 @@ def create_app(config_class=DevConfig):
|
||||||
cache.init_app(app)
|
cache.init_app(app)
|
||||||
sco_cache.CACHE = cache
|
sco_cache.CACHE = cache
|
||||||
|
|
||||||
|
app.register_error_handler(ScoGenError, handle_sco_value_error)
|
||||||
app.register_error_handler(ScoValueError, handle_sco_value_error)
|
app.register_error_handler(ScoValueError, handle_sco_value_error)
|
||||||
app.register_error_handler(500, internal_server_error)
|
app.register_error_handler(500, internal_server_error)
|
||||||
app.register_error_handler(503, postgresql_server_error)
|
app.register_error_handler(503, postgresql_server_error)
|
||||||
|
@ -148,9 +193,16 @@ def create_app(config_class=DevConfig):
|
||||||
absences_bp, url_prefix="/ScoDoc/<scodoc_dept>/Scolarite/Absences"
|
absences_bp, url_prefix="/ScoDoc/<scodoc_dept>/Scolarite/Absences"
|
||||||
)
|
)
|
||||||
app.register_blueprint(api_bp, url_prefix="/ScoDoc/api")
|
app.register_blueprint(api_bp, url_prefix="/ScoDoc/api")
|
||||||
scodoc_exc_formatter = RequestFormatter(
|
scodoc_log_formatter = LogRequestFormatter(
|
||||||
"[%(asctime)s] %(remote_addr)s requested %(url)s\n"
|
"[%(asctime)s] %(sco_user)s@%(remote_addr)s requested %(url)s\n"
|
||||||
"%(levelname)s in %(module)s: %(message)s"
|
"%(levelname)s: %(message)s"
|
||||||
|
)
|
||||||
|
scodoc_exc_formatter = LogExceptionFormatter(
|
||||||
|
"[%(asctime)s] %(sco_user)s@%(remote_addr)s requested %(url)s\n"
|
||||||
|
"%(levelname)s: %(message)s\n"
|
||||||
|
"Referrer: %(http_referrer)s\n"
|
||||||
|
"Method: %(http_method)s\n"
|
||||||
|
"Params: %(http_params)s\n"
|
||||||
)
|
)
|
||||||
if not app.testing:
|
if not app.testing:
|
||||||
if not app.debug:
|
if not app.debug:
|
||||||
|
@ -179,7 +231,7 @@ def create_app(config_class=DevConfig):
|
||||||
app.logger.addHandler(mail_handler)
|
app.logger.addHandler(mail_handler)
|
||||||
else:
|
else:
|
||||||
# Pour logs en DEV uniquement:
|
# Pour logs en DEV uniquement:
|
||||||
default_handler.setFormatter(scodoc_exc_formatter)
|
default_handler.setFormatter(scodoc_log_formatter)
|
||||||
|
|
||||||
# Config logs pour DEV et PRODUCTION
|
# Config logs pour DEV et PRODUCTION
|
||||||
# Configuration des logs (actifs aussi en mode development)
|
# Configuration des logs (actifs aussi en mode development)
|
||||||
|
@ -188,9 +240,17 @@ def create_app(config_class=DevConfig):
|
||||||
file_handler = WatchedFileHandler(
|
file_handler = WatchedFileHandler(
|
||||||
app.config["SCODOC_LOG_FILE"], encoding="utf-8"
|
app.config["SCODOC_LOG_FILE"], encoding="utf-8"
|
||||||
)
|
)
|
||||||
file_handler.setFormatter(scodoc_exc_formatter)
|
file_handler.setFormatter(scodoc_log_formatter)
|
||||||
file_handler.setLevel(logging.INFO)
|
file_handler.setLevel(logging.INFO)
|
||||||
app.logger.addHandler(file_handler)
|
app.logger.addHandler(file_handler)
|
||||||
|
# Log pour les erreurs (exceptions) uniquement:
|
||||||
|
# usually /opt/scodoc-data/log/scodoc_exc.log
|
||||||
|
file_handler = WatchedFileHandler(
|
||||||
|
app.config["SCODOC_ERR_FILE"], encoding="utf-8"
|
||||||
|
)
|
||||||
|
file_handler.setFormatter(scodoc_exc_formatter)
|
||||||
|
file_handler.setLevel(logging.ERROR)
|
||||||
|
app.logger.addHandler(file_handler)
|
||||||
|
|
||||||
# app.logger.setLevel(logging.INFO)
|
# app.logger.setLevel(logging.INFO)
|
||||||
app.logger.info(f"{sco_version.SCONAME} {sco_version.SCOVERSION} startup")
|
app.logger.info(f"{sco_version.SCONAME} {sco_version.SCOVERSION} startup")
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.from flask import jsonify
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
from flask import jsonify
|
||||||
from werkzeug.http import HTTP_STATUS_CODES
|
from werkzeug.http import HTTP_STATUS_CODES
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,18 +43,20 @@ class ZRequest(object):
|
||||||
"Emulating Zope 2 REQUEST"
|
"Emulating Zope 2 REQUEST"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
if current_app.config["DEBUG"]:
|
# if current_app.config["DEBUG"]:
|
||||||
self.URL = request.base_url
|
|
||||||
self.BASE0 = request.url_root
|
# le ReverseProxied se charge maintenant de mettre le bon protocole http ou https
|
||||||
else:
|
# self.URL = request.base_url
|
||||||
self.URL = request.base_url.replace("http://", "https://")
|
# self.BASE0 = request.url_root
|
||||||
self.BASE0 = request.url_root.replace("http://", "https://")
|
# else:
|
||||||
self.URL0 = self.URL
|
# self.URL = request.base_url.replace("http://", "https://")
|
||||||
|
# self.BASE0 = request.url_root.replace("http://", "https://")
|
||||||
|
# self.URL0 = self.URL
|
||||||
# query_string is bytes:
|
# query_string is bytes:
|
||||||
self.QUERY_STRING = request.query_string.decode("utf-8")
|
# self.QUERY_STRING = request.query_string.decode("utf-8")
|
||||||
self.REQUEST_METHOD = request.method
|
# self.REQUEST_METHOD = request.method
|
||||||
self.AUTHENTICATED_USER = current_user
|
# self.AUTHENTICATED_USER = current_user
|
||||||
self.REMOTE_ADDR = request.remote_addr
|
# self.REMOTE_ADDR = request.remote_addr
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
# request.form is a werkzeug.datastructures.ImmutableMultiDict
|
# request.form is a werkzeug.datastructures.ImmutableMultiDict
|
||||||
# must copy to get a mutable version (needed by TrivialFormulator)
|
# must copy to get a mutable version (needed by TrivialFormulator)
|
||||||
|
@ -72,16 +74,13 @@ class ZRequest(object):
|
||||||
if k.endswith(":list"):
|
if k.endswith(":list"):
|
||||||
self.form[k[:-5]] = request.args.getlist(k)
|
self.form[k[:-5]] = request.args.getlist(k)
|
||||||
else:
|
else:
|
||||||
self.form[k] = request.args[k]
|
values = request.args.getlist(k)
|
||||||
|
self.form[k] = values[0] if len(values) == 1 else values
|
||||||
# current_app.logger.info("ZRequest.form=%s" % str(self.form))
|
# current_app.logger.info("ZRequest.form=%s" % str(self.form))
|
||||||
self.RESPONSE = ZResponse()
|
self.RESPONSE = ZResponse()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return """REQUEST
|
return """ZREQUEST
|
||||||
URL={r.URL}
|
|
||||||
QUERY_STRING={r.QUERY_STRING}
|
|
||||||
REQUEST_METHOD={r.REQUEST_METHOD}
|
|
||||||
AUTHENTICATED_USER={r.AUTHENTICATED_USER}
|
|
||||||
form={r.form}
|
form={r.form}
|
||||||
""".format(
|
""".format(
|
||||||
r=self
|
r=self
|
||||||
|
@ -231,6 +230,7 @@ def scodoc7func(func):
|
||||||
if arg_name == "REQUEST": # special case
|
if arg_name == "REQUEST": # special case
|
||||||
pos_arg_values.append(REQUEST)
|
pos_arg_values.append(REQUEST)
|
||||||
else:
|
else:
|
||||||
|
# peut produire une KeyError s'il manque un argument attendu:
|
||||||
v = req_args[arg_name]
|
v = req_args[arg_name]
|
||||||
# try to convert all arguments to INTEGERS
|
# try to convert all arguments to INTEGERS
|
||||||
# necessary for db ids and boolean values
|
# necessary for db ids and boolean values
|
||||||
|
|
|
@ -41,6 +41,7 @@ class Identite(db.Model):
|
||||||
code_nip = db.Column(db.Text())
|
code_nip = db.Column(db.Text())
|
||||||
code_ine = db.Column(db.Text())
|
code_ine = db.Column(db.Text())
|
||||||
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
||||||
|
# ne pas utiliser après migrate_scodoc7_dept_archive
|
||||||
scodoc7_id = db.Column(db.Text(), nullable=True)
|
scodoc7_id = db.Column(db.Text(), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class NotesFormation(db.Model):
|
||||||
"""Programme pédagogique d'une formation"""
|
"""Programme pédagogique d'une formation"""
|
||||||
|
|
||||||
__tablename__ = "notes_formations"
|
__tablename__ = "notes_formations"
|
||||||
__table_args__ = (db.UniqueConstraint("acronyme", "titre", "version"),)
|
__table_args__ = (db.UniqueConstraint("dept_id", "acronyme", "titre", "version"),)
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
formation_id = db.synonym("id")
|
formation_id = db.synonym("id")
|
||||||
|
|
|
@ -41,6 +41,10 @@ class FormSemestre(db.Model):
|
||||||
bul_hide_xml = db.Column(
|
bul_hide_xml = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
|
# Bloque le calcul des moyennes (générale et d'UE)
|
||||||
|
block_moyennes = db.Column(
|
||||||
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
|
)
|
||||||
# semestres decales (pour gestion jurys):
|
# semestres decales (pour gestion jurys):
|
||||||
gestion_semestrielle = db.Column(
|
gestion_semestrielle = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
|
@ -70,6 +74,7 @@ class FormSemestre(db.Model):
|
||||||
"NotesFormsemestreEtape", cascade="all,delete", backref="notes_formsemestre"
|
"NotesFormsemestreEtape", cascade="all,delete", backref="notes_formsemestre"
|
||||||
)
|
)
|
||||||
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
||||||
|
# ne pas utiliser après migrate_scodoc7_dept_archive
|
||||||
scodoc7_id = db.Column(db.Text(), nullable=True)
|
scodoc7_id = db.Column(db.Text(), nullable=True)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
v 1.3 (python3)
|
v 1.3 (python3)
|
||||||
"""
|
"""
|
||||||
|
import html
|
||||||
|
|
||||||
|
|
||||||
def TrivialFormulator(
|
def TrivialFormulator(
|
||||||
|
@ -722,7 +723,9 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts);
|
||||||
if str(descr["allowed_values"][i]) == str(self.values[field]):
|
if str(descr["allowed_values"][i]) == str(self.values[field]):
|
||||||
R.append('<span class="tf-ro-value">%s</span>' % labels[i])
|
R.append('<span class="tf-ro-value">%s</span>' % labels[i])
|
||||||
elif input_type == "textarea":
|
elif input_type == "textarea":
|
||||||
R.append('<div class="tf-ro-textarea">%s</div>' % self.values[field])
|
R.append(
|
||||||
|
'<div class="tf-ro-textarea">%s</div>' % html.escape(self.values[field])
|
||||||
|
)
|
||||||
elif input_type == "separator" or input_type == "hidden":
|
elif input_type == "separator" or input_type == "hidden":
|
||||||
pass
|
pass
|
||||||
elif input_type == "file":
|
elif input_type == "file":
|
||||||
|
|
|
@ -379,6 +379,25 @@ def bonus_iutbethune(notes_sport, coefs, infos=None):
|
||||||
return bonus
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
|
def bonus_iutbeziers(notes_sport, coefs, infos=None):
|
||||||
|
"""Calcul bonus modules optionels (sport, culture), regle IUT BEZIERS
|
||||||
|
|
||||||
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
|
sport , etc) non rattaches à une unité d'enseignement. Les points
|
||||||
|
au-dessus de 10 sur 20 obtenus dans chacune des matières
|
||||||
|
optionnelles sont cumulés et 3% de ces points cumulés s'ajoutent à
|
||||||
|
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||||
|
"""
|
||||||
|
sumc = sum(coefs) # assumes sum. coefs > 0
|
||||||
|
# note_sport = sum(map(mul, notes_sport, coefs)) / sumc # moyenne pondérée
|
||||||
|
bonus = sum([(x - 10) * 0.03 for x in notes_sport if x > 10])
|
||||||
|
# le total du bonus ne doit pas dépasser 0.3 - Fred, 28/01/2020
|
||||||
|
|
||||||
|
if bonus > 0.3:
|
||||||
|
bonus = 0.3
|
||||||
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
def bonus_demo(notes_sport, coefs, infos=None):
|
def bonus_demo(notes_sport, coefs, infos=None):
|
||||||
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
||||||
et aider les développeurs.
|
et aider les développeurs.
|
||||||
|
@ -386,8 +405,8 @@ def bonus_demo(notes_sport, coefs, infos=None):
|
||||||
qui est ECRASE à chaque appel.
|
qui est ECRASE à chaque appel.
|
||||||
*** Ne pas utiliser en production !!! ***
|
*** Ne pas utiliser en production !!! ***
|
||||||
"""
|
"""
|
||||||
f = open("/tmp/scodoc_bonus.log", "w") # mettre 'a' pour ajouter en fin
|
with open("/tmp/scodoc_bonus.log", "w") as f: # mettre 'a' pour ajouter en fin
|
||||||
f.write("\n---------------\n" + pprint.pformat(infos) + "\n")
|
f.write("\n---------------\n" + pprint.pformat(infos) + "\n")
|
||||||
# Statut de chaque UE
|
# Statut de chaque UE
|
||||||
# for ue_id in infos['moy_ues']:
|
# for ue_id in infos['moy_ues']:
|
||||||
# ue_status = infos['moy_ues'][ue_id]
|
# ue_status = infos['moy_ues'][ue_id]
|
||||||
|
|
|
@ -185,6 +185,9 @@ class GenTable(object):
|
||||||
else:
|
else:
|
||||||
self.preferences = DEFAULT_TABLE_PREFERENCES()
|
self.preferences = DEFAULT_TABLE_PREFERENCES()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<gen_table( nrows={self.get_nb_rows()}, ncols={self.get_nb_cols()} )>"
|
||||||
|
|
||||||
def get_nb_cols(self):
|
def get_nb_cols(self):
|
||||||
return len(self.columns_ids)
|
return len(self.columns_ids)
|
||||||
|
|
||||||
|
@ -482,9 +485,9 @@ class GenTable(object):
|
||||||
ses.append_blank_row() # empty line
|
ses.append_blank_row() # empty line
|
||||||
ses.append_single_cell_row(self.origin, style_base)
|
ses.append_single_cell_row(self.origin, style_base)
|
||||||
if wb is None:
|
if wb is None:
|
||||||
return ses.generate_standalone()
|
return ses.generate()
|
||||||
else:
|
else:
|
||||||
ses.generate_embeded()
|
ses.generate()
|
||||||
|
|
||||||
def text(self):
|
def text(self):
|
||||||
"raw text representation of the table"
|
"raw text representation of the table"
|
||||||
|
@ -573,7 +576,7 @@ class GenTable(object):
|
||||||
"""
|
"""
|
||||||
doc = ElementTree.Element(
|
doc = ElementTree.Element(
|
||||||
self.xml_outer_tag,
|
self.xml_outer_tag,
|
||||||
id=self.table_id,
|
id=str(self.table_id),
|
||||||
origin=self.origin or "",
|
origin=self.origin or "",
|
||||||
caption=self.caption or "",
|
caption=self.caption or "",
|
||||||
)
|
)
|
||||||
|
@ -587,7 +590,7 @@ class GenTable(object):
|
||||||
v = row.get(cid, "")
|
v = row.get(cid, "")
|
||||||
if v is None:
|
if v is None:
|
||||||
v = ""
|
v = ""
|
||||||
x_cell = ElementTree.Element(cid, value=str(v))
|
x_cell = ElementTree.Element(str(cid), value=str(v))
|
||||||
x_row.append(x_cell)
|
x_row.append(x_cell)
|
||||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
||||||
|
|
||||||
|
@ -610,7 +613,6 @@ class GenTable(object):
|
||||||
format="html",
|
format="html",
|
||||||
page_title="",
|
page_title="",
|
||||||
filename=None,
|
filename=None,
|
||||||
REQUEST=None,
|
|
||||||
javascripts=[],
|
javascripts=[],
|
||||||
with_html_headers=True,
|
with_html_headers=True,
|
||||||
publish=True,
|
publish=True,
|
||||||
|
@ -643,35 +645,53 @@ class GenTable(object):
|
||||||
H.append(html_sco_header.sco_footer())
|
H.append(html_sco_header.sco_footer())
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
elif format == "pdf":
|
elif format == "pdf":
|
||||||
objects = self.pdf()
|
pdf_objs = self.pdf()
|
||||||
doc = sco_pdf.pdf_basic_page(
|
pdf_doc = sco_pdf.pdf_basic_page(
|
||||||
objects, title=title, preferences=self.preferences
|
pdf_objs, title=title, preferences=self.preferences
|
||||||
)
|
)
|
||||||
if publish:
|
if publish:
|
||||||
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
return scu.send_file(
|
||||||
|
pdf_doc,
|
||||||
|
filename,
|
||||||
|
suffix=".pdf",
|
||||||
|
mime=scu.PDF_MIMETYPE,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return doc
|
return pdf_doc
|
||||||
elif format == "xls" or format == "xlsx":
|
elif format == "xls" or format == "xlsx": # dans les 2 cas retourne du xlsx
|
||||||
xls = self.excel()
|
xls = self.excel()
|
||||||
if publish:
|
if publish:
|
||||||
return sco_excel.send_excel_file(
|
return scu.send_file(
|
||||||
REQUEST, xls, filename + scu.XLSX_SUFFIX
|
xls,
|
||||||
|
filename,
|
||||||
|
suffix=scu.XLSX_SUFFIX,
|
||||||
|
mime=scu.XLSX_MIMETYPE,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return xls
|
return xls
|
||||||
elif format == "text":
|
elif format == "text":
|
||||||
return self.text()
|
return self.text()
|
||||||
elif format == "csv":
|
elif format == "csv":
|
||||||
return scu.sendCSVFile(REQUEST, self.text(), filename + ".csv")
|
return scu.send_file(
|
||||||
|
self.text(),
|
||||||
|
filename,
|
||||||
|
suffix=".csv",
|
||||||
|
mime=scu.CSV_MIMETYPE,
|
||||||
|
attached=True,
|
||||||
|
)
|
||||||
elif format == "xml":
|
elif format == "xml":
|
||||||
xml = self.xml()
|
xml = self.xml()
|
||||||
if REQUEST and publish:
|
if publish:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
return scu.send_file(
|
||||||
|
xml, filename, suffix=".xml", mime=scu.XML_MIMETYPE
|
||||||
|
)
|
||||||
return xml
|
return xml
|
||||||
elif format == "json":
|
elif format == "json":
|
||||||
js = self.json()
|
js = self.json()
|
||||||
if REQUEST and publish:
|
if publish:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
return scu.send_file(
|
||||||
|
js, filename, suffix=".json", mime=scu.JSON_MIMETYPE
|
||||||
|
)
|
||||||
return js
|
return js
|
||||||
else:
|
else:
|
||||||
log("make_page: format=%s" % format)
|
log("make_page: format=%s" % format)
|
||||||
|
@ -732,5 +752,5 @@ if __name__ == "__main__":
|
||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = doc.getvalue()
|
data = doc.getvalue()
|
||||||
open("/tmp/gen_table.pdf", "wb").write(data)
|
open("/tmp/gen_table.pdf", "wb").write(data)
|
||||||
p = T.make_page(format="pdf", REQUEST=None)
|
p = T.make_page(format="pdf")
|
||||||
open("toto.pdf", "wb").write(p)
|
open("toto.pdf", "wb").write(p)
|
||||||
|
|
|
@ -87,10 +87,6 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_TOP_LEVEL_CSS = """
|
|
||||||
<style type="text/css">
|
|
||||||
</style>"""
|
|
||||||
|
|
||||||
_HTML_BEGIN = """<?xml version="1.0" encoding="%(encoding)s"?>
|
_HTML_BEGIN = """<?xml version="1.0" encoding="%(encoding)s"?>
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
@ -105,31 +101,30 @@ _HTML_BEGIN = """<?xml version="1.0" encoding="%(encoding)s"?>
|
||||||
|
|
||||||
<link href="/ScoDoc/static/css/scodoc.css" rel="stylesheet" type="text/css" />
|
<link href="/ScoDoc/static/css/scodoc.css" rel="stylesheet" type="text/css" />
|
||||||
<link href="/ScoDoc/static/css/menu.css" rel="stylesheet" type="text/css" />
|
<link href="/ScoDoc/static/css/menu.css" rel="stylesheet" type="text/css" />
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/menu.js"></script>
|
<script src="/ScoDoc/static/libjs/menu.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/sorttable.js"></script>
|
<script src="/ScoDoc/static/libjs/sorttable.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/bubble.js"></script>
|
<script src="/ScoDoc/static/libjs/bubble.js"></script>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
window.onload=function(){enableTooltips("gtrcontent")};
|
window.onload=function(){enableTooltips("gtrcontent")};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/jQuery/jquery.js"></script>
|
<script src="/ScoDoc/static/jQuery/jquery.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/jQuery/jquery-migrate-1.2.0.min.js"></script>
|
<script src="/ScoDoc/static/jQuery/jquery-migrate-1.2.0.min.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/jquery.field.min.js"></script>
|
<script src="/ScoDoc/static/libjs/jquery.field.min.js"></script>
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.min.js"></script>
|
<script src="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.min.js"></script>
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.js"></script>
|
<script src="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.js"></script>
|
||||||
<link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.css" />
|
<link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.css" />
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/js/scodoc.js"></script>
|
<script src="/ScoDoc/static/js/scodoc.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/js/etud_info.js"></script>
|
<script src="/ScoDoc/static/js/etud_info.js"></script>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def scodoc_top_html_header(page_title="ScoDoc: bienvenue"):
|
def scodoc_top_html_header(page_title="ScoDoc: bienvenue"):
|
||||||
H = [
|
H = [
|
||||||
_HTML_BEGIN % {"page_title": page_title, "encoding": scu.SCO_ENCODING},
|
_HTML_BEGIN % {"page_title": page_title, "encoding": scu.SCO_ENCODING},
|
||||||
_TOP_LEVEL_CSS,
|
|
||||||
"""</head><body class="gtrcontent" id="gtrcontent">""",
|
"""</head><body class="gtrcontent" id="gtrcontent">""",
|
||||||
scu.CUSTOM_HTML_HEADER_CNX,
|
scu.CUSTOM_HTML_HEADER_CNX,
|
||||||
]
|
]
|
||||||
|
@ -185,13 +180,10 @@ def sco_header(
|
||||||
init_jquery = True
|
init_jquery = True
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
"""<?xml version="1.0" encoding="%(encoding)s"?>
|
"""<!DOCTYPE html><html lang="fr">
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
<title>%(page_title)s</title>
|
<title>%(page_title)s</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=%(encoding)s" />
|
|
||||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
|
||||||
<meta name="LANG" content="fr" />
|
<meta name="LANG" content="fr" />
|
||||||
<meta name="DESCRIPTION" content="ScoDoc" />
|
<meta name="DESCRIPTION" content="ScoDoc" />
|
||||||
|
|
||||||
|
@ -206,9 +198,7 @@ def sco_header(
|
||||||
)
|
)
|
||||||
if init_google_maps:
|
if init_google_maps:
|
||||||
# It may be necessary to add an API key:
|
# It may be necessary to add an API key:
|
||||||
H.append(
|
H.append('<script src="https://maps.google.com/maps/api/js"></script>')
|
||||||
'<script type="text/javascript" src="https://maps.google.com/maps/api/js"></script>'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Feuilles de style additionnelles:
|
# Feuilles de style additionnelles:
|
||||||
for cssstyle in cssstyles:
|
for cssstyle in cssstyles:
|
||||||
|
@ -223,9 +213,9 @@ def sco_header(
|
||||||
<link href="/ScoDoc/static/css/menu.css" rel="stylesheet" type="text/css" />
|
<link href="/ScoDoc/static/css/menu.css" rel="stylesheet" type="text/css" />
|
||||||
<link href="/ScoDoc/static/css/gt_table.css" rel="stylesheet" type="text/css" />
|
<link href="/ScoDoc/static/css/gt_table.css" rel="stylesheet" type="text/css" />
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/menu.js"></script>
|
<script src="/ScoDoc/static/libjs/menu.js"></script>
|
||||||
<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/bubble.js"></script>
|
<script src="/ScoDoc/static/libjs/bubble.js"></script>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
window.onload=function(){enableTooltips("gtrcontent")};
|
window.onload=function(){enableTooltips("gtrcontent")};
|
||||||
|
|
||||||
var SCO_URL="%(ScoURL)s";
|
var SCO_URL="%(ScoURL)s";
|
||||||
|
@ -236,16 +226,14 @@ def sco_header(
|
||||||
# jQuery
|
# jQuery
|
||||||
if init_jquery:
|
if init_jquery:
|
||||||
H.append(
|
H.append(
|
||||||
"""<script language="javascript" type="text/javascript" src="/ScoDoc/static/jQuery/jquery.js"></script>
|
"""<script src="/ScoDoc/static/jQuery/jquery.js"></script>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
H.append(
|
H.append('<script src="/ScoDoc/static/libjs/jquery.field.min.js"></script>')
|
||||||
'<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/jquery.field.min.js"></script>'
|
|
||||||
)
|
|
||||||
# qTip
|
# qTip
|
||||||
if init_qtip:
|
if init_qtip:
|
||||||
H.append(
|
H.append(
|
||||||
'<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.js"></script>'
|
'<script src="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.js"></script>'
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.css" />'
|
'<link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/qtip/jquery.qtip-3.0.3.min.css" />'
|
||||||
|
@ -253,32 +241,25 @@ def sco_header(
|
||||||
|
|
||||||
if init_jquery_ui:
|
if init_jquery_ui:
|
||||||
H.append(
|
H.append(
|
||||||
'<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.min.js"></script>'
|
'<script src="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.min.js"></script>'
|
||||||
)
|
|
||||||
# H.append('<script language="javascript" type="text/javascript" src="/ScoDoc/static/libjs/jquery-ui/js/jquery-ui-i18n.js"></script>')
|
|
||||||
H.append(
|
|
||||||
'<script language="javascript" type="text/javascript" src="/ScoDoc/static/js/scodoc.js"></script>'
|
|
||||||
)
|
)
|
||||||
|
# H.append('<script src="/ScoDoc/static/libjs/jquery-ui/js/jquery-ui-i18n.js"></script>')
|
||||||
|
H.append('<script src="/ScoDoc/static/js/scodoc.js"></script>')
|
||||||
if init_google_maps:
|
if init_google_maps:
|
||||||
H.append(
|
H.append(
|
||||||
'<script type="text/javascript" src="/ScoDoc/static/libjs/jquery.ui.map.full.min.js"></script>'
|
'<script src="/ScoDoc/static/libjs/jquery.ui.map.full.min.js"></script>'
|
||||||
)
|
)
|
||||||
if init_datatables:
|
if init_datatables:
|
||||||
H.append(
|
H.append(
|
||||||
'<link rel="stylesheet" type="text/css" href="/ScoDoc/static/DataTables/datatables.min.css"/>'
|
'<link rel="stylesheet" type="text/css" href="/ScoDoc/static/DataTables/datatables.min.css"/>'
|
||||||
)
|
)
|
||||||
H.append(
|
H.append('<script src="/ScoDoc/static/DataTables/datatables.min.js"></script>')
|
||||||
'<script type="text/javascript" src="/ScoDoc/static/DataTables/datatables.min.js"></script>'
|
|
||||||
)
|
|
||||||
# JS additionels
|
# JS additionels
|
||||||
for js in javascripts:
|
for js in javascripts:
|
||||||
H.append(
|
H.append("""<script src="/ScoDoc/static/%s"></script>\n""" % js)
|
||||||
"""<script language="javascript" type="text/javascript" src="/ScoDoc/static/%s"></script>\n"""
|
|
||||||
% js
|
|
||||||
)
|
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<style type="text/css">
|
"""<style>
|
||||||
.gtrcontent {
|
.gtrcontent {
|
||||||
margin-left: %(margin_left)s;
|
margin-left: %(margin_left)s;
|
||||||
height: 100%%;
|
height: 100%%;
|
||||||
|
@ -290,7 +271,7 @@ def sco_header(
|
||||||
)
|
)
|
||||||
# Scripts de la page:
|
# Scripts de la page:
|
||||||
if scripts:
|
if scripts:
|
||||||
H.append("""<script language="javascript" type="text/javascript">""")
|
H.append("""<script>""")
|
||||||
for script in scripts:
|
for script in scripts:
|
||||||
H.append(script)
|
H.append(script)
|
||||||
H.append("""</script>""")
|
H.append("""</script>""")
|
||||||
|
@ -337,13 +318,7 @@ def sco_footer():
|
||||||
|
|
||||||
|
|
||||||
def html_sem_header(
|
def html_sem_header(
|
||||||
REQUEST,
|
title, sem=None, with_page_header=True, with_h2=True, page_title=None, **args
|
||||||
title,
|
|
||||||
sem=None,
|
|
||||||
with_page_header=True,
|
|
||||||
with_h2=True,
|
|
||||||
page_title=None,
|
|
||||||
**args
|
|
||||||
):
|
):
|
||||||
"Titre d'une page semestre avec lien vers tableau de bord"
|
"Titre d'une page semestre avec lien vers tableau de bord"
|
||||||
# sem now unused and thus optional...
|
# sem now unused and thus optional...
|
||||||
|
|
|
@ -28,9 +28,8 @@
|
||||||
"""
|
"""
|
||||||
Génération de la "sidebar" (marge gauche des pages HTML)
|
Génération de la "sidebar" (marge gauche des pages HTML)
|
||||||
"""
|
"""
|
||||||
from flask import url_for
|
from flask import render_template, url_for
|
||||||
from flask import g
|
from flask import g, request
|
||||||
from flask import request
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -155,8 +154,9 @@ def sidebar():
|
||||||
<div class="sidebar-bottom"><a href="{ url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }" class="sidebar">À propos</a><br/>
|
<div class="sidebar-bottom"><a href="{ url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }" class="sidebar">À propos</a><br/>
|
||||||
<a href="{ scu.SCO_USER_MANUAL }" target="_blank" class="sidebar">Aide</a>
|
<a href="{ scu.SCO_USER_MANUAL }" target="_blank" class="sidebar">Aide</a>
|
||||||
</div></div>
|
</div></div>
|
||||||
<div class="logo-logo"><a href= { url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }
|
<div class="logo-logo">
|
||||||
">{ scu.icontag("scologo_img", no_size=True) }</a>
|
<a href="{ url_for( 'scodoc.about', scodoc_dept=g.scodoc_dept ) }">
|
||||||
|
{ scu.icontag("scologo_img", no_size=True) }</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- end of sidebar -->
|
<!-- end of sidebar -->
|
||||||
|
@ -167,19 +167,7 @@ def sidebar():
|
||||||
|
|
||||||
def sidebar_dept():
|
def sidebar_dept():
|
||||||
"""Partie supérieure de la marge de gauche"""
|
"""Partie supérieure de la marge de gauche"""
|
||||||
H = [
|
return render_template(
|
||||||
f"""<h2 class="insidebar">Dépt. {sco_preferences.get_preference("DeptName")}</h2>
|
"sidebar_dept.html",
|
||||||
<a href="{url_for("scodoc.index")}" class="sidebar">Accueil</a> <br/> """
|
prefs=sco_preferences.SemPreferences(),
|
||||||
]
|
)
|
||||||
dept_intranet_url = sco_preferences.get_preference("DeptIntranetURL")
|
|
||||||
if dept_intranet_url:
|
|
||||||
H.append(
|
|
||||||
f"""<a href="{dept_intranet_url}" class="sidebar">{
|
|
||||||
sco_preferences.get_preference("DeptIntranetTitle")}</a> <br/>"""
|
|
||||||
)
|
|
||||||
# Entreprises pas encore supporté en ScoDoc8
|
|
||||||
# H.append(
|
|
||||||
# """<br/><a href="%(ScoURL)s/Entreprises" class="sidebar">Entreprises</a> <br/>"""
|
|
||||||
# % infos
|
|
||||||
# )
|
|
||||||
return "\n".join(H)
|
|
||||||
|
|
|
@ -186,6 +186,8 @@ class NotesTable(object):
|
||||||
self.use_ue_coefs = sco_preferences.get_preference(
|
self.use_ue_coefs = sco_preferences.get_preference(
|
||||||
"use_ue_coefs", formsemestre_id
|
"use_ue_coefs", formsemestre_id
|
||||||
)
|
)
|
||||||
|
# si vrai, bloque calcul des moy gen. et d'UE.:
|
||||||
|
self.block_moyennes = self.sem["block_moyennes"]
|
||||||
# Infos sur les etudiants
|
# Infos sur les etudiants
|
||||||
self.inscrlist = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
self.inscrlist = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
args={"formsemestre_id": formsemestre_id}
|
args={"formsemestre_id": formsemestre_id}
|
||||||
|
@ -738,6 +740,7 @@ class NotesTable(object):
|
||||||
block_computation = (
|
block_computation = (
|
||||||
self.inscrdict[etudid]["etat"] == "D"
|
self.inscrdict[etudid]["etat"] == "D"
|
||||||
or self.inscrdict[etudid]["etat"] == DEF
|
or self.inscrdict[etudid]["etat"] == DEF
|
||||||
|
or self.block_moyennes
|
||||||
)
|
)
|
||||||
|
|
||||||
moy_ues = {}
|
moy_ues = {}
|
||||||
|
|
|
@ -626,7 +626,6 @@ def add_absence(
|
||||||
jour,
|
jour,
|
||||||
matin,
|
matin,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description=None,
|
description=None,
|
||||||
moduleimpl_id=None,
|
moduleimpl_id=None,
|
||||||
):
|
):
|
||||||
|
@ -656,7 +655,7 @@ def add_absence(
|
||||||
sco_abs_notification.abs_notify(etudid, jour)
|
sco_abs_notification.abs_notify(etudid, jour)
|
||||||
|
|
||||||
|
|
||||||
def add_justif(etudid, jour, matin, REQUEST, description=None):
|
def add_justif(etudid, jour, matin, description=None):
|
||||||
"Ajoute un justificatif dans la base"
|
"Ajoute un justificatif dans la base"
|
||||||
# unpublished
|
# unpublished
|
||||||
if _isFarFutur(jour):
|
if _isFarFutur(jour):
|
||||||
|
@ -665,7 +664,9 @@ def add_justif(etudid, jour, matin, REQUEST, description=None):
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"insert into absences (etudid,jour,estabs,estjust,matin, description) values (%(etudid)s,%(jour)s, FALSE, TRUE, %(matin)s, %(description)s )",
|
"""INSERT INTO absences (etudid, jour, estabs, estjust, matin, description)
|
||||||
|
VALUES (%(etudid)s, %(jour)s, FALSE, TRUE, %(matin)s, %(description)s)
|
||||||
|
""",
|
||||||
vars(),
|
vars(),
|
||||||
)
|
)
|
||||||
logdb(
|
logdb(
|
||||||
|
@ -678,7 +679,7 @@ def add_justif(etudid, jour, matin, REQUEST, description=None):
|
||||||
invalidate_abs_etud_date(etudid, jour)
|
invalidate_abs_etud_date(etudid, jour)
|
||||||
|
|
||||||
|
|
||||||
def _add_abslist(abslist, REQUEST, moduleimpl_id=None):
|
def add_abslist(abslist, moduleimpl_id=None):
|
||||||
for a in abslist:
|
for a in abslist:
|
||||||
etudid, jour, ampm = a.split(":")
|
etudid, jour, ampm = a.split(":")
|
||||||
if ampm == "am":
|
if ampm == "am":
|
||||||
|
@ -689,7 +690,7 @@ def _add_abslist(abslist, REQUEST, moduleimpl_id=None):
|
||||||
raise ValueError("invalid ampm !")
|
raise ValueError("invalid ampm !")
|
||||||
# ajoute abs si pas deja absent
|
# ajoute abs si pas deja absent
|
||||||
if count_abs(etudid, jour, jour, matin, moduleimpl_id) == 0:
|
if count_abs(etudid, jour, jour, matin, moduleimpl_id) == 0:
|
||||||
add_absence(etudid, jour, matin, 0, REQUEST, "", moduleimpl_id)
|
add_absence(etudid, jour, matin, 0, "", moduleimpl_id)
|
||||||
|
|
||||||
|
|
||||||
def annule_absence(etudid, jour, matin, moduleimpl_id=None):
|
def annule_absence(etudid, jour, matin, moduleimpl_id=None):
|
||||||
|
@ -721,7 +722,7 @@ def annule_absence(etudid, jour, matin, moduleimpl_id=None):
|
||||||
invalidate_abs_etud_date(etudid, jour)
|
invalidate_abs_etud_date(etudid, jour)
|
||||||
|
|
||||||
|
|
||||||
def annule_justif(etudid, jour, matin, REQUEST=None):
|
def annule_justif(etudid, jour, matin):
|
||||||
"Annule un justificatif"
|
"Annule un justificatif"
|
||||||
# unpublished
|
# unpublished
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
|
@ -58,7 +58,6 @@ def doSignaleAbsence(
|
||||||
estjust=False,
|
estjust=False,
|
||||||
description=None,
|
description=None,
|
||||||
etudid=False,
|
etudid=False,
|
||||||
REQUEST=None,
|
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Signalement d'une absence.
|
"""Signalement d'une absence.
|
||||||
|
|
||||||
|
@ -69,7 +68,8 @@ def doSignaleAbsence(
|
||||||
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
||||||
estjust: absence justifiée
|
estjust: absence justifiée
|
||||||
description: str
|
description: str
|
||||||
etudid: etudiant concerné. Si non spécifié, cherche dans REQUEST.form
|
etudid: etudiant concerné. Si non spécifié, cherche dans
|
||||||
|
les paramètres de la requête courante.
|
||||||
"""
|
"""
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
@ -86,7 +86,6 @@ def doSignaleAbsence(
|
||||||
jour,
|
jour,
|
||||||
False,
|
False,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description_abs,
|
description_abs,
|
||||||
moduleimpl_id,
|
moduleimpl_id,
|
||||||
)
|
)
|
||||||
|
@ -95,7 +94,6 @@ def doSignaleAbsence(
|
||||||
jour,
|
jour,
|
||||||
True,
|
True,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description_abs,
|
description_abs,
|
||||||
moduleimpl_id,
|
moduleimpl_id,
|
||||||
)
|
)
|
||||||
|
@ -106,7 +104,6 @@ def doSignaleAbsence(
|
||||||
jour,
|
jour,
|
||||||
demijournee,
|
demijournee,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description_abs,
|
description_abs,
|
||||||
moduleimpl_id,
|
moduleimpl_id,
|
||||||
)
|
)
|
||||||
|
@ -156,7 +153,7 @@ def doSignaleAbsence(
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def SignaleAbsenceEtud(REQUEST=None): # etudid implied
|
def SignaleAbsenceEtud(): # etudid implied
|
||||||
"""Formulaire individuel simple de signalement d'une absence"""
|
"""Formulaire individuel simple de signalement d'une absence"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
|
@ -228,7 +225,6 @@ def SignaleAbsenceEtud(REQUEST=None): # etudid implied
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
title="fiche de " + etud["nomprenom"],
|
title="fiche de " + etud["nomprenom"],
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""
|
"""
|
||||||
|
@ -281,7 +277,6 @@ def doJustifAbsence(
|
||||||
demijournee,
|
demijournee,
|
||||||
description=None,
|
description=None,
|
||||||
etudid=False,
|
etudid=False,
|
||||||
REQUEST=None,
|
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Justification d'une absence
|
"""Justification d'une absence
|
||||||
|
|
||||||
|
@ -291,7 +286,8 @@ def doJustifAbsence(
|
||||||
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
||||||
estjust: absence justifiée
|
estjust: absence justifiée
|
||||||
description: str
|
description: str
|
||||||
etudid: etudiant concerné. Si non spécifié, cherche dans REQUEST.form
|
etudid: etudiant concerné. Si non spécifié, cherche dans les
|
||||||
|
paramètres de la requête.
|
||||||
"""
|
"""
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
@ -305,14 +301,12 @@ def doJustifAbsence(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
jour=jour,
|
jour=jour,
|
||||||
matin=False,
|
matin=False,
|
||||||
REQUEST=REQUEST,
|
|
||||||
description=description_abs,
|
description=description_abs,
|
||||||
)
|
)
|
||||||
sco_abs.add_justif(
|
sco_abs.add_justif(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
jour=jour,
|
jour=jour,
|
||||||
matin=True,
|
matin=True,
|
||||||
REQUEST=REQUEST,
|
|
||||||
description=description_abs,
|
description=description_abs,
|
||||||
)
|
)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
|
@ -321,7 +315,6 @@ def doJustifAbsence(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
jour=jour,
|
jour=jour,
|
||||||
matin=demijournee,
|
matin=demijournee,
|
||||||
REQUEST=REQUEST,
|
|
||||||
description=description_abs,
|
description=description_abs,
|
||||||
)
|
)
|
||||||
nbadded += 1
|
nbadded += 1
|
||||||
|
@ -357,7 +350,7 @@ def doJustifAbsence(
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def JustifAbsenceEtud(REQUEST=None): # etudid implied
|
def JustifAbsenceEtud(): # etudid implied
|
||||||
"""Formulaire individuel simple de justification d'une absence"""
|
"""Formulaire individuel simple de justification d'une absence"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
|
@ -376,7 +369,6 @@ def JustifAbsenceEtud(REQUEST=None): # etudid implied
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
title="fiche de " + etud["nomprenom"],
|
title="fiche de " + etud["nomprenom"],
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""
|
"""
|
||||||
|
@ -412,9 +404,7 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def doAnnuleAbsence(
|
def doAnnuleAbsence(datedebut, datefin, demijournee, etudid=False): # etudid implied
|
||||||
datedebut, datefin, demijournee, etudid=False, REQUEST=None
|
|
||||||
): # etudid implied
|
|
||||||
"""Annulation des absences pour une demi journée"""
|
"""Annulation des absences pour une demi journée"""
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
@ -462,7 +452,7 @@ autre absence pour <b>%(nomprenom)s</b></a></li>
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def AnnuleAbsenceEtud(REQUEST=None): # etudid implied
|
def AnnuleAbsenceEtud(): # etudid implied
|
||||||
"""Formulaire individuel simple d'annulation d'une absence"""
|
"""Formulaire individuel simple d'annulation d'une absence"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
|
@ -482,7 +472,6 @@ def AnnuleAbsenceEtud(REQUEST=None): # etudid implied
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
title="fiche de " + etud["nomprenom"],
|
title="fiche de " + etud["nomprenom"],
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que l'étudiant était en fait présent. </p>
|
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que l'étudiant était en fait présent. </p>
|
||||||
|
@ -548,7 +537,7 @@ def AnnuleAbsenceEtud(REQUEST=None): # etudid implied
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def doAnnuleJustif(datedebut0, datefin0, demijournee, REQUEST=None): # etudid implied
|
def doAnnuleJustif(datedebut0, datefin0, demijournee): # etudid implied
|
||||||
"""Annulation d'une justification"""
|
"""Annulation d'une justification"""
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
@ -558,11 +547,11 @@ def doAnnuleJustif(datedebut0, datefin0, demijournee, REQUEST=None): # etudid i
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
# Attention: supprime matin et après-midi
|
# Attention: supprime matin et après-midi
|
||||||
if demijournee == 2:
|
if demijournee == 2:
|
||||||
sco_abs.annule_justif(etudid, jour, False, REQUEST=REQUEST)
|
sco_abs.annule_justif(etudid, jour, False)
|
||||||
sco_abs.annule_justif(etudid, jour, True, REQUEST=REQUEST)
|
sco_abs.annule_justif(etudid, jour, True)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
else:
|
else:
|
||||||
sco_abs.annule_justif(etudid, jour, demijournee, REQUEST=REQUEST)
|
sco_abs.annule_justif(etudid, jour, demijournee)
|
||||||
nbadded += 1
|
nbadded += 1
|
||||||
#
|
#
|
||||||
H = [
|
H = [
|
||||||
|
@ -716,7 +705,6 @@ def formChoixSemestreGroupe(all=False):
|
||||||
def CalAbs(etudid, sco_year=None):
|
def CalAbs(etudid, sco_year=None):
|
||||||
"""Calendrier des absences d'un etudiant"""
|
"""Calendrier des absences d'un etudiant"""
|
||||||
# crude portage from 1999 DTML
|
# crude portage from 1999 DTML
|
||||||
REQUEST = None # XXX
|
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
anneescolaire = int(scu.AnneeScolaire(sco_year))
|
anneescolaire = int(scu.AnneeScolaire(sco_year))
|
||||||
|
@ -766,7 +754,6 @@ def CalAbs(etudid, sco_year=None):
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
title="fiche de " + etud["nomprenom"],
|
title="fiche de " + etud["nomprenom"],
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CalHTML,
|
CalHTML,
|
||||||
|
@ -791,7 +778,6 @@ def ListeAbsEtud(
|
||||||
format="html",
|
format="html",
|
||||||
absjust_only=0,
|
absjust_only=0,
|
||||||
sco_year=None,
|
sco_year=None,
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Liste des absences d'un étudiant sur l'année en cours
|
"""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 'html': page avec deux tableaux (non justifiées et justifiées).
|
||||||
|
@ -810,12 +796,12 @@ def ListeAbsEtud(
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
|
|
||||||
# Liste des absences et titres colonnes tables:
|
# Liste des absences et titres colonnes tables:
|
||||||
titles, columns_ids, absnonjust, absjust = _TablesAbsEtud(
|
titles, columns_ids, absnonjust, absjust = _tables_abs_etud(
|
||||||
etudid, datedebut, with_evals=with_evals, format=format
|
etudid, datedebut, with_evals=with_evals, format=format
|
||||||
)
|
)
|
||||||
if REQUEST:
|
if request.base_url:
|
||||||
base_url_nj = "%s?etudid=%s&absjust_only=0" % (REQUEST.URL0, etudid)
|
base_url_nj = "%s?etudid=%s&absjust_only=0" % (request.base_url, etudid)
|
||||||
base_url_j = "%s?etudid=%s&absjust_only=1" % (REQUEST.URL0, etudid)
|
base_url_j = "%s?etudid=%s&absjust_only=1" % (request.base_url, etudid)
|
||||||
else:
|
else:
|
||||||
base_url_nj = base_url_j = ""
|
base_url_nj = base_url_j = ""
|
||||||
tab_absnonjust = GenTable(
|
tab_absnonjust = GenTable(
|
||||||
|
@ -844,9 +830,9 @@ def ListeAbsEtud(
|
||||||
# Formats non HTML et demande d'une seule table:
|
# Formats non HTML et demande d'une seule table:
|
||||||
if format != "html" and format != "text":
|
if format != "html" and format != "text":
|
||||||
if absjust_only == 1:
|
if absjust_only == 1:
|
||||||
return tab_absjust.make_page(format=format, REQUEST=REQUEST)
|
return tab_absjust.make_page(format=format)
|
||||||
else:
|
else:
|
||||||
return tab_absnonjust.make_page(format=format, REQUEST=REQUEST)
|
return tab_absnonjust.make_page(format=format)
|
||||||
|
|
||||||
if format == "html":
|
if format == "html":
|
||||||
# Mise en forme HTML:
|
# Mise en forme HTML:
|
||||||
|
@ -896,13 +882,12 @@ def ListeAbsEtud(
|
||||||
raise ValueError("Invalid format !")
|
raise ValueError("Invalid format !")
|
||||||
|
|
||||||
|
|
||||||
def _TablesAbsEtud(
|
def _tables_abs_etud(
|
||||||
etudid,
|
etudid,
|
||||||
datedebut,
|
datedebut,
|
||||||
with_evals=True,
|
with_evals=True,
|
||||||
format="html",
|
format="html",
|
||||||
absjust_only=0,
|
absjust_only=0,
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Tables des absences justifiees et non justifiees d'un étudiant
|
"""Tables des absences justifiees et non justifiees d'un étudiant
|
||||||
sur l'année en cours
|
sur l'année en cours
|
||||||
|
@ -928,11 +913,11 @@ def _TablesAbsEtud(
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT mi.moduleimpl_id
|
"""SELECT mi.moduleimpl_id
|
||||||
FROM absences abs, notes_moduleimpl_inscription mi, notes_moduleimpl m
|
FROM absences abs, notes_moduleimpl_inscription mi, notes_moduleimpl m
|
||||||
WHERE abs.matin = %(matin)s
|
WHERE abs.matin = %(matin)s
|
||||||
and abs.jour = %(jour)s
|
and abs.jour = %(jour)s
|
||||||
and abs.etudid = %(etudid)s
|
and abs.etudid = %(etudid)s
|
||||||
and abs.moduleimpl_id = mi.moduleimpl_id
|
and abs.moduleimpl_id = mi.moduleimpl_id
|
||||||
and mi.moduleimpl_id = m.id
|
and mi.moduleimpl_id = m.id
|
||||||
and mi.etudid = %(etudid)s
|
and mi.etudid = %(etudid)s
|
||||||
""",
|
""",
|
||||||
{
|
{
|
||||||
|
@ -959,8 +944,9 @@ def _TablesAbsEtud(
|
||||||
)[0]
|
)[0]
|
||||||
if format == "html":
|
if format == "html":
|
||||||
ex.append(
|
ex.append(
|
||||||
'<a href="Notes/moduleimpl_status?moduleimpl_id=%s">%s</a>'
|
f"""<a href="{url_for('notes.moduleimpl_status',
|
||||||
% (mod["moduleimpl_id"], mod["module"]["code"])
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
||||||
|
">{mod["module"]["code"]}</a>"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ex.append(mod["module"]["code"])
|
ex.append(mod["module"]["code"])
|
||||||
|
@ -976,8 +962,9 @@ def _TablesAbsEtud(
|
||||||
)[0]
|
)[0]
|
||||||
if format == "html":
|
if format == "html":
|
||||||
ex.append(
|
ex.append(
|
||||||
'<a href="Notes/moduleimpl_status?moduleimpl_id=%s">%s</a>'
|
f"""<a href="{url_for('notes.moduleimpl_status',
|
||||||
% (mod["moduleimpl_id"], mod["module"]["code"])
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
||||||
|
">{mod["module"]["code"]}</a>"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ex.append(mod["module"]["code"])
|
ex.append(mod["module"]["code"])
|
||||||
|
|
|
@ -29,37 +29,40 @@
|
||||||
|
|
||||||
|
|
||||||
Archives are plain files, stored in
|
Archives are plain files, stored in
|
||||||
<SCODOC_VAR_DIR>/archives/<deptid>
|
<SCODOC_VAR_DIR>/archives/<dept_id>
|
||||||
(where <SCODOC_VAR_DIR> is usually /opt/scodoc-data, and <deptid> a departement id)
|
(where <SCODOC_VAR_DIR> is usually /opt/scodoc-data, and <dept_id> a departement id (int))
|
||||||
|
|
||||||
Les PV de jurys et documents associés sont stockées dans un sous-repertoire de la forme
|
Les PV de jurys et documents associés sont stockées dans un sous-repertoire de la forme
|
||||||
<archivedir>/<dept>/<formsemestre_id>/<YYYY-MM-DD-HH-MM-SS>
|
<archivedir>/<dept>/<formsemestre_id>/<YYYY-MM-DD-HH-MM-SS>
|
||||||
(formsemestre_id est ici FormSemestre.scodoc7_id ou à défaut FormSemestre.id)
|
(formsemestre_id est ici FormSemestre.id)
|
||||||
|
|
||||||
Les documents liés à l'étudiant sont dans
|
Les documents liés à l'étudiant sont dans
|
||||||
<archivedir>/docetuds/<dept>/<etudid>/<YYYY-MM-DD-HH-MM-SS>
|
<archivedir>/docetuds/<dept_id>/<etudid>/<YYYY-MM-DD-HH-MM-SS>
|
||||||
(etudid est ici soit Identite.scodoc7id, soit à défaut Identite.id)
|
(etudid est ici Identite.id)
|
||||||
|
|
||||||
Les maquettes Apogée pour l'export des notes sont dans
|
Les maquettes Apogée pour l'export des notes sont dans
|
||||||
<archivedir>/apo_csv/<dept>/<annee_scolaire>-<sem_id>/<YYYY-MM-DD-HH-MM-SS>/<code_etape>.csv
|
<archivedir>/apo_csv/<dept_id>/<annee_scolaire>-<sem_id>/<YYYY-MM-DD-HH-MM-SS>/<code_etape>.csv
|
||||||
|
|
||||||
Un répertoire d'archive contient des fichiers quelconques, et un fichier texte nommé _description.txt
|
Un répertoire d'archive contient des fichiers quelconques, et un fichier texte nommé _description.txt
|
||||||
qui est une description (humaine, format libre) de l'archive.
|
qui est une description (humaine, format libre) de l'archive.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import glob
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from config import Config
|
from config import Config
|
||||||
from app import log
|
from app import log
|
||||||
|
from app.models import Departement
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
|
@ -108,7 +111,8 @@ class BaseArchiver(object):
|
||||||
If directory does not yet exist, create it.
|
If directory does not yet exist, create it.
|
||||||
"""
|
"""
|
||||||
self.initialize()
|
self.initialize()
|
||||||
dept_dir = os.path.join(self.root, g.scodoc_dept)
|
dept = Departement.query.filter_by(acronym=g.scodoc_dept).first()
|
||||||
|
dept_dir = os.path.join(self.root, str(dept.id))
|
||||||
try:
|
try:
|
||||||
scu.GSL.acquire()
|
scu.GSL.acquire()
|
||||||
if not os.path.isdir(dept_dir):
|
if not os.path.isdir(dept_dir):
|
||||||
|
@ -127,7 +131,8 @@ class BaseArchiver(object):
|
||||||
:return: list of archive oids
|
:return: list of archive oids
|
||||||
"""
|
"""
|
||||||
self.initialize()
|
self.initialize()
|
||||||
base = os.path.join(self.root, g.scodoc_dept) + os.path.sep
|
dept = Departement.query.filter_by(acronym=g.scodoc_dept).first()
|
||||||
|
base = os.path.join(self.root, str(dept.id)) + os.path.sep
|
||||||
dirs = glob.glob(base + "*")
|
dirs = glob.glob(base + "*")
|
||||||
return [os.path.split(x)[1] for x in dirs]
|
return [os.path.split(x)[1] for x in dirs]
|
||||||
|
|
||||||
|
@ -244,31 +249,15 @@ class BaseArchiver(object):
|
||||||
log("reading archive file %s" % fname)
|
log("reading archive file %s" % fname)
|
||||||
return open(fname, "rb").read()
|
return open(fname, "rb").read()
|
||||||
|
|
||||||
def get_archived_file(self, REQUEST, oid, archive_name, filename):
|
def get_archived_file(self, oid, archive_name, filename):
|
||||||
"""Recupere donnees du fichier indiqué et envoie au client"""
|
"""Recupere donnees du fichier indiqué et envoie au client"""
|
||||||
# XXX très incomplet: devrait inférer et assigner un type MIME
|
|
||||||
archive_id = self.get_id_from_name(oid, archive_name)
|
archive_id = self.get_id_from_name(oid, archive_name)
|
||||||
data = self.get(archive_id, filename)
|
data = self.get(archive_id, filename)
|
||||||
ext = os.path.splitext(filename.lower())[1]
|
mime = mimetypes.guess_type(filename)[0]
|
||||||
if ext == ".html" or ext == ".htm":
|
if mime is None:
|
||||||
return data
|
mime = "application/octet-stream"
|
||||||
elif ext == ".xml":
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
return scu.send_file(data, filename, mime=mime)
|
||||||
return data
|
|
||||||
elif ext == ".xls":
|
|
||||||
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":
|
|
||||||
return scu.sendPDFFile(REQUEST, data, filename)
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", "application/octet-stream")
|
|
||||||
return data # should set mimetype for known files like images
|
|
||||||
|
|
||||||
|
|
||||||
class SemsArchiver(BaseArchiver):
|
class SemsArchiver(BaseArchiver):
|
||||||
|
@ -305,7 +294,7 @@ def do_formsemestre_archive(
|
||||||
from app.scodoc.sco_recapcomplet import make_formsemestre_recapcomplet
|
from app.scodoc.sco_recapcomplet import make_formsemestre_recapcomplet
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
|
sem_archive_id = formsemestre_id
|
||||||
archive_id = PVArchive.create_obj_archive(sem_archive_id, description)
|
archive_id = PVArchive.create_obj_archive(sem_archive_id, description)
|
||||||
date = PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y à %H:%M")
|
date = PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y à %H:%M")
|
||||||
|
|
||||||
|
@ -394,9 +383,7 @@ def formsemestre_archive(REQUEST, formsemestre_id, group_ids=[]):
|
||||||
(all students or only selected groups)
|
(all students or only selected groups)
|
||||||
"""
|
"""
|
||||||
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
||||||
raise AccessDenied(
|
raise AccessDenied("opération non autorisée pour %s" % str(current_user))
|
||||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
|
||||||
)
|
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
if not group_ids:
|
if not group_ids:
|
||||||
|
@ -408,7 +395,6 @@ def formsemestre_archive(REQUEST, formsemestre_id, group_ids=[]):
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Archiver les PV et résultats du semestre",
|
"Archiver les PV et résultats du semestre",
|
||||||
sem=sem,
|
sem=sem,
|
||||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||||
|
@ -469,7 +455,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
|
@ -519,7 +505,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
||||||
def formsemestre_list_archives(REQUEST, formsemestre_id):
|
def formsemestre_list_archives(REQUEST, formsemestre_id):
|
||||||
"""Page listing archives"""
|
"""Page listing archives"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
|
sem_archive_id = formsemestre_id
|
||||||
L = []
|
L = []
|
||||||
for archive_id in PVArchive.list_obj_archives(sem_archive_id):
|
for archive_id in PVArchive.list_obj_archives(sem_archive_id):
|
||||||
a = {
|
a = {
|
||||||
|
@ -530,7 +516,7 @@ def formsemestre_list_archives(REQUEST, formsemestre_id):
|
||||||
}
|
}
|
||||||
L.append(a)
|
L.append(a)
|
||||||
|
|
||||||
H = [html_sco_header.html_sem_header(REQUEST, "Archive des PV et résultats ", sem)]
|
H = [html_sco_header.html_sem_header("Archive des PV et résultats ", sem)]
|
||||||
if not L:
|
if not L:
|
||||||
H.append("<p>aucune archive enregistrée</p>")
|
H.append("<p>aucune archive enregistrée</p>")
|
||||||
else:
|
else:
|
||||||
|
@ -559,11 +545,11 @@ def formsemestre_list_archives(REQUEST, formsemestre_id):
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_get_archived_file(REQUEST, formsemestre_id, archive_name, filename):
|
def formsemestre_get_archived_file(formsemestre_id, archive_name, filename):
|
||||||
"""Send file to client."""
|
"""Send file to client."""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
|
sem_archive_id = formsemestre_id
|
||||||
return PVArchive.get_archived_file(REQUEST, sem_archive_id, archive_name, filename)
|
return PVArchive.get_archived_file(sem_archive_id, archive_name, filename)
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_delete_archive(
|
def formsemestre_delete_archive(
|
||||||
|
@ -571,11 +557,9 @@ def formsemestre_delete_archive(
|
||||||
):
|
):
|
||||||
"""Delete an archive"""
|
"""Delete an archive"""
|
||||||
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
if not sco_permissions_check.can_edit_pv(formsemestre_id):
|
||||||
raise AccessDenied(
|
raise AccessDenied("opération non autorisée pour %s" % str(current_user))
|
||||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
|
||||||
)
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
|
sem_archive_id = formsemestre_id
|
||||||
archive_id = PVArchive.get_id_from_name(sem_archive_id, archive_name)
|
archive_id = PVArchive.get_id_from_name(sem_archive_id, archive_name)
|
||||||
|
|
||||||
dest_url = "formsemestre_list_archives?formsemestre_id=%s" % (formsemestre_id)
|
dest_url = "formsemestre_list_archives?formsemestre_id=%s" % (formsemestre_id)
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
les dossiers d'admission et autres pièces utiles.
|
les dossiers d'admission et autres pièces utiles.
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_import_etuds
|
from app.scodoc import sco_import_etuds
|
||||||
|
@ -60,12 +61,12 @@ def can_edit_etud_archive(authuser):
|
||||||
|
|
||||||
def etud_list_archives_html(REQUEST, etudid):
|
def etud_list_archives_html(REQUEST, etudid):
|
||||||
"""HTML snippet listing archives"""
|
"""HTML snippet listing archives"""
|
||||||
can_edit = can_edit_etud_archive(REQUEST.AUTHENTICATED_USER)
|
can_edit = can_edit_etud_archive(current_user)
|
||||||
etuds = sco_etud.get_etud_info(etudid=etudid)
|
etuds = sco_etud.get_etud_info(etudid=etudid)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
raise ScoValueError("étudiant inexistant")
|
raise ScoValueError("étudiant inexistant")
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
etud_archive_id = etud["scodoc7_id"] or etudid
|
etud_archive_id = etudid
|
||||||
L = []
|
L = []
|
||||||
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
|
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
|
||||||
a = {
|
a = {
|
||||||
|
@ -118,7 +119,7 @@ def add_archives_info_to_etud_list(etuds):
|
||||||
"""
|
"""
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
l = []
|
l = []
|
||||||
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
|
etud_archive_id = etud["etudid"]
|
||||||
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
|
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
|
||||||
l.append(
|
l.append(
|
||||||
"%s (%s)"
|
"%s (%s)"
|
||||||
|
@ -133,10 +134,8 @@ def add_archives_info_to_etud_list(etuds):
|
||||||
def etud_upload_file_form(REQUEST, etudid):
|
def etud_upload_file_form(REQUEST, etudid):
|
||||||
"""Page with a form to choose and upload a file, with a description."""
|
"""Page with a form to choose and upload a file, with a description."""
|
||||||
# check permission
|
# check permission
|
||||||
if not can_edit_etud_archive(REQUEST.AUTHENTICATED_USER):
|
if not can_edit_etud_archive(current_user):
|
||||||
raise AccessDenied(
|
raise AccessDenied("opération non autorisée pour %s" % current_user)
|
||||||
"opération non autorisée pour %s" % REQUEST.AUTHENTICATED_USER
|
|
||||||
)
|
|
||||||
etuds = sco_etud.get_etud_info(filled=True)
|
etuds = sco_etud.get_etud_info(filled=True)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
raise ScoValueError("étudiant inexistant")
|
raise ScoValueError("étudiant inexistant")
|
||||||
|
@ -153,7 +152,7 @@ def etud_upload_file_form(REQUEST, etudid):
|
||||||
% (scu.CONFIG.ETUD_MAX_FILE_SIZE // (1024 * 1024)),
|
% (scu.CONFIG.ETUD_MAX_FILE_SIZE // (1024 * 1024)),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("etudid", {"default": etudid, "input_type": "hidden"}),
|
("etudid", {"default": etudid, "input_type": "hidden"}),
|
||||||
|
@ -181,7 +180,7 @@ def etud_upload_file_form(REQUEST, etudid):
|
||||||
data = tf[2]["datafile"].read()
|
data = tf[2]["datafile"].read()
|
||||||
descr = tf[2]["description"]
|
descr = tf[2]["description"]
|
||||||
filename = tf[2]["datafile"].filename
|
filename = tf[2]["datafile"].filename
|
||||||
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
|
etud_archive_id = etud["etudid"]
|
||||||
_store_etud_file_to_new_archive(
|
_store_etud_file_to_new_archive(
|
||||||
etud_archive_id, data, filename, description=descr
|
etud_archive_id, data, filename, description=descr
|
||||||
)
|
)
|
||||||
|
@ -202,15 +201,13 @@ def _store_etud_file_to_new_archive(etud_archive_id, data, filename, description
|
||||||
def etud_delete_archive(REQUEST, etudid, archive_name, dialog_confirmed=False):
|
def etud_delete_archive(REQUEST, etudid, archive_name, dialog_confirmed=False):
|
||||||
"""Delete an archive"""
|
"""Delete an archive"""
|
||||||
# check permission
|
# check permission
|
||||||
if not can_edit_etud_archive(REQUEST.AUTHENTICATED_USER):
|
if not can_edit_etud_archive(current_user):
|
||||||
raise AccessDenied(
|
raise AccessDenied("opération non autorisée pour %s" % str(current_user))
|
||||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
|
||||||
)
|
|
||||||
etuds = sco_etud.get_etud_info(filled=True)
|
etuds = sco_etud.get_etud_info(filled=True)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
raise ScoValueError("étudiant inexistant")
|
raise ScoValueError("étudiant inexistant")
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
|
etud_archive_id = etud["etudid"]
|
||||||
archive_id = EtudsArchive.get_id_from_name(etud_archive_id, archive_name)
|
archive_id = EtudsArchive.get_id_from_name(etud_archive_id, archive_name)
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
|
@ -242,16 +239,14 @@ def etud_delete_archive(REQUEST, etudid, archive_name, dialog_confirmed=False):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def etud_get_archived_file(REQUEST, etudid, archive_name, filename):
|
def etud_get_archived_file(etudid, archive_name, filename):
|
||||||
"""Send file to client."""
|
"""Send file to client."""
|
||||||
etuds = sco_etud.get_etud_info(filled=True)
|
etuds = sco_etud.get_etud_info(etudid=etudid, filled=True)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
raise ScoValueError("étudiant inexistant")
|
raise ScoValueError("étudiant inexistant")
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
|
etud_archive_id = etud["etudid"]
|
||||||
return EtudsArchive.get_archived_file(
|
return EtudsArchive.get_archived_file(etud_archive_id, archive_name, filename)
|
||||||
REQUEST, etud_archive_id, archive_name, filename
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# --- Upload d'un ensemble de fichiers (pour un groupe d'étudiants)
|
# --- Upload d'un ensemble de fichiers (pour un groupe d'étudiants)
|
||||||
|
@ -271,8 +266,11 @@ def etudarchive_generate_excel_sample(group_id=None, REQUEST=None):
|
||||||
],
|
],
|
||||||
extra_cols=["fichier_a_charger"],
|
extra_cols=["fichier_a_charger"],
|
||||||
)
|
)
|
||||||
return sco_excel.send_excel_file(
|
return scu.send_file(
|
||||||
REQUEST, data, "ImportFichiersEtudiants" + scu.XLSX_SUFFIX
|
data,
|
||||||
|
"ImportFichiersEtudiants",
|
||||||
|
suffix=scu.XLSX_SUFFIX,
|
||||||
|
mime=scu.XLSX_MIMETYPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -310,7 +308,7 @@ def etudarchive_import_files_form(group_id, REQUEST=None):
|
||||||
]
|
]
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("xlsfile", {"title": "Fichier Excel:", "input_type": "file", "size": 40}),
|
("xlsfile", {"title": "Fichier Excel:", "input_type": "file", "size": 40}),
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"""Génération des bulletins de notes
|
"""Génération des bulletins de notes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from app.models import formsemestre
|
||||||
import time
|
import time
|
||||||
import pprint
|
import pprint
|
||||||
import email
|
import email
|
||||||
|
@ -35,11 +36,10 @@ from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.mime.base import MIMEBase
|
from email.mime.base import MIMEBase
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
|
|
||||||
from reportlab.lib.colors import Color
|
from reportlab.lib.colors import Color
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
import urllib
|
||||||
|
|
||||||
from flask import g
|
from flask import g, request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
|
@ -48,7 +48,7 @@ import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import AccessDenied
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import htmlutils
|
from app.scodoc import htmlutils
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
|
@ -121,9 +121,7 @@ def make_context_dict(sem, etud):
|
||||||
return C
|
return C
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_bulletinetud_dict(
|
def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
||||||
formsemestre_id, etudid, version="long", REQUEST=None
|
|
||||||
):
|
|
||||||
"""Collecte informations pour bulletin de notes
|
"""Collecte informations pour bulletin de notes
|
||||||
Retourne un dictionnaire (avec valeur par défaut chaine vide).
|
Retourne un dictionnaire (avec valeur par défaut chaine vide).
|
||||||
Le contenu du dictionnaire dépend des options (rangs, ...)
|
Le contenu du dictionnaire dépend des options (rangs, ...)
|
||||||
|
@ -143,10 +141,7 @@ def formsemestre_bulletinetud_dict(
|
||||||
I["etudid"] = etudid
|
I["etudid"] = etudid
|
||||||
I["formsemestre_id"] = formsemestre_id
|
I["formsemestre_id"] = formsemestre_id
|
||||||
I["sem"] = nt.sem
|
I["sem"] = nt.sem
|
||||||
if REQUEST:
|
I["server_name"] = request.url_root
|
||||||
I["server_name"] = REQUEST.BASE0
|
|
||||||
else:
|
|
||||||
I["server_name"] = ""
|
|
||||||
|
|
||||||
# Formation et parcours
|
# Formation et parcours
|
||||||
I["formation"] = sco_formations.formation_list(
|
I["formation"] = sco_formations.formation_list(
|
||||||
|
@ -778,7 +773,10 @@ def formsemestre_bulletinetud(
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
except:
|
except:
|
||||||
return scu.log_unknown_etud(REQUEST, format=format)
|
sco_etud.log_unknown_etud()
|
||||||
|
raise ScoValueError("étudiant inconnu")
|
||||||
|
|
||||||
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
bulletin = do_formsemestre_bulletinetud(
|
bulletin = do_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
|
@ -791,7 +789,8 @@ def formsemestre_bulletinetud(
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
)[0]
|
)[0]
|
||||||
if format not in {"html", "pdfmail"}:
|
if format not in {"html", "pdfmail"}:
|
||||||
return bulletin
|
filename = scu.bul_filename(sem, etud, format)
|
||||||
|
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
|
@ -862,14 +861,13 @@ def do_formsemestre_bulletinetud(
|
||||||
):
|
):
|
||||||
"""Génère le bulletin au format demandé.
|
"""Génère le bulletin au format demandé.
|
||||||
Retourne: (bul, filigranne)
|
Retourne: (bul, filigranne)
|
||||||
où bul est au format demandé (html, pdf, pdfmail, pdfpart, xml)
|
où bul est str ou bytes au format demandé (html, pdf, pdfmail, pdfpart, xml, json)
|
||||||
et filigranne est un message à placer en "filigranne" (eg "Provisoire").
|
et filigranne est un message à placer en "filigranne" (eg "Provisoire").
|
||||||
"""
|
"""
|
||||||
if format == "xml":
|
if format == "xml":
|
||||||
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
|
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
etudid,
|
etudid,
|
||||||
REQUEST=REQUEST,
|
|
||||||
xml_with_decisions=xml_with_decisions,
|
xml_with_decisions=xml_with_decisions,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
version=version,
|
version=version,
|
||||||
|
@ -881,19 +879,18 @@ def do_formsemestre_bulletinetud(
|
||||||
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
|
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
etudid,
|
etudid,
|
||||||
REQUEST=REQUEST,
|
|
||||||
xml_with_decisions=xml_with_decisions,
|
xml_with_decisions=xml_with_decisions,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
version=version,
|
version=version,
|
||||||
)
|
)
|
||||||
return bul, ""
|
return bul, ""
|
||||||
|
|
||||||
I = formsemestre_bulletinetud_dict(formsemestre_id, etudid, REQUEST=REQUEST)
|
I = formsemestre_bulletinetud_dict(formsemestre_id, etudid)
|
||||||
etud = I["etud"]
|
etud = I["etud"]
|
||||||
|
|
||||||
if format == "html":
|
if format == "html":
|
||||||
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||||
I, version=version, format="html", REQUEST=REQUEST
|
I, version=version, format="html"
|
||||||
)
|
)
|
||||||
return htm, I["filigranne"]
|
return htm, I["filigranne"]
|
||||||
|
|
||||||
|
@ -903,11 +900,10 @@ def do_formsemestre_bulletinetud(
|
||||||
version=version,
|
version=version,
|
||||||
format="pdf",
|
format="pdf",
|
||||||
stand_alone=(format != "pdfpart"),
|
stand_alone=(format != "pdfpart"),
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
)
|
||||||
if format == "pdf":
|
if format == "pdf":
|
||||||
return (
|
return (
|
||||||
scu.sendPDFFile(REQUEST, bul, filename),
|
scu.sendPDFFile(bul, filename),
|
||||||
I["filigranne"],
|
I["filigranne"],
|
||||||
) # unused ret. value
|
) # unused ret. value
|
||||||
else:
|
else:
|
||||||
|
@ -923,11 +919,11 @@ def do_formsemestre_bulletinetud(
|
||||||
htm = "" # speed up if html version not needed
|
htm = "" # speed up if html version not needed
|
||||||
else:
|
else:
|
||||||
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||||
I, version=version, format="html", REQUEST=REQUEST
|
I, version=version, format="html"
|
||||||
)
|
)
|
||||||
|
|
||||||
pdfdata, filename = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
pdfdata, filename = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||||
I, version=version, format="pdf", REQUEST=REQUEST
|
I, version=version, format="pdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
if prefer_mail_perso:
|
if prefer_mail_perso:
|
||||||
|
@ -998,7 +994,6 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr):
|
||||||
|
|
||||||
# Attach pdf
|
# Attach pdf
|
||||||
msg.attach(filename, scu.PDF_MIMETYPE, pdfdata)
|
msg.attach(filename, scu.PDF_MIMETYPE, pdfdata)
|
||||||
|
|
||||||
log("mail bulletin a %s" % recipient_addr)
|
log("mail bulletin a %s" % recipient_addr)
|
||||||
email.send_message(msg)
|
email.send_message(msg)
|
||||||
|
|
||||||
|
@ -1033,7 +1028,7 @@ def _formsemestre_bulletinetud_header_html(
|
||||||
),
|
),
|
||||||
"""
|
"""
|
||||||
<form name="f" method="GET" action="%s">"""
|
<form name="f" method="GET" action="%s">"""
|
||||||
% REQUEST.URL0,
|
% request.base_url,
|
||||||
f"""Bulletin <span class="bull_liensemestre"><a href="{
|
f"""Bulletin <span class="bull_liensemestre"><a href="{
|
||||||
url_for("notes.formsemestre_status",
|
url_for("notes.formsemestre_status",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
@ -1063,14 +1058,20 @@ def _formsemestre_bulletinetud_header_html(
|
||||||
H.append("""</select></td>""")
|
H.append("""</select></td>""")
|
||||||
# Menu
|
# Menu
|
||||||
endpoint = "notes.formsemestre_bulletinetud"
|
endpoint = "notes.formsemestre_bulletinetud"
|
||||||
url = REQUEST.URL0
|
|
||||||
qurl = six.moves.urllib.parse.quote_plus(url + "?" + REQUEST.QUERY_STRING)
|
|
||||||
|
|
||||||
menuBul = [
|
menuBul = [
|
||||||
{
|
{
|
||||||
"title": "Réglages bulletins",
|
"title": "Réglages bulletins",
|
||||||
"endpoint": "notes.formsemestre_edit_options",
|
"endpoint": "notes.formsemestre_edit_options",
|
||||||
"args": {"formsemestre_id": formsemestre_id, "target_url": qurl},
|
"args": {
|
||||||
|
"formsemestre_id": formsemestre_id,
|
||||||
|
# "target_url": url_for(
|
||||||
|
# "notes.formsemestre_bulletinetud",
|
||||||
|
# scodoc_dept=g.scodoc_dept,
|
||||||
|
# formsemestre_id=formsemestre_id,
|
||||||
|
# etudid=etudid,
|
||||||
|
# ),
|
||||||
|
},
|
||||||
"enabled": (current_user.id in sem["responsables"])
|
"enabled": (current_user.id in sem["responsables"])
|
||||||
or current_user.has_permission(Permission.ScoImplement),
|
or current_user.has_permission(Permission.ScoImplement),
|
||||||
},
|
},
|
||||||
|
@ -1113,6 +1114,16 @@ def _formsemestre_bulletinetud_header_html(
|
||||||
"enabled": etud["emailperso"]
|
"enabled": etud["emailperso"]
|
||||||
and can_send_bulletin_by_mail(formsemestre_id),
|
and can_send_bulletin_by_mail(formsemestre_id),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Version json",
|
||||||
|
"endpoint": endpoint,
|
||||||
|
"args": {
|
||||||
|
"formsemestre_id": formsemestre_id,
|
||||||
|
"etudid": etudid,
|
||||||
|
"version": version,
|
||||||
|
"format": "json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "Version XML",
|
"title": "Version XML",
|
||||||
"endpoint": endpoint,
|
"endpoint": endpoint,
|
||||||
|
@ -1188,9 +1199,14 @@ def _formsemestre_bulletinetud_header_html(
|
||||||
H.append(
|
H.append(
|
||||||
'<td> <a href="%s">%s</a></td>'
|
'<td> <a href="%s">%s</a></td>'
|
||||||
% (
|
% (
|
||||||
url
|
url_for(
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
"notes.formsemestre_bulletinetud",
|
||||||
% (formsemestre_id, etudid, version),
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre_id,
|
||||||
|
etudid=etudid,
|
||||||
|
format="pdf",
|
||||||
|
version=version,
|
||||||
|
),
|
||||||
scu.ICON_PDF,
|
scu.ICON_PDF,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1201,9 +1217,7 @@ def _formsemestre_bulletinetud_header_html(
|
||||||
"""
|
"""
|
||||||
% (
|
% (
|
||||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"]),
|
||||||
etud, title="fiche de " + etud["nom"], REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
|
|
|
@ -52,6 +52,9 @@ import reportlab
|
||||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||||
|
|
||||||
|
from flask import request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_exceptions import NoteProcessError
|
from app.scodoc.sco_exceptions import NoteProcessError
|
||||||
from app import log
|
from app import log
|
||||||
|
@ -148,14 +151,7 @@ class BulletinGenerator(object):
|
||||||
def get_filename(self):
|
def get_filename(self):
|
||||||
"""Build a filename to be proposed to the web client"""
|
"""Build a filename to be proposed to the web client"""
|
||||||
sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"])
|
||||||
dt = time.strftime("%Y-%m-%d")
|
return scu.bul_filename(sem, self.infos["etud"], "pdf")
|
||||||
filename = "bul-%s-%s-%s.pdf" % (
|
|
||||||
sem["titre_num"],
|
|
||||||
dt,
|
|
||||||
self.infos["etud"]["nom"],
|
|
||||||
)
|
|
||||||
filename = scu.unescape_html(filename).replace(" ", "_").replace("&", "")
|
|
||||||
return filename
|
|
||||||
|
|
||||||
def generate(self, format="", stand_alone=True):
|
def generate(self, format="", stand_alone=True):
|
||||||
"""Return bulletin in specified format"""
|
"""Return bulletin in specified format"""
|
||||||
|
@ -260,7 +256,6 @@ def make_formsemestre_bulletinetud(
|
||||||
version="long", # short, long, selectedevals
|
version="long", # short, long, selectedevals
|
||||||
format="pdf", # html, pdf
|
format="pdf", # html, pdf
|
||||||
stand_alone=True,
|
stand_alone=True,
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Bulletin de notes
|
"""Bulletin de notes
|
||||||
|
|
||||||
|
@ -286,10 +281,10 @@ def make_formsemestre_bulletinetud(
|
||||||
PDFLOCK.acquire()
|
PDFLOCK.acquire()
|
||||||
bul_generator = gen_class(
|
bul_generator = gen_class(
|
||||||
infos,
|
infos,
|
||||||
authuser=REQUEST.AUTHENTICATED_USER,
|
authuser=current_user,
|
||||||
version=version,
|
version=version,
|
||||||
filigranne=infos["filigranne"],
|
filigranne=infos["filigranne"],
|
||||||
server_name=REQUEST.BASE0,
|
server_name=request.url_root,
|
||||||
)
|
)
|
||||||
if format not in bul_generator.supported_formats:
|
if format not in bul_generator.supported_formats:
|
||||||
# use standard generator
|
# use standard generator
|
||||||
|
@ -301,10 +296,10 @@ def make_formsemestre_bulletinetud(
|
||||||
gen_class = bulletin_get_class(bul_class_name)
|
gen_class = bulletin_get_class(bul_class_name)
|
||||||
bul_generator = gen_class(
|
bul_generator = gen_class(
|
||||||
infos,
|
infos,
|
||||||
authuser=REQUEST.AUTHENTICATED_USER,
|
authuser=current_user,
|
||||||
version=version,
|
version=version,
|
||||||
filigranne=infos["filigranne"],
|
filigranne=infos["filigranne"],
|
||||||
server_name=REQUEST.BASE0,
|
server_name=request.url_root,
|
||||||
)
|
)
|
||||||
|
|
||||||
data = bul_generator.generate(format=format, stand_alone=stand_alone)
|
data = bul_generator.generate(format=format, stand_alone=stand_alone)
|
||||||
|
|
|
@ -47,27 +47,22 @@ from app.scodoc import sco_etud
|
||||||
|
|
||||||
|
|
||||||
def make_json_formsemestre_bulletinetud(
|
def make_json_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre_id: int,
|
||||||
etudid,
|
etudid: int,
|
||||||
REQUEST=None,
|
|
||||||
xml_with_decisions=False,
|
xml_with_decisions=False,
|
||||||
version="long",
|
version="long",
|
||||||
force_publishing=False, # force publication meme si semestre non publie sur "portail"
|
force_publishing=False, # force publication meme si semestre non publie sur "portail"
|
||||||
):
|
) -> str:
|
||||||
"""Renvoie bulletin en chaine JSON"""
|
"""Renvoie bulletin en chaine JSON"""
|
||||||
|
|
||||||
d = formsemestre_bulletinetud_published_dict(
|
d = formsemestre_bulletinetud_published_dict(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
etudid,
|
etudid,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
REQUEST=REQUEST,
|
|
||||||
xml_with_decisions=xml_with_decisions,
|
xml_with_decisions=xml_with_decisions,
|
||||||
version=version,
|
version=version,
|
||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
|
||||||
|
|
||||||
return json.dumps(d, cls=scu.ScoDocJSONEncoder)
|
return json.dumps(d, cls=scu.ScoDocJSONEncoder)
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +74,6 @@ def formsemestre_bulletinetud_published_dict(
|
||||||
etudid,
|
etudid,
|
||||||
force_publishing=False,
|
force_publishing=False,
|
||||||
xml_nodate=False,
|
xml_nodate=False,
|
||||||
REQUEST=None,
|
|
||||||
xml_with_decisions=False, # inclue les decisions même si non publiées
|
xml_with_decisions=False, # inclue les decisions même si non publiées
|
||||||
version="long",
|
version="long",
|
||||||
):
|
):
|
||||||
|
|
|
@ -58,7 +58,7 @@ import traceback
|
||||||
|
|
||||||
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
|
@ -193,7 +193,7 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, REQUEST, version="selectedev
|
||||||
#
|
#
|
||||||
infos = {"DeptName": sco_preferences.get_preference("DeptName", formsemestre_id)}
|
infos = {"DeptName": sco_preferences.get_preference("DeptName", formsemestre_id)}
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
server_name = REQUEST.BASE0
|
server_name = request.url_root
|
||||||
else:
|
else:
|
||||||
server_name = ""
|
server_name = ""
|
||||||
try:
|
try:
|
||||||
|
@ -243,7 +243,7 @@ def get_etud_bulletins_pdf(etudid, REQUEST, version="selectedevals"):
|
||||||
i = i + 1
|
i = i + 1
|
||||||
infos = {"DeptName": sco_preferences.get_preference("DeptName")}
|
infos = {"DeptName": sco_preferences.get_preference("DeptName")}
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
server_name = REQUEST.BASE0
|
server_name = request.url_root
|
||||||
else:
|
else:
|
||||||
server_name = ""
|
server_name = ""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -69,16 +69,13 @@ def make_xml_formsemestre_bulletinetud(
|
||||||
doc=None, # XML document
|
doc=None, # XML document
|
||||||
force_publishing=False,
|
force_publishing=False,
|
||||||
xml_nodate=False,
|
xml_nodate=False,
|
||||||
REQUEST=None,
|
|
||||||
xml_with_decisions=False, # inclue les decisions même si non publiées
|
xml_with_decisions=False, # inclue les decisions même si non publiées
|
||||||
version="long",
|
version="long",
|
||||||
):
|
) -> str:
|
||||||
"bulletin au format XML"
|
"bulletin au format XML"
|
||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
|
|
||||||
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
||||||
if REQUEST:
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
if (not sem["bul_hide_xml"]) or force_publishing:
|
if (not sem["bul_hide_xml"]) or force_publishing:
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
(coût théorique en heures équivalent TD)
|
(coût théorique en heures équivalent TD)
|
||||||
"""
|
"""
|
||||||
|
from flask import request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
|
@ -182,7 +184,7 @@ def formsemestre_estim_cost(
|
||||||
<br/>
|
<br/>
|
||||||
</form>
|
</form>
|
||||||
""" % (
|
""" % (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
n_group_td,
|
n_group_td,
|
||||||
n_group_tp,
|
n_group_tp,
|
||||||
|
@ -190,11 +192,11 @@ def formsemestre_estim_cost(
|
||||||
)
|
)
|
||||||
tab.html_before_table = h
|
tab.html_before_table = h
|
||||||
tab.base_url = "%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s" % (
|
tab.base_url = "%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s" % (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
n_group_td,
|
n_group_td,
|
||||||
n_group_tp,
|
n_group_tp,
|
||||||
coef_tp,
|
coef_tp,
|
||||||
)
|
)
|
||||||
|
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
|
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
|
||||||
"""
|
"""
|
||||||
import http
|
import http
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -47,10 +47,10 @@ from app.scodoc import sco_etud
|
||||||
import sco_version
|
import sco_version
|
||||||
|
|
||||||
|
|
||||||
def report_debouche_date(start_year=None, format="html", REQUEST=None):
|
def report_debouche_date(start_year=None, format="html"):
|
||||||
"""Rapport (table) pour les débouchés des étudiants sortis à partir de l'année indiquée."""
|
"""Rapport (table) pour les débouchés des étudiants sortis à partir de l'année indiquée."""
|
||||||
if not start_year:
|
if not start_year:
|
||||||
return report_debouche_ask_date(REQUEST=REQUEST)
|
return report_debouche_ask_date()
|
||||||
if format == "xls":
|
if format == "xls":
|
||||||
keep_numeric = True # pas de conversion des notes en strings
|
keep_numeric = True # pas de conversion des notes en strings
|
||||||
else:
|
else:
|
||||||
|
@ -64,13 +64,12 @@ def report_debouche_date(start_year=None, format="html", REQUEST=None):
|
||||||
"Généré par %s le " % sco_version.SCONAME + scu.timedate_human_repr() + ""
|
"Généré par %s le " % sco_version.SCONAME + scu.timedate_human_repr() + ""
|
||||||
)
|
)
|
||||||
tab.caption = "Récapitulatif débouchés à partir du 1/1/%s." % start_year
|
tab.caption = "Récapitulatif débouchés à partir du 1/1/%s." % start_year
|
||||||
tab.base_url = "%s?start_year=%s" % (REQUEST.URL0, start_year)
|
tab.base_url = "%s?start_year=%s" % (request.base_url, start_year)
|
||||||
return tab.make_page(
|
return tab.make_page(
|
||||||
title="""<h2 class="formsemestre">Débouchés étudiants </h2>""",
|
title="""<h2 class="formsemestre">Débouchés étudiants </h2>""",
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=["js/etud_info.js"],
|
javascripts=["js/etud_info.js"],
|
||||||
format=format,
|
format=format,
|
||||||
REQUEST=REQUEST,
|
|
||||||
with_html_headers=True,
|
with_html_headers=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -194,7 +193,7 @@ def table_debouche_etudids(etudids, keep_numeric=True):
|
||||||
return tab
|
return tab
|
||||||
|
|
||||||
|
|
||||||
def report_debouche_ask_date(REQUEST=None):
|
def report_debouche_ask_date():
|
||||||
"""Formulaire demande date départ"""
|
"""Formulaire demande date départ"""
|
||||||
return (
|
return (
|
||||||
html_sco_header.sco_header()
|
html_sco_header.sco_header()
|
||||||
|
@ -249,7 +248,7 @@ def itemsuivi_get(cnx, itemsuivi_id, ignore_errors=False):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_suppress(itemsuivi_id, REQUEST=None):
|
def itemsuivi_suppress(itemsuivi_id):
|
||||||
"""Suppression d'un item"""
|
"""Suppression d'un item"""
|
||||||
if not sco_permissions_check.can_edit_suivi():
|
if not sco_permissions_check.can_edit_suivi():
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
@ -259,9 +258,10 @@ def itemsuivi_suppress(itemsuivi_id, REQUEST=None):
|
||||||
_itemsuivi_delete(cnx, itemsuivi_id)
|
_itemsuivi_delete(cnx, itemsuivi_id)
|
||||||
logdb(cnx, method="itemsuivi_suppress", etudid=item["etudid"])
|
logdb(cnx, method="itemsuivi_suppress", etudid=item["etudid"])
|
||||||
log("suppressed itemsuivi %s" % (itemsuivi_id,))
|
log("suppressed itemsuivi %s" % (itemsuivi_id,))
|
||||||
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_create(etudid, item_date=None, situation="", REQUEST=None, format=None):
|
def itemsuivi_create(etudid, item_date=None, situation="", format=None):
|
||||||
"""Creation d'un item"""
|
"""Creation d'un item"""
|
||||||
if not sco_permissions_check.can_edit_suivi():
|
if not sco_permissions_check.can_edit_suivi():
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
@ -273,11 +273,11 @@ def itemsuivi_create(etudid, item_date=None, situation="", REQUEST=None, format=
|
||||||
log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
|
log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
|
||||||
item = itemsuivi_get(cnx, itemsuivi_id)
|
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||||
if format == "json":
|
if format == "json":
|
||||||
return scu.sendJSON(REQUEST, item)
|
return scu.sendJSON(item)
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_set_date(itemsuivi_id, item_date, REQUEST=None):
|
def itemsuivi_set_date(itemsuivi_id, item_date):
|
||||||
"""set item date
|
"""set item date
|
||||||
item_date is a string dd/mm/yyyy
|
item_date is a string dd/mm/yyyy
|
||||||
"""
|
"""
|
||||||
|
@ -288,9 +288,10 @@ def itemsuivi_set_date(itemsuivi_id, item_date, REQUEST=None):
|
||||||
item = itemsuivi_get(cnx, itemsuivi_id)
|
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||||
item["item_date"] = item_date
|
item["item_date"] = item_date
|
||||||
_itemsuivi_edit(cnx, item)
|
_itemsuivi_edit(cnx, item)
|
||||||
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_set_situation(object, value, REQUEST=None):
|
def itemsuivi_set_situation(object, value):
|
||||||
"""set situation"""
|
"""set situation"""
|
||||||
if not sco_permissions_check.can_edit_suivi():
|
if not sco_permissions_check.can_edit_suivi():
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
@ -304,14 +305,14 @@ def itemsuivi_set_situation(object, value, REQUEST=None):
|
||||||
return situation or scu.IT_SITUATION_MISSING_STR
|
return situation or scu.IT_SITUATION_MISSING_STR
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_list_etud(etudid, format=None, REQUEST=None):
|
def itemsuivi_list_etud(etudid, format=None):
|
||||||
"""Liste des items pour cet étudiant, avec tags"""
|
"""Liste des items pour cet étudiant, avec tags"""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
items = _itemsuivi_list(cnx, {"etudid": etudid})
|
items = _itemsuivi_list(cnx, {"etudid": etudid})
|
||||||
for it in items:
|
for it in items:
|
||||||
it["tags"] = ", ".join(itemsuivi_tag_list(it["itemsuivi_id"]))
|
it["tags"] = ", ".join(itemsuivi_tag_list(it["itemsuivi_id"]))
|
||||||
if format == "json":
|
if format == "json":
|
||||||
return scu.sendJSON(REQUEST, items)
|
return scu.sendJSON(items)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,7 +329,7 @@ def itemsuivi_tag_list(itemsuivi_id):
|
||||||
return [x["title"] for x in r]
|
return [x["title"] for x in r]
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_tag_search(term, REQUEST=None):
|
def itemsuivi_tag_search(term):
|
||||||
"""List all used tag names (for auto-completion)"""
|
"""List all used tag names (for auto-completion)"""
|
||||||
# restrict charset to avoid injections
|
# restrict charset to avoid injections
|
||||||
if not scu.ALPHANUM_EXP.match(term):
|
if not scu.ALPHANUM_EXP.match(term):
|
||||||
|
@ -343,10 +344,10 @@ def itemsuivi_tag_search(term, REQUEST=None):
|
||||||
)
|
)
|
||||||
data = [x["title"] for x in r]
|
data = [x["title"] for x in r]
|
||||||
|
|
||||||
return scu.sendJSON(REQUEST, data)
|
return scu.sendJSON(data)
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_tag_set(itemsuivi_id="", taglist=[], REQUEST=None):
|
def itemsuivi_tag_set(itemsuivi_id="", taglist=None):
|
||||||
"""taglist may either be:
|
"""taglist may either be:
|
||||||
a string with tag names separated by commas ("un;deux")
|
a string with tag names separated by commas ("un;deux")
|
||||||
or a list of strings (["un", "deux"])
|
or a list of strings (["un", "deux"])
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"""Page accueil département (liste des semestres, etc)
|
"""Page accueil département (liste des semestres, etc)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import g
|
from flask import g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app
|
import app
|
||||||
|
@ -131,7 +131,7 @@ def index_html(REQUEST=None, showcodes=0, showsemtable=0):
|
||||||
if not showsemtable:
|
if not showsemtable:
|
||||||
H.append(
|
H.append(
|
||||||
'<hr/><p><a href="%s?showsemtable=1">Voir tous les semestres</a></p>'
|
'<hr/><p><a href="%s?showsemtable=1">Voir tous les semestres</a></p>'
|
||||||
% REQUEST.URL0
|
% request.base_url
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -242,7 +242,7 @@ def _sem_table_gt(sems, showcodes=False):
|
||||||
rows=sems,
|
rows=sems,
|
||||||
html_class="table_leftalign semlist",
|
html_class="table_leftalign semlist",
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
# base_url = '%s?formsemestre_id=%s' % (REQUEST.URL0, formsemestre_id),
|
# base_url = '%s?formsemestre_id=%s' % (request.base_url, formsemestre_id),
|
||||||
# caption='Maquettes enregistrées',
|
# caption='Maquettes enregistrées',
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -51,6 +51,7 @@ import fcntl
|
||||||
import subprocess
|
import subprocess
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -64,7 +65,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
||||||
SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
||||||
|
|
||||||
|
|
||||||
def sco_dump_and_send_db(REQUEST=None):
|
def sco_dump_and_send_db():
|
||||||
"""Dump base de données et l'envoie anonymisée pour debug"""
|
"""Dump base de données et l'envoie anonymisée pour debug"""
|
||||||
H = [html_sco_header.sco_header(page_title="Assistance technique")]
|
H = [html_sco_header.sco_header(page_title="Assistance technique")]
|
||||||
# get currect (dept) DB name:
|
# get currect (dept) DB name:
|
||||||
|
@ -93,7 +94,7 @@ def sco_dump_and_send_db(REQUEST=None):
|
||||||
_anonymize_db(ano_db_name)
|
_anonymize_db(ano_db_name)
|
||||||
|
|
||||||
# Send
|
# Send
|
||||||
r = _send_db(REQUEST, ano_db_name)
|
r = _send_db(ano_db_name)
|
||||||
if (
|
if (
|
||||||
r.status_code
|
r.status_code
|
||||||
== requests.codes.INSUFFICIENT_STORAGE # pylint: disable=no-member
|
== requests.codes.INSUFFICIENT_STORAGE # pylint: disable=no-member
|
||||||
|
@ -171,29 +172,27 @@ def _get_scodoc_serial():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _send_db(REQUEST, ano_db_name):
|
def _send_db(ano_db_name):
|
||||||
"""Dump this (anonymized) database and send it to tech support"""
|
"""Dump this (anonymized) database and send it to tech support"""
|
||||||
log("dumping anonymized database {}".format(ano_db_name))
|
log(f"dumping anonymized database {ano_db_name}")
|
||||||
try:
|
try:
|
||||||
data = subprocess.check_output("pg_dump {} | gzip".format(ano_db_name), shell=1)
|
dump = subprocess.check_output(
|
||||||
except subprocess.CalledProcessError as e:
|
f"pg_dump --format=custom {ano_db_name}", shell=1
|
||||||
log("sco_dump_and_send_db: exception in anonymisation: {}".format(e))
|
|
||||||
raise ScoValueError(
|
|
||||||
"erreur lors de l'anonymisation de la base {}".format(ano_db_name)
|
|
||||||
)
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log(f"sco_dump_and_send_db: exception in anonymisation: {e}")
|
||||||
|
raise ScoValueError(f"erreur lors de l'anonymisation de la base {ano_db_name}")
|
||||||
|
|
||||||
log("uploading anonymized dump...")
|
log("uploading anonymized dump...")
|
||||||
files = {"file": (ano_db_name + ".gz", data)}
|
files = {"file": (ano_db_name + ".dump", dump)}
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
scu.SCO_DUMP_UP_URL,
|
scu.SCO_DUMP_UP_URL,
|
||||||
files=files,
|
files=files,
|
||||||
data={
|
data={
|
||||||
"dept_name": sco_preferences.get_preference("DeptName"),
|
"dept_name": sco_preferences.get_preference("DeptName"),
|
||||||
"serial": _get_scodoc_serial(),
|
"serial": _get_scodoc_serial(),
|
||||||
"sco_user": str(REQUEST.AUTHENTICATED_USER),
|
"sco_user": str(current_user),
|
||||||
"sent_by": sco_users.user_info(str(REQUEST.AUTHENTICATED_USER))[
|
"sent_by": sco_users.user_info(str(current_user))["nomcomplet"],
|
||||||
"nomcomplet"
|
|
||||||
],
|
|
||||||
"sco_version": sco_version.SCOVERSION,
|
"sco_version": sco_version.SCOVERSION,
|
||||||
"sco_fullversion": scu.get_scodoc_version(),
|
"sco_fullversion": scu.get_scodoc_version(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -47,7 +47,7 @@ from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_news
|
from app.scodoc import sco_news
|
||||||
|
|
||||||
|
|
||||||
def formation_delete(formation_id=None, dialog_confirmed=False, REQUEST=None):
|
def formation_delete(formation_id=None, dialog_confirmed=False):
|
||||||
"""Delete a formation"""
|
"""Delete a formation"""
|
||||||
F = sco_formations.formation_list(args={"formation_id": formation_id})
|
F = sco_formations.formation_list(args={"formation_id": formation_id})
|
||||||
if not F:
|
if not F:
|
||||||
|
@ -159,7 +159,7 @@ def formation_edit(formation_id=None, create=False, REQUEST=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("formation_id", {"default": formation_id, "input_type": "hidden"}),
|
("formation_id", {"default": formation_id, "input_type": "hidden"}),
|
||||||
|
@ -311,7 +311,7 @@ def invalidate_sems_in_formation(formation_id):
|
||||||
) # > formation modif.
|
) # > formation modif.
|
||||||
|
|
||||||
|
|
||||||
def module_move(module_id, after=0, REQUEST=None, redirect=1):
|
def module_move(module_id, after=0, redirect=1):
|
||||||
"""Move before/after previous one (decrement/increment numero)"""
|
"""Move before/after previous one (decrement/increment numero)"""
|
||||||
module = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
module = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -116,7 +116,7 @@ associé.
|
||||||
</p>""",
|
</p>""",
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("ue_id", {"input_type": "hidden", "default": ue_id}),
|
("ue_id", {"input_type": "hidden", "default": ue_id}),
|
||||||
|
@ -202,7 +202,7 @@ def matiere_delete(matiere_id=None, REQUEST=None):
|
||||||
]
|
]
|
||||||
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + str(UE["formation_id"])
|
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + str(UE["formation_id"])
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("matiere_id", {"input_type": "hidden"}),),
|
(("matiere_id", {"input_type": "hidden"}),),
|
||||||
initvalues=M,
|
initvalues=M,
|
||||||
|
@ -256,7 +256,7 @@ des notes.</em>
|
||||||
associé.
|
associé.
|
||||||
</p>"""
|
</p>"""
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("matiere_id", {"input_type": "hidden"}),
|
("matiere_id", {"input_type": "hidden"}),
|
||||||
|
@ -323,4 +323,4 @@ def matiere_is_locked(matiere_id):
|
||||||
""",
|
""",
|
||||||
{"matiere_id": matiere_id},
|
{"matiere_id": matiere_id},
|
||||||
)
|
)
|
||||||
return len(r) > 0
|
return len(r) > 0
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -143,7 +144,7 @@ def module_create(matiere_id=None, REQUEST=None):
|
||||||
else:
|
else:
|
||||||
default_num = 10
|
default_num = 10
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -258,12 +259,13 @@ def do_module_delete(oid):
|
||||||
# S'il y a des moduleimpls, on ne peut pas detruire le module !
|
# S'il y a des moduleimpls, on ne peut pas detruire le module !
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(module_id=oid)
|
mods = sco_moduleimpl.do_moduleimpl_list(module_id=oid)
|
||||||
if mods:
|
if mods:
|
||||||
err_page = scu.confirm_dialog(
|
err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
|
||||||
message="""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>""",
|
<p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
||||||
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.""",
|
laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
||||||
dest_url="ue_list",
|
</p>
|
||||||
parameters={"formation_id": mod["formation_id"]},
|
<a href="{url_for('notes.ue_list', scodoc_dept=g.scodoc_dept,
|
||||||
)
|
formation_id=mod["formation_id"])}">reprendre</a>
|
||||||
|
"""
|
||||||
raise ScoGenError(err_page)
|
raise ScoGenError(err_page)
|
||||||
# delete
|
# delete
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
|
@ -294,7 +296,7 @@ def module_delete(module_id=None, REQUEST=None):
|
||||||
|
|
||||||
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + str(Mod["formation_id"])
|
dest_url = scu.NotesURL() + "/ue_list?formation_id=" + str(Mod["formation_id"])
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("module_id", {"input_type": "hidden"}),),
|
(("module_id", {"input_type": "hidden"}),),
|
||||||
initvalues=Mod,
|
initvalues=Mod,
|
||||||
|
@ -388,7 +390,7 @@ def module_edit(module_id=None, REQUEST=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -544,7 +546,7 @@ def module_list(formation_id, REQUEST=None):
|
||||||
% F,
|
% F,
|
||||||
'<ul class="notes_module_list">',
|
'<ul class="notes_module_list">',
|
||||||
]
|
]
|
||||||
editable = REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoChangeFormation)
|
editable = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
|
|
||||||
for Mod in do_module_list(args={"formation_id": formation_id}):
|
for Mod in do_module_list(args={"formation_id": formation_id}):
|
||||||
H.append('<li class="notes_module_list">%s' % Mod)
|
H.append('<li class="notes_module_list">%s' % Mod)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -326,7 +326,11 @@ def ue_edit(ue_id=None, create=False, formation_id=None, REQUEST=None):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0, REQUEST.form, fw, initvalues=initvalues, submitlabel=submitlabel
|
request.base_url,
|
||||||
|
REQUEST.form,
|
||||||
|
fw,
|
||||||
|
initvalues=initvalues,
|
||||||
|
submitlabel=submitlabel,
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
X = """<div id="ue_list_code"></div>
|
X = """<div id="ue_list_code"></div>
|
||||||
|
@ -1033,13 +1037,13 @@ def formation_table_recap(formation_id, format="html", REQUEST=None):
|
||||||
caption=title,
|
caption=title,
|
||||||
html_caption=title,
|
html_caption=title,
|
||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
base_url="%s?formation_id=%s" % (REQUEST.URL0, formation_id),
|
base_url="%s?formation_id=%s" % (request.base_url, formation_id),
|
||||||
page_title=title,
|
page_title=title,
|
||||||
html_title="<h2>" + title + "</h2>",
|
html_title="<h2>" + title + "</h2>",
|
||||||
pdf_title=title,
|
pdf_title=title,
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def ue_list_semestre_ids(ue):
|
def ue_list_semestre_ids(ue):
|
||||||
|
|
|
@ -149,7 +149,7 @@ def group_edt_json(group_id, start="", end="", REQUEST=None): # actuellement in
|
||||||
}
|
}
|
||||||
J.append(d)
|
J.append(d)
|
||||||
|
|
||||||
return scu.sendJSON(REQUEST, J)
|
return scu.sendJSON(J)
|
||||||
|
|
||||||
|
|
||||||
"""XXX
|
"""XXX
|
||||||
|
|
|
@ -32,11 +32,11 @@
|
||||||
Voir sco_apogee_csv.py pour la structure du fichier Apogée.
|
Voir sco_apogee_csv.py pour la structure du fichier Apogée.
|
||||||
|
|
||||||
Stockage: utilise sco_archive.py
|
Stockage: utilise sco_archive.py
|
||||||
=> /opt/scodoc/var/scodoc/archives/apo_csv/RT/2016-1/2016-07-03-16-12-19/V3ASR.csv
|
=> /opt/scodoc/var/scodoc/archives/apo_csv/<dept_id>/2016-1/2016-07-03-16-12-19/V3ASR.csv
|
||||||
pour une maquette de l'année scolaire 2016, semestre 1, etape V3ASR
|
pour une maquette de l'année scolaire 2016, semestre 1, etape V3ASR
|
||||||
|
|
||||||
ou bien (à partir de ScoDoc 1678) :
|
ou bien (à partir de ScoDoc 1678) :
|
||||||
/opt/scodoc/var/scodoc/archives/apo_csv/RT/2016-1/2016-07-03-16-12-19/V3ASR!111.csv
|
/opt/scodoc/var/scodoc/archives/apo_csv/<dept_id>/2016-1/2016-07-03-16-12-19/V3ASR!111.csv
|
||||||
pour une maquette de l'étape V3ASR version VDI 111.
|
pour une maquette de l'étape V3ASR version VDI 111.
|
||||||
|
|
||||||
La version VDI sera ignorée sauf si elle est indiquée dans l'étape du semestre.
|
La version VDI sera ignorée sauf si elle est indiquée dans l'étape du semestre.
|
||||||
|
|
|
@ -32,7 +32,7 @@ import io
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, send_file
|
from flask import url_for, g, send_file, request
|
||||||
|
|
||||||
# from werkzeug.utils import send_file
|
# from werkzeug.utils import send_file
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ def apo_semset_maq_status(
|
||||||
"""<form name="f" method="get" action="%s">
|
"""<form name="f" method="get" action="%s">
|
||||||
<input type="hidden" name="semset_id" value="%s"></input>
|
<input type="hidden" name="semset_id" value="%s"></input>
|
||||||
<div><input type="checkbox" name="allow_missing_apo" value="1" onchange="document.f.submit()" """
|
<div><input type="checkbox" name="allow_missing_apo" value="1" onchange="document.f.submit()" """
|
||||||
% (REQUEST.URL0, semset_id)
|
% (request.base_url, semset_id)
|
||||||
)
|
)
|
||||||
if allow_missing_apo:
|
if allow_missing_apo:
|
||||||
H.append("checked")
|
H.append("checked")
|
||||||
|
@ -476,7 +476,7 @@ def table_apo_csv_list(semset, REQUEST=None):
|
||||||
rows=T,
|
rows=T,
|
||||||
html_class="table_leftalign apo_maq_list",
|
html_class="table_leftalign apo_maq_list",
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
# base_url = '%s?formsemestre_id=%s' % (REQUEST.URL0, formsemestre_id),
|
# base_url = '%s?formsemestre_id=%s' % (request.base_url, formsemestre_id),
|
||||||
# caption='Maquettes enregistrées',
|
# caption='Maquettes enregistrées',
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
@ -578,7 +578,7 @@ def _view_etuds_page(
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
|
|
||||||
|
@ -678,7 +678,8 @@ def view_apo_csv(etape_apo="", semset_id="", format="html", REQUEST=None):
|
||||||
sem_id = semset["sem_id"]
|
sem_id = semset["sem_id"]
|
||||||
csv_data = sco_etape_apogee.apo_csv_get(etape_apo, annee_scolaire, sem_id)
|
csv_data = sco_etape_apogee.apo_csv_get(etape_apo, annee_scolaire, sem_id)
|
||||||
if format == "raw":
|
if format == "raw":
|
||||||
return scu.sendCSVFile(REQUEST, csv_data, etape_apo + ".txt")
|
scu.send_file(csv_data, etape_apo, suffix=".txt", mime=scu.CSV_MIMETYPE)
|
||||||
|
|
||||||
apo_data = sco_apogee_csv.ApoData(csv_data, periode=semset["sem_id"])
|
apo_data = sco_apogee_csv.ApoData(csv_data, periode=semset["sem_id"])
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -746,14 +747,15 @@ def view_apo_csv(etape_apo="", semset_id="", format="html", REQUEST=None):
|
||||||
rows=etuds,
|
rows=etuds,
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
html_class="table_leftalign apo_maq_table",
|
html_class="table_leftalign apo_maq_table",
|
||||||
base_url="%s?etape_apo=%s&semset_id=%s" % (REQUEST.URL0, etape_apo, semset_id),
|
base_url="%s?etape_apo=%s&semset_id=%s"
|
||||||
|
% (request.base_url, etape_apo, semset_id),
|
||||||
filename="students_" + etape_apo,
|
filename="students_" + etape_apo,
|
||||||
caption="Etudiants Apogée en " + etape_apo,
|
caption="Etudiants Apogée en " + etape_apo,
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
H += [
|
H += [
|
||||||
tab.html(),
|
tab.html(),
|
||||||
|
@ -768,7 +770,7 @@ def view_apo_csv(etape_apo="", semset_id="", format="html", REQUEST=None):
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
# called from Web
|
# called from Web (GET)
|
||||||
def apo_csv_export_results(
|
def apo_csv_export_results(
|
||||||
semset_id,
|
semset_id,
|
||||||
block_export_res_etape=False,
|
block_export_res_etape=False,
|
||||||
|
|
|
@ -31,27 +31,21 @@
|
||||||
# Ancien module "scolars"
|
# Ancien module "scolars"
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from flask import url_for, g, request
|
|
||||||
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
from email.header import Header
|
|
||||||
from email.mime.base import MIMEBase
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
|
from flask import url_for, g, request
|
||||||
|
from flask_mail import Message
|
||||||
|
|
||||||
|
from app import email
|
||||||
|
from app import log
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import SCO_ENCODING
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
|
from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
|
||||||
|
|
||||||
from app import log
|
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
|
||||||
from app.scodoc import safehtml
|
from app.scodoc import safehtml
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from flask_mail import Message
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app import mail
|
|
||||||
|
|
||||||
MONTH_NAMES_ABBREV = [
|
MONTH_NAMES_ABBREV = [
|
||||||
"Jan ",
|
"Jan ",
|
||||||
|
@ -256,7 +250,6 @@ _identiteEditor = ndb.EditableTable(
|
||||||
"photo_filename",
|
"photo_filename",
|
||||||
"code_ine",
|
"code_ine",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
"scodoc7_id",
|
|
||||||
),
|
),
|
||||||
filter_dept=True,
|
filter_dept=True,
|
||||||
sortkey="nom",
|
sortkey="nom",
|
||||||
|
@ -345,31 +338,33 @@ def _check_duplicate_code(
|
||||||
)
|
)
|
||||||
if etudid:
|
if etudid:
|
||||||
OK = "retour à la fiche étudiant"
|
OK = "retour à la fiche étudiant"
|
||||||
dest_url = "ficheEtud"
|
dest_endpoint = "scolar.ficheEtud"
|
||||||
parameters = {"etudid": etudid}
|
parameters = {"etudid": etudid}
|
||||||
else:
|
else:
|
||||||
if "tf_submitted" in args:
|
if "tf_submitted" in args:
|
||||||
del args["tf_submitted"]
|
del args["tf_submitted"]
|
||||||
OK = "Continuer"
|
OK = "Continuer"
|
||||||
dest_url = "etudident_create_form"
|
dest_endpoint = "scolar.etudident_create_form"
|
||||||
parameters = args
|
parameters = args
|
||||||
else:
|
else:
|
||||||
OK = "Annuler"
|
OK = "Annuler"
|
||||||
dest_url = ""
|
dest_endpoint = "notes.index_html"
|
||||||
parameters = {}
|
parameters = {}
|
||||||
if not disable_notify:
|
if not disable_notify:
|
||||||
err_page = scu.confirm_dialog(
|
err_page = f"""<h3><h3>Code étudiant ({code_name}) dupliqué !</h3>
|
||||||
message="""<h3>Code étudiant (%s) dupliqué !</h3>""" % code_name,
|
<p class="help">Le {code_name} {args[code_name]} est déjà utilisé: un seul étudiant peut avoir
|
||||||
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>"""
|
ce code. Vérifier votre valeur ou supprimer l'autre étudiant avec cette valeur.
|
||||||
% (code_name, args[code_name])
|
</p>
|
||||||
+ "</li><li>".join(listh)
|
<ul><li>
|
||||||
+ "</li></ul><p>",
|
{ '</li><li>'.join(listh) }
|
||||||
OK=OK,
|
</li></ul>
|
||||||
dest_url=dest_url,
|
<p>
|
||||||
parameters=parameters,
|
<a href="{ url_for(dest_endpoint, scodoc_dept=g.scodoc_dept, **parameters) }
|
||||||
)
|
">{OK}</a>
|
||||||
|
</p>
|
||||||
|
"""
|
||||||
else:
|
else:
|
||||||
err_page = """<h3>Code étudiant (%s) dupliqué !</h3>""" % code_name
|
err_page = f"""<h3>Code étudiant ({code_name}) dupliqué !</h3>"""
|
||||||
log("*** error: code %s duplique: %s" % (code_name, args[code_name]))
|
log("*** error: code %s duplique: %s" % (code_name, args[code_name]))
|
||||||
raise ScoGenError(err_page)
|
raise ScoGenError(err_page)
|
||||||
|
|
||||||
|
@ -456,7 +451,7 @@ def notify_etud_change(email_addr, etud, before, after, subject):
|
||||||
log("notify_etud_change: sending notification to %s" % email_addr)
|
log("notify_etud_change: sending notification to %s" % email_addr)
|
||||||
log("notify_etud_change: subject: %s" % subject)
|
log("notify_etud_change: subject: %s" % subject)
|
||||||
log(txt)
|
log(txt)
|
||||||
mail.send_email(
|
email.send_email(
|
||||||
subject, sco_preferences.get_preference("email_from_addr"), [email_addr], txt
|
subject, sco_preferences.get_preference("email_from_addr"), [email_addr], txt
|
||||||
)
|
)
|
||||||
return txt
|
return txt
|
||||||
|
@ -559,7 +554,6 @@ _admissionEditor = ndb.EditableTable(
|
||||||
"villelycee",
|
"villelycee",
|
||||||
"codepostallycee",
|
"codepostallycee",
|
||||||
"codelycee",
|
"codelycee",
|
||||||
"debouche",
|
|
||||||
"type_admission",
|
"type_admission",
|
||||||
"boursier_prec",
|
"boursier_prec",
|
||||||
),
|
),
|
||||||
|
@ -656,6 +650,12 @@ def make_etud_args(etudid=None, code_nip=None, use_request=True, raise_exc=True)
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def log_unknown_etud():
|
||||||
|
"""Log request: cas ou getEtudInfo n'a pas ramene de resultat"""
|
||||||
|
etud_args = make_etud_args(raise_exc=False)
|
||||||
|
log(f"unknown student: args={etud_args}")
|
||||||
|
|
||||||
|
|
||||||
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
|
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
|
||||||
"""infos sur un etudiant (API). If not foud, returns empty list.
|
"""infos sur un etudiant (API). If not foud, returns empty list.
|
||||||
On peut specifier etudid ou code_nip
|
On peut specifier etudid ou code_nip
|
||||||
|
|
|
@ -31,7 +31,7 @@ import datetime
|
||||||
import operator
|
import operator
|
||||||
import pprint
|
import pprint
|
||||||
import time
|
import time
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
import urllib
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
@ -274,13 +274,13 @@ def do_evaluation_create(
|
||||||
if args["jour"]:
|
if args["jour"]:
|
||||||
next_eval = None
|
next_eval = None
|
||||||
t = (
|
t = (
|
||||||
ndb.DateDMYtoISO(args["jour"]),
|
ndb.DateDMYtoISO(args["jour"], null_is_empty=True),
|
||||||
ndb.TimetoISO8601(args["heure_debut"]),
|
ndb.TimetoISO8601(args["heure_debut"], null_is_empty=True),
|
||||||
)
|
)
|
||||||
for e in ModEvals:
|
for e in ModEvals:
|
||||||
if (
|
if (
|
||||||
ndb.DateDMYtoISO(e["jour"]),
|
ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
ndb.TimetoISO8601(e["heure_debut"]),
|
ndb.TimetoISO8601(e["heure_debut"], null_is_empty=True),
|
||||||
) > t:
|
) > t:
|
||||||
next_eval = e
|
next_eval = e
|
||||||
break
|
break
|
||||||
|
@ -780,7 +780,6 @@ def formsemestre_evaluations_cal(formsemestre_id, REQUEST=None):
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Evaluations du semestre",
|
"Evaluations du semestre",
|
||||||
sem,
|
sem,
|
||||||
cssstyles=["css/calabs.css"],
|
cssstyles=["css/calabs.css"],
|
||||||
|
@ -915,13 +914,13 @@ def formsemestre_evaluations_delai_correction(
|
||||||
html_title="<h2>Correction des évaluations du semestre</h2>",
|
html_title="<h2>Correction des évaluations du semestre</h2>",
|
||||||
caption="Correction des évaluations du semestre",
|
caption="Correction des évaluations du semestre",
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
|
||||||
origin="Généré par %s le " % sco_version.SCONAME
|
origin="Généré par %s le " % sco_version.SCONAME
|
||||||
+ scu.timedate_human_repr()
|
+ scu.timedate_human_repr()
|
||||||
+ "",
|
+ "",
|
||||||
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def module_evaluation_insert_before(ModEvals, next_eval):
|
def module_evaluation_insert_before(ModEvals, next_eval):
|
||||||
|
@ -1089,7 +1088,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
||||||
% (
|
% (
|
||||||
scu.ScoURL(),
|
scu.ScoURL(),
|
||||||
group_id,
|
group_id,
|
||||||
six.moves.urllib.parse.quote(E["jour"], safe=""),
|
urllib.parse.quote(E["jour"], safe=""),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -1346,7 +1345,7 @@ def evaluation_create_form(
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
|
|
|
@ -35,11 +35,11 @@ from enum import Enum
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
import openpyxl.utils.datetime
|
import openpyxl.utils.datetime
|
||||||
|
from openpyxl.styles.numbers import FORMAT_NUMBER_00, FORMAT_GENERAL
|
||||||
|
from openpyxl.comments import Comment
|
||||||
from openpyxl import Workbook, load_workbook
|
from openpyxl import Workbook, load_workbook
|
||||||
from openpyxl.cell import WriteOnlyCell
|
from openpyxl.cell import WriteOnlyCell
|
||||||
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
|
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
|
||||||
from openpyxl.styles.numbers import FORMAT_NUMBER_00, FORMAT_GENERAL
|
|
||||||
from openpyxl.comments import Comment
|
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import notesdb
|
from app.scodoc import notesdb
|
||||||
|
@ -59,24 +59,9 @@ class COLORS(Enum):
|
||||||
LIGHT_YELLOW = "FFFFFF99"
|
LIGHT_YELLOW = "FFFFFF99"
|
||||||
|
|
||||||
|
|
||||||
def send_excel_file(request, data, filename, mime=scu.XLSX_MIMETYPE):
|
|
||||||
"""publication fichier.
|
|
||||||
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
|
||||||
"""
|
|
||||||
filename = (
|
|
||||||
scu.unescape_html(scu.suppress_accents(filename))
|
|
||||||
.replace("&", "")
|
|
||||||
.replace(" ", "_")
|
|
||||||
)
|
|
||||||
request.RESPONSE.setHeader("content-type", mime)
|
|
||||||
request.RESPONSE.setHeader(
|
|
||||||
"content-disposition", 'attachment; filename="%s"' % filename
|
|
||||||
)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
# Un style est enregistré comme un dictionnaire qui précise la valeur d'un attributdans la liste suivante:
|
# Un style est enregistré comme un dictionnaire qui précise la valeur d'un attributdans la liste suivante:
|
||||||
# font, border, number_format, fill, .. (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles)
|
# font, border, number_format, fill,...
|
||||||
|
# (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles)
|
||||||
|
|
||||||
|
|
||||||
def xldate_as_datetime(xldate, datemode=0):
|
def xldate_as_datetime(xldate, datemode=0):
|
||||||
|
@ -86,6 +71,17 @@ def xldate_as_datetime(xldate, datemode=0):
|
||||||
return openpyxl.utils.datetime.from_ISO8601(xldate)
|
return openpyxl.utils.datetime.from_ISO8601(xldate)
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_sheetname(sheet_name):
|
||||||
|
"""Renvoie un nom convenable pour une feuille excel: < 31 cars, sans caractères spéciaux
|
||||||
|
Le / n'est pas autorisé par exemple.
|
||||||
|
Voir https://xlsxwriter.readthedocs.io/workbook.html#add_worksheet
|
||||||
|
"""
|
||||||
|
sheet_name = scu.make_filename(sheet_name)
|
||||||
|
# Le nom de la feuille ne peut faire plus de 31 caractères.
|
||||||
|
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
|
||||||
|
return sheet_name[:31]
|
||||||
|
|
||||||
|
|
||||||
class ScoExcelBook:
|
class ScoExcelBook:
|
||||||
"""Permet la génération d'un classeur xlsx composé de plusieurs feuilles.
|
"""Permet la génération d'un classeur xlsx composé de plusieurs feuilles.
|
||||||
usage:
|
usage:
|
||||||
|
@ -98,13 +94,16 @@ class ScoExcelBook:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sheets = [] # list of sheets
|
self.sheets = [] # list of sheets
|
||||||
|
self.wb = Workbook(write_only=True)
|
||||||
|
|
||||||
def create_sheet(self, sheet_name="feuille", default_style=None):
|
def create_sheet(self, sheet_name="feuille", default_style=None):
|
||||||
"""Crée une nouvelle feuille dans ce classeur
|
"""Crée une nouvelle feuille dans ce classeur
|
||||||
sheet_name -- le nom de la feuille
|
sheet_name -- le nom de la feuille
|
||||||
default_style -- le style par défaut
|
default_style -- le style par défaut
|
||||||
"""
|
"""
|
||||||
sheet = ScoExcelSheet(sheet_name, default_style)
|
sheet_name = adjust_sheetname(sheet_name)
|
||||||
|
ws = self.wb.create_sheet(sheet_name)
|
||||||
|
sheet = ScoExcelSheet(sheet_name, default_style, ws)
|
||||||
self.sheets.append(sheet)
|
self.sheets.append(sheet)
|
||||||
return sheet
|
return sheet
|
||||||
|
|
||||||
|
@ -112,12 +111,12 @@ class ScoExcelBook:
|
||||||
"""génération d'un stream binaire représentant la totalité du classeur.
|
"""génération d'un stream binaire représentant la totalité du classeur.
|
||||||
retourne le flux
|
retourne le flux
|
||||||
"""
|
"""
|
||||||
wb = Workbook(write_only=True)
|
|
||||||
for sheet in self.sheets:
|
for sheet in self.sheets:
|
||||||
sheet.generate(self)
|
sheet.prepare()
|
||||||
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
|
# construction d'un flux
|
||||||
|
# (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
|
||||||
with NamedTemporaryFile() as tmp:
|
with NamedTemporaryFile() as tmp:
|
||||||
wb.save(tmp.name)
|
self.wb.save(tmp.name)
|
||||||
tmp.seek(0)
|
tmp.seek(0)
|
||||||
return tmp.read()
|
return tmp.read()
|
||||||
|
|
||||||
|
@ -125,6 +124,7 @@ class ScoExcelBook:
|
||||||
def excel_make_style(
|
def excel_make_style(
|
||||||
bold=False,
|
bold=False,
|
||||||
italic=False,
|
italic=False,
|
||||||
|
outline=False,
|
||||||
color: COLORS = COLORS.BLACK,
|
color: COLORS = COLORS.BLACK,
|
||||||
bgcolor: COLORS = None,
|
bgcolor: COLORS = None,
|
||||||
halign=None,
|
halign=None,
|
||||||
|
@ -145,7 +145,14 @@ def excel_make_style(
|
||||||
size -- taille de police
|
size -- taille de police
|
||||||
"""
|
"""
|
||||||
style = {}
|
style = {}
|
||||||
font = Font(name=font_name, bold=bold, italic=italic, color=color.value, size=size)
|
font = Font(
|
||||||
|
name=font_name,
|
||||||
|
bold=bold,
|
||||||
|
italic=italic,
|
||||||
|
outline=outline,
|
||||||
|
color=color.value,
|
||||||
|
size=size,
|
||||||
|
)
|
||||||
style["font"] = font
|
style["font"] = font
|
||||||
if bgcolor:
|
if bgcolor:
|
||||||
style["fill"] = PatternFill(fill_type="solid", fgColor=bgcolor.value)
|
style["fill"] = PatternFill(fill_type="solid", fgColor=bgcolor.value)
|
||||||
|
@ -182,41 +189,93 @@ class ScoExcelSheet:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sheet_name="feuille", default_style=None, wb=None):
|
def __init__(self, sheet_name="feuille", default_style=None, wb=None):
|
||||||
"""Création de la feuille.
|
"""Création de la feuille. sheet_name
|
||||||
sheet_name -- le nom de la feuille
|
-- le nom de la feuille default_style
|
||||||
default_style -- le style par défaut des cellules
|
-- le style par défaut des cellules ws
|
||||||
wb -- le WorkBook dans laquelle se trouve la feuille. Si wb est None (cas d'un classeur mono-feuille),
|
-- None si la feuille est autonome (dans ce cas ell crée son propre wb), sinon c'est la worksheet
|
||||||
un workbook est crée et associé à cette feuille.
|
créée par le workbook propriétaire un workbook est crée et associé à cette feuille.
|
||||||
"""
|
"""
|
||||||
# Le nom de la feuille ne peut faire plus de 31 caractères.
|
# Le nom de la feuille ne peut faire plus de 31 caractères.
|
||||||
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
|
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
|
||||||
self.sheet_name = sheet_name[
|
self.sheet_name = adjust_sheetname(sheet_name)
|
||||||
:31
|
|
||||||
] # if len(sheet_name) > 31: sheet_name = 'Feuille' ?
|
|
||||||
self.rows = [] # list of list of cells
|
|
||||||
# self.cells_styles_lico = {} # { (li,co) : style }
|
|
||||||
# self.cells_styles_li = {} # { li : style }
|
|
||||||
# self.cells_styles_co = {} # { co : style }
|
|
||||||
if default_style is None:
|
if default_style is None:
|
||||||
default_style = excel_make_style()
|
default_style = excel_make_style()
|
||||||
self.default_style = default_style
|
self.default_style = default_style
|
||||||
self.wb = wb or Workbook(write_only=True) # Création de workbook si nécessaire
|
if wb is None:
|
||||||
self.ws = self.wb.create_sheet(title=self.sheet_name)
|
self.wb = Workbook()
|
||||||
|
self.ws = self.wb.active
|
||||||
|
self.ws.title = self.sheet_name
|
||||||
|
else:
|
||||||
|
self.wb = None
|
||||||
|
self.ws = wb
|
||||||
|
# internal data
|
||||||
|
self.rows = [] # list of list of cells
|
||||||
self.column_dimensions = {}
|
self.column_dimensions = {}
|
||||||
|
self.row_dimensions = {}
|
||||||
|
|
||||||
def set_column_dimension_width(self, cle, value):
|
def excel_make_composite_style(
|
||||||
"""Détermine la largeur d'une colonne.
|
self,
|
||||||
cle -- identifie la colonne ("A"n "B", ...)
|
alignment=None,
|
||||||
value -- la dimension (unité : 7 pixels comme affiché dans Excel)
|
border=None,
|
||||||
|
fill=None,
|
||||||
|
number_format=None,
|
||||||
|
font=None,
|
||||||
|
):
|
||||||
|
style = {}
|
||||||
|
if font is not None:
|
||||||
|
style["font"] = font
|
||||||
|
if alignment is not None:
|
||||||
|
style["alignment"] = alignment
|
||||||
|
if border is not None:
|
||||||
|
style["border"] = border
|
||||||
|
if fill is not None:
|
||||||
|
style["fill"] = fill
|
||||||
|
if number_format is None:
|
||||||
|
style["number_format"] = FORMAT_GENERAL
|
||||||
|
else:
|
||||||
|
style["number_format"] = number_format
|
||||||
|
return style
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def i2col(idx):
|
||||||
|
if idx < 26: # one letter key
|
||||||
|
return chr(idx + 65)
|
||||||
|
else: # two letters AA..ZZ
|
||||||
|
first = (idx // 26) + 66
|
||||||
|
second = (idx % 26) + 65
|
||||||
|
return "" + chr(first) + chr(second)
|
||||||
|
|
||||||
|
def set_column_dimension_width(self, cle=None, value=21):
|
||||||
|
"""Détermine la largeur d'une colonne. cle -- identifie la colonne ("A" "B", ... ou 0, 1, 2, ...) si None,
|
||||||
|
value donne la liste des largeurs de colonnes depuis A, B, C, ... value -- la dimension (unité : 7 pixels
|
||||||
|
comme affiché dans Excel)
|
||||||
"""
|
"""
|
||||||
self.ws.column_dimensions[cle].width = value
|
if cle is None:
|
||||||
|
for i, val in enumerate(value):
|
||||||
|
self.ws.column_dimensions[self.i2col(i)].width = val
|
||||||
|
# No keys: value is a list of widths
|
||||||
|
elif type(cle) == str: # accepts set_column_with("D", ...)
|
||||||
|
self.ws.column_dimensions[cle].width = value
|
||||||
|
else:
|
||||||
|
self.ws.column_dimensions[self.i2col(cle)].width = value
|
||||||
|
|
||||||
def set_column_dimension_hidden(self, cle, value):
|
def set_row_dimension_height(self, cle=None, value=21):
|
||||||
"""Masque ou affiche une colonne.
|
"""Détermine la hauteur d'une ligne. cle -- identifie la ligne (1, 2, ...) si None,
|
||||||
cle -- identifie la colonne ("A"n "B", ...)
|
value donne la liste des hauteurs de colonnes depuis 1, 2, 3, ... value -- la dimension
|
||||||
|
"""
|
||||||
|
if cle is None:
|
||||||
|
for i, val in enumerate(value, start=1):
|
||||||
|
self.ws.row_dimensions[i].height = val
|
||||||
|
# No keys: value is a list of widths
|
||||||
|
else:
|
||||||
|
self.ws.row_dimensions[cle].height = value
|
||||||
|
|
||||||
|
def set_row_dimension_hidden(self, cle, value):
|
||||||
|
"""Masque ou affiche une ligne.
|
||||||
|
cle -- identifie la colonne (1...)
|
||||||
value -- boolean (vrai = colonne cachée)
|
value -- boolean (vrai = colonne cachée)
|
||||||
"""
|
"""
|
||||||
self.ws.column_dimensions[cle].hidden = value
|
self.ws.row_dimensions[cle].hidden = value
|
||||||
|
|
||||||
def make_cell(self, value: any = None, style=None, comment=None):
|
def make_cell(self, value: any = None, style=None, comment=None):
|
||||||
"""Construit une cellule.
|
"""Construit une cellule.
|
||||||
|
@ -232,8 +291,12 @@ class ScoExcelSheet:
|
||||||
style = self.default_style
|
style = self.default_style
|
||||||
if "font" in style:
|
if "font" in style:
|
||||||
cell.font = style["font"]
|
cell.font = style["font"]
|
||||||
|
if "alignment" in style:
|
||||||
|
cell.alignment = style["alignment"]
|
||||||
if "border" in style:
|
if "border" in style:
|
||||||
cell.border = style["border"]
|
cell.border = style["border"]
|
||||||
|
if "fill" in style:
|
||||||
|
cell.fill = style["fill"]
|
||||||
if "number_format" in style:
|
if "number_format" in style:
|
||||||
cell.number_format = style["number_format"]
|
cell.number_format = style["number_format"]
|
||||||
if "fill" in style:
|
if "fill" in style:
|
||||||
|
@ -272,73 +335,31 @@ class ScoExcelSheet:
|
||||||
"""ajoute une ligne déjà construite à la feuille."""
|
"""ajoute une ligne déjà construite à la feuille."""
|
||||||
self.rows.append(row)
|
self.rows.append(row)
|
||||||
|
|
||||||
# def set_style(self, style=None, li=None, co=None):
|
def prepare(self):
|
||||||
# if li is not None and co is not None:
|
|
||||||
# self.cells_styles_lico[(li, co)] = style
|
|
||||||
# elif li is None:
|
|
||||||
# self.cells_styles_li[li] = style
|
|
||||||
# elif co is None:
|
|
||||||
# self.cells_styles_co[co] = style
|
|
||||||
#
|
|
||||||
# def get_cell_style(self, li, co):
|
|
||||||
# """Get style for specified cell"""
|
|
||||||
# return (
|
|
||||||
# self.cells_styles_lico.get((li, co), None)
|
|
||||||
# or self.cells_styles_li.get(li, None)
|
|
||||||
# or self.cells_styles_co.get(co, None)
|
|
||||||
# or self.default_style
|
|
||||||
# )
|
|
||||||
|
|
||||||
def _generate_ws(self):
|
|
||||||
"""génére un flux décrivant la feuille.
|
"""génére un flux décrivant la feuille.
|
||||||
Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille)
|
Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille)
|
||||||
ou pour la génération d'un classeur multi-feuilles
|
ou pour la génération d'un classeur multi-feuilles
|
||||||
"""
|
"""
|
||||||
for col in self.column_dimensions.keys():
|
for row in self.column_dimensions.keys():
|
||||||
self.ws.column_dimensions[col] = self.column_dimensions[col]
|
self.ws.column_dimensions[row] = self.column_dimensions[row]
|
||||||
|
for row in self.row_dimensions.keys():
|
||||||
|
self.ws.row_dimensions[row] = self.row_dimensions[row]
|
||||||
for row in self.rows:
|
for row in self.rows:
|
||||||
self.ws.append(row)
|
self.ws.append(row)
|
||||||
|
|
||||||
def generate_standalone(self):
|
def generate(self):
|
||||||
"""génération d'un classeur mono-feuille"""
|
"""génération d'un classeur mono-feuille"""
|
||||||
self._generate_ws()
|
# this method makes sense only if it is a standalone worksheet (else call workbook.generate()
|
||||||
|
if self.wb is None: # embeded sheet
|
||||||
|
raise ScoValueError("can't generate a single sheet from a ScoWorkbook")
|
||||||
|
|
||||||
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
|
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
|
||||||
|
self.prepare()
|
||||||
with NamedTemporaryFile() as tmp:
|
with NamedTemporaryFile() as tmp:
|
||||||
self.wb.save(tmp.name)
|
self.wb.save(tmp.name)
|
||||||
tmp.seek(0)
|
tmp.seek(0)
|
||||||
return tmp.read()
|
return tmp.read()
|
||||||
|
|
||||||
def generate_embeded(self):
|
|
||||||
"""generation d'une feuille include dans un classeur multi-feuilles"""
|
|
||||||
self._generate_ws()
|
|
||||||
|
|
||||||
def gen_workbook(self, wb=None):
|
|
||||||
"""TODO: à remplacer"""
|
|
||||||
"""Generates and returns a workbook from stored data.
|
|
||||||
If wb, add a sheet (tab) to the existing workbook (in this case, returns None).
|
|
||||||
"""
|
|
||||||
if wb is None:
|
|
||||||
wb = Workbook() # Création du fichier
|
|
||||||
sauvegarde = True
|
|
||||||
else:
|
|
||||||
sauvegarde = False
|
|
||||||
ws0 = wb.add_sheet(self.sheet_name)
|
|
||||||
li = 0
|
|
||||||
for row in self.rows:
|
|
||||||
co = 0
|
|
||||||
for c in row:
|
|
||||||
# safety net: allow only str, int and float
|
|
||||||
# #py3 #sco8 A revoir lors de la ré-écriture de ce module
|
|
||||||
# XXX if type(c) not in (IntType, FloatType):
|
|
||||||
# c = str(c).decode(scu.SCO_ENCODING)
|
|
||||||
ws0.write(li, co, c, self.get_cell_style(li, co))
|
|
||||||
co += 1
|
|
||||||
li += 1
|
|
||||||
if sauvegarde:
|
|
||||||
return wb.savetostr()
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def excel_simple_table(
|
def excel_simple_table(
|
||||||
titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None
|
titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None
|
||||||
|
@ -377,7 +398,7 @@ def excel_simple_table(
|
||||||
cell_style = text_style
|
cell_style = text_style
|
||||||
cells.append(ws.make_cell(it, cell_style))
|
cells.append(ws.make_cell(it, cell_style))
|
||||||
ws.append_row(cells)
|
ws.append_row(cells)
|
||||||
return ws.generate_standalone()
|
return ws.generate()
|
||||||
|
|
||||||
|
|
||||||
def excel_feuille_saisie(e, titreannee, description, lines):
|
def excel_feuille_saisie(e, titreannee, description, lines):
|
||||||
|
@ -538,16 +559,28 @@ def excel_feuille_saisie(e, titreannee, description, lines):
|
||||||
ws.make_cell("cellule vide -> note non modifiée", style_expl),
|
ws.make_cell("cellule vide -> note non modifiée", style_expl),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return ws.generate_standalone()
|
return ws.generate()
|
||||||
|
|
||||||
|
|
||||||
def excel_bytes_to_list(bytes_content):
|
def excel_bytes_to_list(bytes_content):
|
||||||
filelike = io.BytesIO(bytes_content)
|
try:
|
||||||
return _excel_to_list(filelike)
|
filelike = io.BytesIO(bytes_content)
|
||||||
|
return _excel_to_list(filelike)
|
||||||
|
except:
|
||||||
|
raise ScoValueError("""
|
||||||
|
scolars_import_excel_file: un contenu xlsx semble corrompu!
|
||||||
|
peut-être avez vous fourni un fichier au mauvais format (txt, xls, ..)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def excel_file_to_list(filename):
|
def excel_file_to_list(filename):
|
||||||
return _excel_to_list(filename)
|
try:
|
||||||
|
return _excel_to_list(filename)
|
||||||
|
except:
|
||||||
|
raise ScoValueError("""
|
||||||
|
scolars_import_excel_file: un contenu xlsx semble corrompu!
|
||||||
|
peut-être avez vous fourni un fichier au mauvais format (txt, xls, ..)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def _excel_to_list(filelike): # we may need 'encoding' argument ?
|
def _excel_to_list(filelike): # we may need 'encoding' argument ?
|
||||||
|
@ -758,4 +791,4 @@ def excel_feuille_listeappel(
|
||||||
cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i)
|
cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i)
|
||||||
ws.append_row([None, cell_2])
|
ws.append_row([None, cell_2])
|
||||||
|
|
||||||
return ws.generate_standalone()
|
return ws.generate()
|
||||||
|
|
|
@ -55,11 +55,9 @@ class InvalidNoteValue(ScoException):
|
||||||
|
|
||||||
# Exception qui stoque dest_url, utilisee dans Zope standard_error_message
|
# Exception qui stoque dest_url, utilisee dans Zope standard_error_message
|
||||||
class ScoValueError(ScoException):
|
class ScoValueError(ScoException):
|
||||||
def __init__(self, msg, dest_url=None, REQUEST=None):
|
def __init__(self, msg, dest_url=None):
|
||||||
ScoException.__init__(self, msg)
|
ScoException.__init__(self, msg)
|
||||||
self.dest_url = dest_url
|
self.dest_url = dest_url
|
||||||
if REQUEST and dest_url:
|
|
||||||
REQUEST.set("dest_url", dest_url)
|
|
||||||
|
|
||||||
|
|
||||||
class FormatError(ScoValueError):
|
class FormatError(ScoValueError):
|
||||||
|
@ -79,7 +77,7 @@ class ScoConfigurationError(ScoValueError):
|
||||||
|
|
||||||
|
|
||||||
class ScoLockedFormError(ScoException):
|
class ScoLockedFormError(ScoException):
|
||||||
def __init__(self, msg="", REQUEST=None):
|
def __init__(self, msg=""):
|
||||||
msg = (
|
msg = (
|
||||||
"Cette formation est verrouillée (car il y a un semestre verrouillé qui s'y réfère). "
|
"Cette formation est verrouillée (car il y a un semestre verrouillé qui s'y réfère). "
|
||||||
+ str(msg)
|
+ str(msg)
|
||||||
|
@ -90,7 +88,7 @@ class ScoLockedFormError(ScoException):
|
||||||
class ScoGenError(ScoException):
|
class ScoGenError(ScoException):
|
||||||
"exception avec affichage d'une page explicative ad-hoc"
|
"exception avec affichage d'une page explicative ad-hoc"
|
||||||
|
|
||||||
def __init__(self, msg="", REQUEST=None):
|
def __init__(self, msg=""):
|
||||||
ScoException.__init__(self, msg)
|
ScoException.__init__(self, msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
"""Export d'une table avec les résultats de tous les étudiants
|
"""Export d'une table avec les résultats de tous les étudiants
|
||||||
"""
|
"""
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -240,15 +240,13 @@ def scodoc_table_results(
|
||||||
start_date_iso, end_date_iso, types_parcours
|
start_date_iso, end_date_iso, types_parcours
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
|
tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
start_date,
|
start_date,
|
||||||
end_date,
|
end_date,
|
||||||
"&types_parcours=".join([str(x) for x in types_parcours]),
|
"&types_parcours=".join([str(x) for x in types_parcours]),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(
|
return tab.make_page(format=format, with_html_headers=False)
|
||||||
format=format, with_html_headers=False, REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
tab_html = tab.html()
|
tab_html = tab.html()
|
||||||
nb_rows = tab.get_nb_rows()
|
nb_rows = tab.get_nb_rows()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -404,6 +404,4 @@ def search_inscr_etud_by_nip(code_nip, REQUEST=None, format="json"):
|
||||||
)
|
)
|
||||||
tab = GenTable(columns_ids=columns_ids, rows=T)
|
tab = GenTable(columns_ids=columns_ids, rows=T)
|
||||||
|
|
||||||
return tab.make_page(
|
return tab.make_page(format=format, with_html_headers=False, publish=True)
|
||||||
format=format, with_html_headers=False, REQUEST=REQUEST, publish=True
|
|
||||||
)
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ from operator import itemgetter
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
@ -92,9 +93,7 @@ def formation_has_locked_sems(formation_id):
|
||||||
return sems
|
return sems
|
||||||
|
|
||||||
|
|
||||||
def formation_export(
|
def formation_export(formation_id, export_ids=False, export_tags=True, format=None):
|
||||||
formation_id, export_ids=False, export_tags=True, format=None, REQUEST=None
|
|
||||||
):
|
|
||||||
"""Get a formation, with UE, matieres, modules
|
"""Get a formation, with UE, matieres, modules
|
||||||
in desired format
|
in desired format
|
||||||
"""
|
"""
|
||||||
|
@ -131,9 +130,7 @@ def formation_export(
|
||||||
if mod["ects"] is None:
|
if mod["ects"] is None:
|
||||||
del mod["ects"]
|
del mod["ects"]
|
||||||
|
|
||||||
return scu.sendResult(
|
return scu.sendResult(F, name="formation", format=format, force_outer_xml_tag=False, attached=True)
|
||||||
REQUEST, F, name="formation", format=format, force_outer_xml_tag=False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def formation_import_xml(doc: str, import_tags=True):
|
def formation_import_xml(doc: str, import_tags=True):
|
||||||
|
@ -162,20 +159,18 @@ def formation_import_xml(doc: str, import_tags=True):
|
||||||
D = sco_xml.xml_to_dicts(f)
|
D = sco_xml.xml_to_dicts(f)
|
||||||
assert D[0] == "formation"
|
assert D[0] == "formation"
|
||||||
F = D[1]
|
F = D[1]
|
||||||
F_quoted = F.copy()
|
# F_quoted = F.copy()
|
||||||
log("F=%s" % F)
|
# ndb.quote_dict(F_quoted)
|
||||||
ndb.quote_dict(F_quoted)
|
F["dept_id"] = g.scodoc_dept_id
|
||||||
log("F_quoted=%s" % F_quoted)
|
|
||||||
# find new version number
|
# find new version number
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
log(
|
|
||||||
"select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s"
|
|
||||||
% F_quoted
|
|
||||||
)
|
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s",
|
"""SELECT max(version)
|
||||||
F_quoted,
|
FROM notes_formations
|
||||||
|
WHERE acronyme=%(acronyme)s and titre=%(titre)s and dept_id=%(dept_id)s
|
||||||
|
""",
|
||||||
|
F,
|
||||||
)
|
)
|
||||||
res = cursor.fetchall()
|
res = cursor.fetchall()
|
||||||
try:
|
try:
|
||||||
|
@ -196,7 +191,7 @@ def formation_import_xml(doc: str, import_tags=True):
|
||||||
assert ue_info[0] == "ue"
|
assert ue_info[0] == "ue"
|
||||||
ue_info[1]["formation_id"] = formation_id
|
ue_info[1]["formation_id"] = formation_id
|
||||||
if "ue_id" in ue_info[1]:
|
if "ue_id" in ue_info[1]:
|
||||||
xml_ue_id = ue_info[1]["ue_id"]
|
xml_ue_id = int(ue_info[1]["ue_id"])
|
||||||
del ue_info[1]["ue_id"]
|
del ue_info[1]["ue_id"]
|
||||||
else:
|
else:
|
||||||
xml_ue_id = None
|
xml_ue_id = None
|
||||||
|
@ -212,7 +207,7 @@ def formation_import_xml(doc: str, import_tags=True):
|
||||||
for mod_info in mat_info[2]:
|
for mod_info in mat_info[2]:
|
||||||
assert mod_info[0] == "module"
|
assert mod_info[0] == "module"
|
||||||
if "module_id" in mod_info[1]:
|
if "module_id" in mod_info[1]:
|
||||||
xml_module_id = mod_info[1]["module_id"]
|
xml_module_id = int(mod_info[1]["module_id"])
|
||||||
del mod_info[1]["module_id"]
|
del mod_info[1]["module_id"]
|
||||||
else:
|
else:
|
||||||
xml_module_id = None
|
xml_module_id = None
|
||||||
|
@ -230,7 +225,7 @@ def formation_import_xml(doc: str, import_tags=True):
|
||||||
return formation_id, modules_old2new, ues_old2new
|
return formation_id, modules_old2new, ues_old2new
|
||||||
|
|
||||||
|
|
||||||
def formation_list_table(formation_id=None, args={}, REQUEST=None):
|
def formation_list_table(formation_id=None, args={}):
|
||||||
"""List formation, grouped by titre and sorted by versions
|
"""List formation, grouped by titre and sorted by versions
|
||||||
and listing associated semestres
|
and listing associated semestres
|
||||||
returns a table
|
returns a table
|
||||||
|
@ -247,7 +242,7 @@ def formation_list_table(formation_id=None, args={}, REQUEST=None):
|
||||||
"edit_img", border="0", alt="modifier", title="Modifier titres et code"
|
"edit_img", border="0", alt="modifier", title="Modifier titres et code"
|
||||||
)
|
)
|
||||||
|
|
||||||
editable = REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoChangeFormation)
|
editable = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
|
|
||||||
# Traduit/ajoute des champs à afficher:
|
# Traduit/ajoute des champs à afficher:
|
||||||
for f in formations:
|
for f in formations:
|
||||||
|
@ -347,17 +342,18 @@ def formation_list_table(formation_id=None, args={}, REQUEST=None):
|
||||||
html_class="formation_list_table table_leftalign",
|
html_class="formation_list_table table_leftalign",
|
||||||
html_with_td_classes=True,
|
html_with_td_classes=True,
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
base_url="%s?formation_id=%s" % (REQUEST.URL0, formation_id),
|
base_url="%s?formation_id=%s" % (request.base_url, formation_id),
|
||||||
page_title=title,
|
page_title=title,
|
||||||
pdf_title=title,
|
pdf_title=title,
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def formation_create_new_version(formation_id, redirect=True, REQUEST=None):
|
def formation_create_new_version(formation_id, redirect=True):
|
||||||
"duplicate formation, with new version number"
|
"duplicate formation, with new version number"
|
||||||
xml = formation_export(formation_id, export_ids=True, format="xml")
|
resp = formation_export(formation_id, export_ids=True, format="xml")
|
||||||
new_id, modules_old2new, ues_old2new = formation_import_xml(xml)
|
xml_data = resp.get_data(as_text=True)
|
||||||
|
new_id, modules_old2new, ues_old2new = formation_import_xml(xml_data)
|
||||||
# news
|
# news
|
||||||
F = formation_list(args={"formation_id": new_id})[0]
|
F = formation_list(args={"formation_id": new_id})[0]
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
|
|
|
@ -31,7 +31,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
||||||
import time
|
import time
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import g
|
from flask import g, request
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
|
@ -61,6 +61,7 @@ _formsemestreEditor = ndb.EditableTable(
|
||||||
"gestion_semestrielle",
|
"gestion_semestrielle",
|
||||||
"etat",
|
"etat",
|
||||||
"bul_hide_xml",
|
"bul_hide_xml",
|
||||||
|
"block_moyennes",
|
||||||
"bul_bgcolor",
|
"bul_bgcolor",
|
||||||
"modalite",
|
"modalite",
|
||||||
"resp_can_edit",
|
"resp_can_edit",
|
||||||
|
@ -68,7 +69,6 @@ _formsemestreEditor = ndb.EditableTable(
|
||||||
"ens_can_edit_eval",
|
"ens_can_edit_eval",
|
||||||
"elt_sem_apo",
|
"elt_sem_apo",
|
||||||
"elt_annee_apo",
|
"elt_annee_apo",
|
||||||
"scodoc7_id",
|
|
||||||
),
|
),
|
||||||
filter_dept=True,
|
filter_dept=True,
|
||||||
sortkey="date_debut",
|
sortkey="date_debut",
|
||||||
|
@ -82,6 +82,7 @@ _formsemestreEditor = ndb.EditableTable(
|
||||||
"etat": bool,
|
"etat": bool,
|
||||||
"gestion_compensation": bool,
|
"gestion_compensation": bool,
|
||||||
"bul_hide_xml": bool,
|
"bul_hide_xml": bool,
|
||||||
|
"block_moyennes": bool,
|
||||||
"gestion_semestrielle": bool,
|
"gestion_semestrielle": bool,
|
||||||
"gestion_compensation": bool,
|
"gestion_compensation": bool,
|
||||||
"gestion_semestrielle": bool,
|
"gestion_semestrielle": bool,
|
||||||
|
@ -95,6 +96,7 @@ _formsemestreEditor = ndb.EditableTable(
|
||||||
def get_formsemestre(formsemestre_id):
|
def get_formsemestre(formsemestre_id):
|
||||||
"list ONE formsemestre"
|
"list ONE formsemestre"
|
||||||
if not isinstance(formsemestre_id, int):
|
if not isinstance(formsemestre_id, int):
|
||||||
|
raise ValueError()
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"""Semestre invalide, reprenez l'opération au départ ou si le problème persiste signalez l'erreur sur scodoc-devel@listes.univ-paris13.fr"""
|
"""Semestre invalide, reprenez l'opération au départ ou si le problème persiste signalez l'erreur sur scodoc-devel@listes.univ-paris13.fr"""
|
||||||
)
|
)
|
||||||
|
@ -565,7 +567,7 @@ def list_formsemestre_by_etape(etape_apo=False, annee_scolaire=False):
|
||||||
return sems
|
return sems
|
||||||
|
|
||||||
|
|
||||||
def view_formsemestre_by_etape(etape_apo=None, format="html", REQUEST=None):
|
def view_formsemestre_by_etape(etape_apo=None, format="html"):
|
||||||
"""Affiche table des semestres correspondants à l'étape"""
|
"""Affiche table des semestres correspondants à l'étape"""
|
||||||
if etape_apo:
|
if etape_apo:
|
||||||
html_title = (
|
html_title = (
|
||||||
|
@ -582,8 +584,8 @@ def view_formsemestre_by_etape(etape_apo=None, format="html", REQUEST=None):
|
||||||
Etape: <input name="etape_apo" type="text" size="8"></input>
|
Etape: <input name="etape_apo" type="text" size="8"></input>
|
||||||
</form>""",
|
</form>""",
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?etape_apo=%s" % (REQUEST.URL0, etape_apo or "")
|
tab.base_url = "%s?etape_apo=%s" % (request.base_url, etape_apo or "")
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def sem_has_etape(sem, code_etape):
|
def sem_has_etape(sem, code_etape):
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"""Menu "custom" (défini par l'utilisateur) dans les semestres
|
"""Menu "custom" (défini par l'utilisateur) dans les semestres
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -84,9 +84,7 @@ def formsemestre_custommenu_edit(formsemestre_id, REQUEST=None):
|
||||||
scu.NotesURL() + "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
scu.NotesURL() + "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
)
|
)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header("Modification du menu du semestre ", sem),
|
||||||
REQUEST, "Modification du menu du semestre ", sem
|
|
||||||
),
|
|
||||||
"""<p class="help">Ce menu, spécifique à chaque semestre, peut être utilisé pour placer des liens vers vos applications préférées.</p>
|
"""<p class="help">Ce menu, spécifique à chaque semestre, peut être utilisé pour placer des liens vers vos applications préférées.</p>
|
||||||
<p class="help">Procédez en plusieurs fois si vous voulez ajouter plusieurs items.</p>""",
|
<p class="help">Procédez en plusieurs fois si vous voulez ajouter plusieurs items.</p>""",
|
||||||
]
|
]
|
||||||
|
@ -119,7 +117,7 @@ def formsemestre_custommenu_edit(formsemestre_id, REQUEST=None):
|
||||||
initvalues["title_" + str(item["custommenu_id"])] = item["title"]
|
initvalues["title_" + str(item["custommenu_id"])] = item["title"]
|
||||||
initvalues["url_" + str(item["custommenu_id"])] = item["url"]
|
initvalues["url_" + str(item["custommenu_id"])] = item["url"]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
initvalues=initvalues,
|
initvalues=initvalues,
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"""Form choix modules / responsables et creation formsemestre
|
"""Form choix modules / responsables et creation formsemestre
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
|
|
||||||
|
@ -91,7 +91,6 @@ def formsemestre_editwithmodules(REQUEST, formsemestre_id):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Modification du semestre",
|
"Modification du semestre",
|
||||||
sem,
|
sem,
|
||||||
javascripts=["libjs/AutoSuggest.js"],
|
javascripts=["libjs/AutoSuggest.js"],
|
||||||
|
@ -501,6 +500,14 @@ def do_formsemestre_createwithmodules(REQUEST=None, edit=False):
|
||||||
"labels": [""],
|
"labels": [""],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"block_moyennes",
|
||||||
|
{
|
||||||
|
"input_type": "boolcheckbox",
|
||||||
|
"title": "Bloquer moyennes",
|
||||||
|
"explanation": "empêcher le calcul des moyennes d'UE et générale.",
|
||||||
|
},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"sep",
|
"sep",
|
||||||
{
|
{
|
||||||
|
@ -653,7 +660,7 @@ def do_formsemestre_createwithmodules(REQUEST=None, edit=False):
|
||||||
|
|
||||||
#
|
#
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
modform,
|
modform,
|
||||||
submitlabel=submitlabel,
|
submitlabel=submitlabel,
|
||||||
|
@ -693,7 +700,6 @@ def do_formsemestre_createwithmodules(REQUEST=None, edit=False):
|
||||||
tf[2]["bul_hide_xml"] = False
|
tf[2]["bul_hide_xml"] = False
|
||||||
else:
|
else:
|
||||||
tf[2]["bul_hide_xml"] = True
|
tf[2]["bul_hide_xml"] = True
|
||||||
|
|
||||||
# remap les identifiants de responsables:
|
# remap les identifiants de responsables:
|
||||||
tf[2]["responsable_id"] = User.get_user_id_from_nomplogin(
|
tf[2]["responsable_id"] = User.get_user_id_from_nomplogin(
|
||||||
tf[2]["responsable_id"]
|
tf[2]["responsable_id"]
|
||||||
|
@ -888,7 +894,6 @@ def formsemestre_clone(formsemestre_id, REQUEST=None):
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Copie du semestre",
|
"Copie du semestre",
|
||||||
sem,
|
sem,
|
||||||
javascripts=["libjs/AutoSuggest.js"],
|
javascripts=["libjs/AutoSuggest.js"],
|
||||||
|
@ -959,7 +964,7 @@ def formsemestre_clone(formsemestre_id, REQUEST=None):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
submitlabel="Dupliquer ce semestre",
|
submitlabel="Dupliquer ce semestre",
|
||||||
|
@ -1113,10 +1118,11 @@ def do_formsemestre_clone(
|
||||||
def formsemestre_associate_new_version(
|
def formsemestre_associate_new_version(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
other_formsemestre_ids=[],
|
other_formsemestre_ids=[],
|
||||||
REQUEST=None,
|
|
||||||
dialog_confirmed=False,
|
dialog_confirmed=False,
|
||||||
):
|
):
|
||||||
"""Formulaire changement formation d'un semestre"""
|
"""Formulaire changement formation d'un semestre"""
|
||||||
|
formsemestre_id = int(formsemestre_id)
|
||||||
|
other_formsemestre_ids = [int(x) for x in other_formsemestre_ids]
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
# dresse le liste des semestres de la meme formation et version
|
# dresse le liste des semestres de la meme formation et version
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
@ -1161,15 +1167,19 @@ def formsemestre_associate_new_version(
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
do_formsemestres_associate_new_version(
|
do_formsemestres_associate_new_version(
|
||||||
[formsemestre_id] + other_formsemestre_ids, REQUEST=REQUEST
|
[formsemestre_id] + other_formsemestre_ids
|
||||||
)
|
)
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s&head_message=Formation%%20dupliquée"
|
url_for(
|
||||||
% formsemestre_id
|
"notes.formsemestre_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre_id,
|
||||||
|
head_message="Formation dupliquée",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_formsemestres_associate_new_version(formsemestre_ids, REQUEST=None):
|
def do_formsemestres_associate_new_version(formsemestre_ids):
|
||||||
"""Cree une nouvelle version de la formation du semestre, et y rattache les semestres.
|
"""Cree une nouvelle version de la formation du semestre, et y rattache les semestres.
|
||||||
Tous les moduleimpl sont ré-associés à la nouvelle formation, ainsi que les decisions de jury
|
Tous les moduleimpl sont ré-associés à la nouvelle formation, ainsi que les decisions de jury
|
||||||
si elles existent (codes d'UE validées).
|
si elles existent (codes d'UE validées).
|
||||||
|
@ -1179,9 +1189,11 @@ def do_formsemestres_associate_new_version(formsemestre_ids, REQUEST=None):
|
||||||
if not formsemestre_ids:
|
if not formsemestre_ids:
|
||||||
return
|
return
|
||||||
# Check: tous de la même formation
|
# Check: tous de la même formation
|
||||||
|
assert isinstance(formsemestre_ids[0], int)
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_ids[0])
|
sem = sco_formsemestre.get_formsemestre(formsemestre_ids[0])
|
||||||
formation_id = sem["formation_id"]
|
formation_id = sem["formation_id"]
|
||||||
for formsemestre_id in formsemestre_ids[1:]:
|
for formsemestre_id in formsemestre_ids[1:]:
|
||||||
|
assert isinstance(formsemestre_id, int)
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
if formation_id != sem["formation_id"]:
|
if formation_id != sem["formation_id"]:
|
||||||
raise ScoValueError("les semestres ne sont pas tous de la même formation !")
|
raise ScoValueError("les semestres ne sont pas tous de la même formation !")
|
||||||
|
@ -1192,9 +1204,7 @@ def do_formsemestres_associate_new_version(formsemestre_ids, REQUEST=None):
|
||||||
formation_id,
|
formation_id,
|
||||||
modules_old2new,
|
modules_old2new,
|
||||||
ues_old2new,
|
ues_old2new,
|
||||||
) = sco_formations.formation_create_new_version(
|
) = sco_formations.formation_create_new_version(formation_id, redirect=False)
|
||||||
formation_id, redirect=False, REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
|
|
||||||
for formsemestre_id in formsemestre_ids:
|
for formsemestre_id in formsemestre_ids:
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
@ -1235,7 +1245,7 @@ def formsemestre_delete(formsemestre_id, REQUEST=None):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(REQUEST, "Suppression du semestre", sem),
|
html_sco_header.html_sem_header("Suppression du semestre", sem),
|
||||||
"""<div class="ue_warning"><span>Attention !</span>
|
"""<div class="ue_warning"><span>Attention !</span>
|
||||||
<p class="help">A n'utiliser qu'en cas d'erreur lors de la saisie d'une formation. Normalement,
|
<p class="help">A n'utiliser qu'en cas d'erreur lors de la saisie d'une formation. Normalement,
|
||||||
<b>un semestre ne doit jamais être supprimé</b> (on perd la mémoire des notes et de tous les événements liés à ce semestre !).</p>
|
<b>un semestre ne doit jamais être supprimé</b> (on perd la mémoire des notes et de tous les événements liés à ce semestre !).</p>
|
||||||
|
@ -1261,7 +1271,7 @@ def formsemestre_delete(formsemestre_id, REQUEST=None):
|
||||||
else:
|
else:
|
||||||
submit_label = "Confirmer la suppression du semestre"
|
submit_label = "Confirmer la suppression du semestre"
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("formsemestre_id", {"input_type": "hidden"}),),
|
(("formsemestre_id", {"input_type": "hidden"}),),
|
||||||
initvalues=F,
|
initvalues=F,
|
||||||
|
@ -1421,7 +1431,7 @@ def do_formsemestre_delete(formsemestre_id):
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------
|
||||||
def formsemestre_edit_options(formsemestre_id, target_url=None, REQUEST=None):
|
def formsemestre_edit_options(formsemestre_id, REQUEST=None):
|
||||||
"""dialog to change formsemestre options
|
"""dialog to change formsemestre options
|
||||||
(accessible par ScoImplement ou dir. etudes)
|
(accessible par ScoImplement ou dir. etudes)
|
||||||
"""
|
"""
|
||||||
|
@ -1538,9 +1548,7 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None, REQUEST=None):
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header("Coefficients des UE du semestre", sem),
|
||||||
REQUEST, "Coefficients des UE du semestre", sem
|
|
||||||
),
|
|
||||||
help,
|
help,
|
||||||
]
|
]
|
||||||
#
|
#
|
||||||
|
@ -1576,7 +1584,7 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None, REQUEST=None):
|
||||||
form.append(("ue_" + str(ue["ue_id"]), descr))
|
form.append(("ue_" + str(ue["ue_id"]), descr))
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
submitlabel="Changer les coefficients",
|
submitlabel="Changer les coefficients",
|
||||||
|
@ -1652,9 +1660,7 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None, REQUEST=None):
|
||||||
formsemestre_id=formsemestre_id
|
formsemestre_id=formsemestre_id
|
||||||
) # > modif coef UE cap (modifs notes de _certains_ etudiants)
|
) # > modif coef UE cap (modifs notes de _certains_ etudiants)
|
||||||
|
|
||||||
header = html_sco_header.html_sem_header(
|
header = html_sco_header.html_sem_header("Coefficients des UE du semestre", sem)
|
||||||
REQUEST, "Coefficients des UE du semestre", sem
|
|
||||||
)
|
|
||||||
return (
|
return (
|
||||||
header
|
header
|
||||||
+ "\n".join(z)
|
+ "\n".join(z)
|
||||||
|
|
|
@ -34,7 +34,7 @@ Ces semestres n'auront qu'un seul inscrit !
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -181,7 +181,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id, REQUEST=None):
|
||||||
]
|
]
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
|
@ -231,7 +231,7 @@ def formsemestre_ext_edit_ue_validations(formsemestre_id, etudid, REQUEST=None):
|
||||||
else:
|
else:
|
||||||
initvalues = {}
|
initvalues = {}
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cssclass="tf_ext_edit_ue_validations",
|
cssclass="tf_ext_edit_ue_validations",
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
|
@ -334,7 +334,6 @@ def formsemestre_inscription_with_modules(
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Inscription de %s dans ce semestre" % etud["nomprenom"],
|
"Inscription de %s dans ce semestre" % etud["nomprenom"],
|
||||||
sem,
|
sem,
|
||||||
)
|
)
|
||||||
|
@ -415,7 +414,7 @@ def formsemestre_inscription_with_modules(
|
||||||
<input type="hidden" name="etudid" value="%s">
|
<input type="hidden" name="etudid" value="%s">
|
||||||
<input type="hidden" name="formsemestre_id" value="%s">
|
<input type="hidden" name="formsemestre_id" value="%s">
|
||||||
"""
|
"""
|
||||||
% (REQUEST.URL0, etudid, formsemestre_id)
|
% (request.base_url, etudid, formsemestre_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append(sco_groups.form_group_choice(formsemestre_id, allow_none=True))
|
H.append(sco_groups.form_group_choice(formsemestre_id, allow_none=True))
|
||||||
|
@ -533,7 +532,7 @@ function chkbx_select(field_id, state) {
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
initvalues,
|
initvalues,
|
||||||
|
@ -763,7 +762,6 @@ def formsemestre_inscrits_ailleurs(formsemestre_id, REQUEST=None):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Inscriptions multiples parmi les étudiants du semestre ",
|
"Inscriptions multiples parmi les étudiants du semestre ",
|
||||||
sem,
|
sem,
|
||||||
)
|
)
|
||||||
|
|
|
@ -436,7 +436,7 @@ def formsemestre_status_menubar(sem):
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def retreive_formsemestre_from_request():
|
def retreive_formsemestre_from_request() -> int:
|
||||||
"""Cherche si on a de quoi déduire le semestre affiché à partir des
|
"""Cherche si on a de quoi déduire le semestre affiché à partir des
|
||||||
arguments de la requête:
|
arguments de la requête:
|
||||||
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
|
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
|
||||||
|
@ -482,7 +482,7 @@ def retreive_formsemestre_from_request():
|
||||||
else:
|
else:
|
||||||
return None # no current formsemestre
|
return None # no current formsemestre
|
||||||
|
|
||||||
return formsemestre_id
|
return int(formsemestre_id)
|
||||||
|
|
||||||
|
|
||||||
# Element HTML decrivant un semestre (barre de menu et infos)
|
# Element HTML decrivant un semestre (barre de menu et infos)
|
||||||
|
@ -698,10 +698,10 @@ def formsemestre_description_table(formsemestre_id, REQUEST=None, with_evals=Fal
|
||||||
html_caption=title,
|
html_caption=title,
|
||||||
html_class="table_leftalign formsemestre_description",
|
html_class="table_leftalign formsemestre_description",
|
||||||
base_url="%s?formsemestre_id=%s&with_evals=%s"
|
base_url="%s?formsemestre_id=%s&with_evals=%s"
|
||||||
% (REQUEST.URL0, formsemestre_id, with_evals),
|
% (request.base_url, formsemestre_id, with_evals),
|
||||||
page_title=title,
|
page_title=title,
|
||||||
html_title=html_sco_header.html_sem_header(
|
html_title=html_sco_header.html_sem_header(
|
||||||
REQUEST, "Description du semestre", sem, with_page_header=False
|
"Description du semestre", sem, with_page_header=False
|
||||||
),
|
),
|
||||||
pdf_title=title,
|
pdf_title=title,
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
|
@ -721,14 +721,14 @@ def formsemestre_description(
|
||||||
tab.html_before_table = """<form name="f" method="get" action="%s">
|
tab.html_before_table = """<form name="f" method="get" action="%s">
|
||||||
<input type="hidden" name="formsemestre_id" value="%s"></input>
|
<input type="hidden" name="formsemestre_id" value="%s"></input>
|
||||||
<input type="checkbox" name="with_evals" value="1" onchange="document.f.submit()" """ % (
|
<input type="checkbox" name="with_evals" value="1" onchange="document.f.submit()" """ % (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
)
|
)
|
||||||
if with_evals:
|
if with_evals:
|
||||||
tab.html_before_table += "checked"
|
tab.html_before_table += "checked"
|
||||||
tab.html_before_table += ">indiquer les évaluations</input></form>"
|
tab.html_before_table += ">indiquer les évaluations</input></form>"
|
||||||
|
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
# genere liste html pour accès aux groupes de ce semestre
|
# genere liste html pour accès aux groupes de ce semestre
|
||||||
|
@ -912,12 +912,12 @@ def formsemestre_status_head(formsemestre_id=None, REQUEST=None, page_title=None
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST, page_title, sem, with_page_header=False, with_h2=False
|
page_title, sem, with_page_header=False, with_h2=False
|
||||||
),
|
),
|
||||||
"""<table>
|
f"""<table>
|
||||||
<tr><td class="fichetitre2">Formation: </td><td>
|
<tr><td class="fichetitre2">Formation: </td><td>
|
||||||
<a href="Notes/ue_list?formation_id=%(formation_id)s" class="discretelink" title="Formation %(acronyme)s, v%(version)s">%(titre)s</a>"""
|
<a href="{url_for('notes.ue_list', scodoc_dept=g.scodoc_dept, formation_id=F['formation_id'])}"
|
||||||
% F,
|
class="discretelink" title="Formation {F['acronyme']}, v{F['version']}">{F['titre']}</a>""",
|
||||||
]
|
]
|
||||||
if sem["semestre_id"] >= 0:
|
if sem["semestre_id"] >= 0:
|
||||||
H.append(", %s %s" % (parcours.SESSION_NAME, sem["semestre_id"]))
|
H.append(", %s %s" % (parcours.SESSION_NAME, sem["semestre_id"]))
|
||||||
|
@ -948,10 +948,13 @@ Il y a des notes en attente ! Le classement des étudiants n'a qu'une valeur ind
|
||||||
</td></tr>"""
|
</td></tr>"""
|
||||||
)
|
)
|
||||||
H.append("</table>")
|
H.append("</table>")
|
||||||
|
sem_warning = ""
|
||||||
if sem["bul_hide_xml"]:
|
if sem["bul_hide_xml"]:
|
||||||
H.append(
|
sem_warning += "Bulletins non publiés sur le portail. "
|
||||||
'<p class="fontorange"><em>Bulletins non publiés sur le portail</em></p>'
|
if sem["block_moyennes"]:
|
||||||
)
|
sem_warning += "Calcul des moyennes bloqué !"
|
||||||
|
if sem_warning:
|
||||||
|
H.append('<p class="fontorange"><em>' + sem_warning + "</em></p>")
|
||||||
if sem["semestre_id"] >= 0 and not sco_formsemestre.sem_une_annee(sem):
|
if sem["semestre_id"] >= 0 and not sco_formsemestre.sem_une_annee(sem):
|
||||||
H.append(
|
H.append(
|
||||||
'<p class="fontorange"><em>Attention: ce semestre couvre plusieurs années scolaires !</em></p>'
|
'<p class="fontorange"><em>Attention: ce semestre couvre plusieurs années scolaires !</em></p>'
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error, time, datetime
|
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error, time, datetime
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -149,9 +149,7 @@ def formsemestre_validation_etud_form(
|
||||||
'</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>'
|
'</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>'
|
||||||
% (
|
% (
|
||||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(etud, title="fiche de %s" % etud["nom"]),
|
||||||
etud, title="fiche de %s" % etud["nom"], REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -356,7 +354,7 @@ def formsemestre_validation_etud(
|
||||||
#
|
#
|
||||||
Se.valide_decision(selected_choice, REQUEST) # enregistre
|
Se.valide_decision(selected_choice, REQUEST) # enregistre
|
||||||
return _redirect_valid_choice(
|
return _redirect_valid_choice(
|
||||||
formsemestre_id, etudid, Se, selected_choice, desturl, sortcol, REQUEST
|
formsemestre_id, etudid, Se, selected_choice, desturl, sortcol
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -402,19 +400,17 @@ def formsemestre_validation_etud_manu(
|
||||||
Se.valide_decision(choice, REQUEST) # enregistre
|
Se.valide_decision(choice, REQUEST) # enregistre
|
||||||
if redirect:
|
if redirect:
|
||||||
return _redirect_valid_choice(
|
return _redirect_valid_choice(
|
||||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
formsemestre_id, etudid, Se, choice, desturl, sortcol
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _redirect_valid_choice(
|
def _redirect_valid_choice(formsemestre_id, etudid, Se, choice, desturl, sortcol):
|
||||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
|
||||||
):
|
|
||||||
adr = "formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1" % (
|
adr = "formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1" % (
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
etudid,
|
etudid,
|
||||||
)
|
)
|
||||||
if sortcol:
|
if sortcol:
|
||||||
adr += "&sortcol=" + sortcol
|
adr += "&sortcol=" + str(sortcol)
|
||||||
# if desturl:
|
# if desturl:
|
||||||
# desturl += "&desturl=" + desturl
|
# desturl += "&desturl=" + desturl
|
||||||
return flask.redirect(adr)
|
return flask.redirect(adr)
|
||||||
|
@ -826,7 +822,7 @@ def formsemestre_validation_auto(formsemestre_id, REQUEST):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST, "Saisie automatique des décisions du semestre", sem
|
"Saisie automatique des décisions du semestre", sem
|
||||||
),
|
),
|
||||||
"""
|
"""
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -994,9 +990,7 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid, REQUEST=None):
|
||||||
'</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>'
|
'</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>'
|
||||||
% (
|
% (
|
||||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(etud, title="fiche de %s" % etud["nom"]),
|
||||||
etud, title="fiche de %s" % etud["nom"], REQUEST=REQUEST
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"""<p class="help">Utiliser cette page pour enregistrer une UE validée antérieurement,
|
"""<p class="help">Utiliser cette page pour enregistrer une UE validée antérieurement,
|
||||||
|
@ -1017,7 +1011,7 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid, REQUEST=None):
|
||||||
ue_names = ["Choisir..."] + ["%(acronyme)s %(titre)s" % ue for ue in ues]
|
ue_names = ["Choisir..."] + ["%(acronyme)s %(titre)s" % ue for ue in ues]
|
||||||
ue_ids = [""] + [ue["ue_id"] for ue in ues]
|
ue_ids = [""] + [ue["ue_id"] for ue in ues]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("etudid", {"input_type": "hidden"}),
|
("etudid", {"input_type": "hidden"}),
|
||||||
|
|
|
@ -42,7 +42,7 @@ from xml.etree import ElementTree
|
||||||
from xml.etree.ElementTree import Element
|
from xml.etree.ElementTree import Element
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g, request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -476,7 +476,7 @@ def formsemestre_partition_list(formsemestre_id, format="xml", REQUEST=None):
|
||||||
# Ajoute les groupes
|
# Ajoute les groupes
|
||||||
for p in partitions:
|
for p in partitions:
|
||||||
p["group"] = get_partition_groups(p)
|
p["group"] = get_partition_groups(p)
|
||||||
return scu.sendResult(REQUEST, partitions, name="partition", format=format)
|
return scu.sendResult(partitions, name="partition", format=format)
|
||||||
|
|
||||||
|
|
||||||
# Encore utilisé par groupmgr.js
|
# Encore utilisé par groupmgr.js
|
||||||
|
@ -1079,7 +1079,7 @@ def partition_rename(partition_id, REQUEST=None):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
H = ["<h2>Renommer une partition</h2>"]
|
H = ["<h2>Renommer une partition</h2>"]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("partition_id", {"default": partition_id, "input_type": "hidden"}),
|
("partition_id", {"default": partition_id, "input_type": "hidden"}),
|
||||||
|
@ -1188,7 +1188,7 @@ def group_rename(group_id, REQUEST=None):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
|
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("group_id", {"default": group_id, "input_type": "hidden"}),
|
("group_id", {"default": group_id, "input_type": "hidden"}),
|
||||||
|
@ -1268,7 +1268,7 @@ def groups_auto_repartition(partition_id=None, REQUEST=None):
|
||||||
]
|
]
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
{},
|
{},
|
||||||
|
@ -1499,7 +1499,7 @@ def _sortgroups(groups):
|
||||||
# Tri: place 'all' en tête, puis groupe par partition / nom de groupe
|
# Tri: place 'all' en tête, puis groupe par partition / nom de groupe
|
||||||
R = [g for g in groups if g["partition_name"] is None]
|
R = [g for g in groups if g["partition_name"] is None]
|
||||||
o = [g for g in groups if g["partition_name"] != None]
|
o = [g for g in groups if g["partition_name"] != None]
|
||||||
o.sort(key=lambda x: (x["numero"], x["group_name"]))
|
o.sort(key=lambda x: (x["numero"] or 0, x["group_name"]))
|
||||||
|
|
||||||
return R + o
|
return R + o
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -81,6 +81,7 @@ def list_authorized_etuds_by_sem(sem, delai=274):
|
||||||
"title": src["titreannee"],
|
"title": src["titreannee"],
|
||||||
"title_target": "formsemestre_status?formsemestre_id=%s"
|
"title_target": "formsemestre_status?formsemestre_id=%s"
|
||||||
% src["formsemestre_id"],
|
% src["formsemestre_id"],
|
||||||
|
"filename": "etud_autorises",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
# ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest.
|
# ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest.
|
||||||
|
@ -99,6 +100,7 @@ def list_authorized_etuds_by_sem(sem, delai=274):
|
||||||
% sem["formsemestre_id"],
|
% sem["formsemestre_id"],
|
||||||
"comment": " actuellement inscrits dans ce semestre",
|
"comment": " actuellement inscrits dans ce semestre",
|
||||||
"help": "Ces étudiants sont actuellement inscrits dans ce semestre. Si vous les décochez, il seront désinscrits.",
|
"help": "Ces étudiants sont actuellement inscrits dans ce semestre. Si vous les décochez, il seront désinscrits.",
|
||||||
|
"filename": "etud_inscrits",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,16 +148,15 @@ def list_inscrits_date(sem):
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
|
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT I.etudid
|
"""SELECT ins.etudid
|
||||||
FROM
|
FROM
|
||||||
notes_formsemestre_inscription ins,
|
notes_formsemestre_inscription ins,
|
||||||
notes_formsemestre S,
|
notes_formsemestre S
|
||||||
identite i
|
|
||||||
WHERE ins.formsemestre_id = S.id
|
WHERE ins.formsemestre_id = S.id
|
||||||
AND S.id != %(formsemestre_id)s
|
AND S.id != %(formsemestre_id)s
|
||||||
AND S.date_debut <= %(date_debut_iso)s
|
AND S.date_debut <= %(date_debut_iso)s
|
||||||
AND S.date_fin >= %(date_debut_iso)s
|
AND S.date_fin >= %(date_debut_iso)s
|
||||||
AND ins.dept_id = %(dept_id)
|
AND S.dept_id = %(dept_id)s
|
||||||
""",
|
""",
|
||||||
sem,
|
sem,
|
||||||
)
|
)
|
||||||
|
@ -413,9 +414,9 @@ def build_page(
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST, "Passages dans le semestre", sem, with_page_header=False
|
"Passages dans le semestre", sem, with_page_header=False
|
||||||
),
|
),
|
||||||
"""<form method="post" action="%s">""" % REQUEST.URL0,
|
"""<form method="post" action="%s">""" % request.base_url,
|
||||||
"""<input type="hidden" name="formsemestre_id" value="%(formsemestre_id)s"/>
|
"""<input type="hidden" name="formsemestre_id" value="%(formsemestre_id)s"/>
|
||||||
<input type="submit" name="submitted" value="Appliquer les modifications"/>
|
<input type="submit" name="submitted" value="Appliquer les modifications"/>
|
||||||
<a href="#help">aide</a>
|
<a href="#help">aide</a>
|
||||||
|
@ -507,7 +508,12 @@ def etuds_select_boxes(
|
||||||
</script>
|
</script>
|
||||||
<div class="etuds_select_boxes">"""
|
<div class="etuds_select_boxes">"""
|
||||||
] # "
|
] # "
|
||||||
|
# Élimine les boites vides:
|
||||||
|
auth_etuds_by_cat = {
|
||||||
|
k: auth_etuds_by_cat[k]
|
||||||
|
for k in auth_etuds_by_cat
|
||||||
|
if auth_etuds_by_cat[k]["etuds"]
|
||||||
|
}
|
||||||
for src_cat in auth_etuds_by_cat.keys():
|
for src_cat in auth_etuds_by_cat.keys():
|
||||||
infos = auth_etuds_by_cat[src_cat]["infos"]
|
infos = auth_etuds_by_cat[src_cat]["infos"]
|
||||||
infos["comment"] = infos.get("comment", "") # commentaire dans sous-titre boite
|
infos["comment"] = infos.get("comment", "") # commentaire dans sous-titre boite
|
||||||
|
@ -550,10 +556,8 @@ def etuds_select_boxes(
|
||||||
if with_checkbox or sel_inscrits:
|
if with_checkbox or sel_inscrits:
|
||||||
H.append(")")
|
H.append(")")
|
||||||
if base_url and etuds:
|
if base_url and etuds:
|
||||||
H.append(
|
url = scu.build_url_query(base_url, export_cat_xls=src_cat)
|
||||||
'<a href="%s&export_cat_xls=%s">%s</a> '
|
H.append(f'<a href="{url}">{scu.ICON_XLS}</a> ')
|
||||||
% (base_url, src_cat, scu.ICON_XLS)
|
|
||||||
)
|
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
if etud.get("inscrit", False):
|
if etud.get("inscrit", False):
|
||||||
|
@ -633,4 +637,4 @@ def etuds_select_box_xls(src_cat):
|
||||||
caption="%(title)s. %(help)s" % src_cat["infos"],
|
caption="%(title)s. %(help)s" % src_cat["infos"],
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
return tab.excel()
|
return tab.excel() # tab.make_page(filename=src_cat["infos"]["filename"])
|
||||||
|
|
|
@ -27,11 +27,11 @@
|
||||||
|
|
||||||
"""Liste des notes d'une évaluation
|
"""Liste des notes d'une évaluation
|
||||||
"""
|
"""
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
import urllib
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -177,7 +177,7 @@ def do_evaluation_listenotes(REQUEST):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cancelbutton=None,
|
cancelbutton=None,
|
||||||
|
@ -482,7 +482,7 @@ def _make_table_notes(
|
||||||
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
|
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
|
||||||
)
|
)
|
||||||
|
|
||||||
t = tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
t = tab.make_page(format=format, with_html_headers=False)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
@ -778,9 +778,7 @@ def evaluation_check_absences_html(
|
||||||
|
|
||||||
if with_header:
|
if with_header:
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header("Vérification absences à l'évaluation"),
|
||||||
REQUEST, "Vérification absences à l'évaluation"
|
|
||||||
),
|
|
||||||
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
||||||
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""",
|
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""",
|
||||||
]
|
]
|
||||||
|
@ -817,8 +815,8 @@ def evaluation_check_absences_html(
|
||||||
'<a class="stdlink" href="Absences/doSignaleAbsence?etudid=%s&datedebut=%s&datefin=%s&demijournee=%s&moduleimpl_id=%s">signaler cette absence</a>'
|
'<a class="stdlink" href="Absences/doSignaleAbsence?etudid=%s&datedebut=%s&datefin=%s&demijournee=%s&moduleimpl_id=%s">signaler cette absence</a>'
|
||||||
% (
|
% (
|
||||||
etud["etudid"],
|
etud["etudid"],
|
||||||
six.moves.urllib.parse.quote(E["jour"]),
|
urllib.parse.quote(E["jour"]),
|
||||||
six.moves.urllib.parse.quote(E["jour"]),
|
urllib.parse.quote(E["jour"]),
|
||||||
demijournee,
|
demijournee,
|
||||||
E["moduleimpl_id"],
|
E["moduleimpl_id"],
|
||||||
)
|
)
|
||||||
|
@ -866,7 +864,6 @@ def formsemestre_check_absences_html(formsemestre_id, REQUEST=None):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Vérification absences aux évaluations de ce semestre",
|
"Vérification absences aux évaluations de ce semestre",
|
||||||
sem,
|
sem,
|
||||||
),
|
),
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"""
|
"""
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app
|
import app
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -84,8 +84,8 @@ def scodoc_table_etuds_lycees(format="html", REQUEST=None):
|
||||||
sco_preferences.SemPreferences(),
|
sco_preferences.SemPreferences(),
|
||||||
no_links=True,
|
no_links=True,
|
||||||
)
|
)
|
||||||
tab.base_url = REQUEST.URL0
|
tab.base_url = request.base_url
|
||||||
t = tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
t = tab.make_page(format=format, with_html_headers=False)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return t
|
return t
|
||||||
H = [
|
H = [
|
||||||
|
@ -187,12 +187,12 @@ def formsemestre_etuds_lycees(
|
||||||
tab, etuds_by_lycee = formsemestre_table_etuds_lycees(
|
tab, etuds_by_lycee = formsemestre_table_etuds_lycees(
|
||||||
formsemestre_id, only_primo=only_primo, group_lycees=not no_grouping
|
formsemestre_id, only_primo=only_primo, group_lycees=not no_grouping
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
|
||||||
if only_primo:
|
if only_primo:
|
||||||
tab.base_url += "&only_primo=1"
|
tab.base_url += "&only_primo=1"
|
||||||
if no_grouping:
|
if no_grouping:
|
||||||
tab.base_url += "&no_grouping=1"
|
tab.base_url += "&no_grouping=1"
|
||||||
t = tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
t = tab.make_page(format=format, with_html_headers=False)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return t
|
return t
|
||||||
F = [
|
F = [
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -137,7 +138,7 @@ def moduleimpl_inscriptions_edit(
|
||||||
|
|
||||||
</script>"""
|
</script>"""
|
||||||
)
|
)
|
||||||
H.append("""<form method="post" id="mi_form" action="%s">""" % REQUEST.URL0)
|
H.append("""<form method="post" id="mi_form" action="%s">""" % request.base_url)
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<input type="hidden" name="moduleimpl_id" value="%(moduleimpl_id)s"/>
|
<input type="hidden" name="moduleimpl_id" value="%(moduleimpl_id)s"/>
|
||||||
|
@ -250,7 +251,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id, REQUEST=None):
|
||||||
tous sauf <liste d'au plus 7 noms>
|
tous sauf <liste d'au plus 7 noms>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
|
@ -285,9 +286,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id, REQUEST=None):
|
||||||
mod["nb_inscrits"] = nb_inscrits
|
mod["nb_inscrits"] = nb_inscrits
|
||||||
options.append(mod)
|
options.append(mod)
|
||||||
# Page HTML:
|
# Page HTML:
|
||||||
H = [
|
H = [html_sco_header.html_sem_header("Inscriptions aux modules du semestre")]
|
||||||
html_sco_header.html_sem_header(REQUEST, "Inscriptions aux modules du semestre")
|
|
||||||
]
|
|
||||||
|
|
||||||
H.append("<h3>Inscrits au semestre: %d étudiants</h3>" % len(inscrits))
|
H.append("<h3>Inscrits au semestre: %d étudiants</h3>" % len(inscrits))
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"""Tableau de bord module
|
"""Tableau de bord module
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
import urllib
|
||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
@ -64,7 +64,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sco_permissions_check.can_edit_notes(
|
sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
)
|
)
|
||||||
and nbnotes != 0
|
and nbnotes != 0
|
||||||
):
|
):
|
||||||
|
@ -80,7 +80,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
"evaluation_id": evaluation_id,
|
"evaluation_id": evaluation_id,
|
||||||
},
|
},
|
||||||
"enabled": sco_permissions_check.can_edit_notes(
|
"enabled": sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
current_user, E["moduleimpl_id"]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -90,7 +90,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
"evaluation_id": evaluation_id,
|
"evaluation_id": evaluation_id,
|
||||||
},
|
},
|
||||||
"enabled": sco_permissions_check.can_edit_notes(
|
"enabled": sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -101,7 +101,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
},
|
},
|
||||||
"enabled": nbnotes == 0
|
"enabled": nbnotes == 0
|
||||||
and sco_permissions_check.can_edit_notes(
|
and sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -111,7 +111,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
"evaluation_id": evaluation_id,
|
"evaluation_id": evaluation_id,
|
||||||
},
|
},
|
||||||
"enabled": sco_permissions_check.can_edit_notes(
|
"enabled": sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -128,16 +128,15 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0, REQUEST=None):
|
||||||
"args": {
|
"args": {
|
||||||
"evaluation_id": evaluation_id,
|
"evaluation_id": evaluation_id,
|
||||||
},
|
},
|
||||||
"enabled": nbnotes == 0
|
"enabled": sco_permissions_check.can_edit_notes(
|
||||||
and sco_permissions_check.can_edit_notes(
|
current_user, E["moduleimpl_id"]
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"]
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Absences ce jour",
|
"title": "Absences ce jour",
|
||||||
"endpoint": "absences.EtatAbsencesDate",
|
"endpoint": "absences.EtatAbsencesDate",
|
||||||
"args": {
|
"args": {
|
||||||
"date": six.moves.urllib.parse.quote(E["jour"], safe=""),
|
"date": urllib.parse.quote(E["jour"], safe=""),
|
||||||
"group_ids": group_id,
|
"group_ids": group_id,
|
||||||
},
|
},
|
||||||
"enabled": E["jour"],
|
"enabled": E["jour"],
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from flask import url_for, g
|
from flask import url_for, g
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -144,7 +145,7 @@ def _menuScolarite(authuser, sem, etudid):
|
||||||
|
|
||||||
def ficheEtud(etudid=None, REQUEST=None):
|
def ficheEtud(etudid=None, REQUEST=None):
|
||||||
"fiche d'informations sur un etudiant"
|
"fiche d'informations sur un etudiant"
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
if etudid and REQUEST:
|
if etudid and REQUEST:
|
||||||
# la sidebar est differente s'il y a ou pas un etudid
|
# la sidebar est differente s'il y a ou pas un etudid
|
||||||
|
@ -167,7 +168,7 @@ def ficheEtud(etudid=None, REQUEST=None):
|
||||||
info["info_naissance"] += " à " + info["lieu_naissance"]
|
info["info_naissance"] += " à " + info["lieu_naissance"]
|
||||||
if info["dept_naissance"]:
|
if info["dept_naissance"]:
|
||||||
info["info_naissance"] += " (%s)" % info["dept_naissance"]
|
info["info_naissance"] += " (%s)" % info["dept_naissance"]
|
||||||
info["etudfoto"] = sco_photos.etud_photo_html(etud, REQUEST=REQUEST)
|
info["etudfoto"] = sco_photos.etud_photo_html(etud)
|
||||||
if (
|
if (
|
||||||
(not info["domicile"])
|
(not info["domicile"])
|
||||||
and (not info["codepostaldomicile"])
|
and (not info["codepostaldomicile"])
|
||||||
|
@ -491,7 +492,7 @@ def menus_etud(REQUEST=None):
|
||||||
"""Menu etudiant (operations sur l'etudiant)"""
|
"""Menu etudiant (operations sur l'etudiant)"""
|
||||||
if "etudid" not in REQUEST.form:
|
if "etudid" not in REQUEST.form:
|
||||||
return ""
|
return ""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
|
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
|
|
||||||
|
@ -539,9 +540,7 @@ def etud_info_html(etudid, with_photo="1", REQUEST=None, debug=False):
|
||||||
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
|
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
|
||||||
with_photo = int(with_photo)
|
with_photo = int(with_photo)
|
||||||
etud = sco_etud.get_etud_info(filled=True)[0]
|
etud = sco_etud.get_etud_info(filled=True)[0]
|
||||||
photo_html = sco_photos.etud_photo_html(
|
photo_html = sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"])
|
||||||
etud, title="fiche de " + etud["nom"], REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
# experimental: may be too slow to be here
|
# experimental: may be too slow to be here
|
||||||
etud["codeparcours"], etud["decisions_jury"] = sco_report.get_codeparcoursetud(
|
etud["codeparcours"], etud["decisions_jury"] = sco_report.get_codeparcoursetud(
|
||||||
etud, prefix="S", separator=", "
|
etud, prefix="S", separator=", "
|
||||||
|
|
|
@ -588,7 +588,6 @@ class SituationEtudParcoursGeneric(object):
|
||||||
self.etudid,
|
self.etudid,
|
||||||
decision.code_etat,
|
decision.code_etat,
|
||||||
decision.assiduite,
|
decision.assiduite,
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
)
|
||||||
# -- modification du code du semestre precedent
|
# -- modification du code du semestre precedent
|
||||||
if self.prev and decision.new_code_prev:
|
if self.prev and decision.new_code_prev:
|
||||||
|
@ -619,7 +618,6 @@ class SituationEtudParcoursGeneric(object):
|
||||||
self.etudid,
|
self.etudid,
|
||||||
decision.new_code_prev,
|
decision.new_code_prev,
|
||||||
decision.assiduite, # attention: en toute rigueur il faudrait utiliser une indication de l'assiduite au sem. precedent, que nous n'avons pas...
|
decision.assiduite, # attention: en toute rigueur il faudrait utiliser une indication de l'assiduite au sem. precedent, que nous n'avons pas...
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sco_cache.invalidate_formsemestre(
|
sco_cache.invalidate_formsemestre(
|
||||||
|
@ -897,9 +895,7 @@ def formsemestre_update_validation_sem(
|
||||||
return to_invalidate
|
return to_invalidate
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_validate_ues(
|
def formsemestre_validate_ues(formsemestre_id, etudid, code_etat_sem, assiduite):
|
||||||
formsemestre_id, etudid, code_etat_sem, assiduite, REQUEST=None
|
|
||||||
):
|
|
||||||
"""Enregistre codes UE, selon état semestre.
|
"""Enregistre codes UE, selon état semestre.
|
||||||
Les codes UE sont toujours calculés ici, et non passés en paramètres
|
Les codes UE sont toujours calculés ici, et non passés en paramètres
|
||||||
car ils ne dépendent que de la note d'UE et de la validation ou non du semestre.
|
car ils ne dépendent que de la note d'UE et de la validation ou non du semestre.
|
||||||
|
@ -933,14 +929,13 @@ def formsemestre_validate_ues(
|
||||||
cnx, nt, formsemestre_id, etudid, ue_id, code_ue
|
cnx, nt, formsemestre_id, etudid, ue_id, code_ue
|
||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
logdb(
|
||||||
logdb(
|
cnx,
|
||||||
cnx,
|
method="validate_ue",
|
||||||
method="validate_ue",
|
etudid=etudid,
|
||||||
etudid=etudid,
|
msg="ue_id=%s code=%s" % (ue_id, code_ue),
|
||||||
msg="ue_id=%s code=%s" % (ue_id, code_ue),
|
commit=False,
|
||||||
commit=False,
|
)
|
||||||
)
|
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ Les images sont servies par ScoDoc, via la méthode getphotofile?etudid=xxx
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from app.scodoc.sco_exceptions import ScoGenError
|
||||||
import datetime
|
import datetime
|
||||||
import glob
|
import glob
|
||||||
import io
|
import io
|
||||||
|
@ -52,6 +53,7 @@ import requests
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
import PIL
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
from flask import request, g
|
from flask import request, g
|
||||||
|
@ -172,7 +174,7 @@ def etud_photo_is_local(etud, size="small"):
|
||||||
return photo_pathname(etud, size=size)
|
return photo_pathname(etud, size=size)
|
||||||
|
|
||||||
|
|
||||||
def etud_photo_html(etud=None, etudid=None, title=None, size="small", REQUEST=None):
|
def etud_photo_html(etud=None, etudid=None, title=None, size="small"):
|
||||||
"""HTML img tag for the photo, either in small size (h90)
|
"""HTML img tag for the photo, either in small size (h90)
|
||||||
or original size (size=="orig")
|
or original size (size=="orig")
|
||||||
"""
|
"""
|
||||||
|
@ -209,9 +211,7 @@ def etud_photo_orig_html(etud=None, etudid=None, title=None, REQUEST=None):
|
||||||
Full-size images are always stored locally in the filesystem.
|
Full-size images are always stored locally in the filesystem.
|
||||||
They are the original uploaded images, converted in jpeg.
|
They are the original uploaded images, converted in jpeg.
|
||||||
"""
|
"""
|
||||||
return etud_photo_html(
|
return etud_photo_html(etud=etud, etudid=etudid, title=title, size="orig")
|
||||||
etud=etud, etudid=etudid, title=title, size="orig", REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def photo_pathname(etud, size="orig"):
|
def photo_pathname(etud, size="orig"):
|
||||||
|
@ -246,7 +246,10 @@ def store_photo(etud, data):
|
||||||
filesize = len(data)
|
filesize = len(data)
|
||||||
if filesize < 10 or filesize > MAX_FILE_SIZE:
|
if filesize < 10 or filesize > MAX_FILE_SIZE:
|
||||||
return 0, "Fichier image de taille invalide ! (%d)" % filesize
|
return 0, "Fichier image de taille invalide ! (%d)" % filesize
|
||||||
filename = save_image(etud["etudid"], data)
|
try:
|
||||||
|
filename = save_image(etud["etudid"], data)
|
||||||
|
except PIL.UnidentifiedImageError:
|
||||||
|
raise ScoGenError(msg="Fichier d'image invalide ou non format non supporté")
|
||||||
# update database:
|
# update database:
|
||||||
etud["photo_filename"] = filename
|
etud["photo_filename"] = filename
|
||||||
etud["foto"] = None
|
etud["foto"] = None
|
||||||
|
@ -298,6 +301,7 @@ def save_image(etudid, data):
|
||||||
filename = get_new_filename(etudid)
|
filename = get_new_filename(etudid)
|
||||||
path = os.path.join(PHOTO_DIR, filename)
|
path = os.path.join(PHOTO_DIR, filename)
|
||||||
log("saving %dx%d jpeg to %s" % (img.size[0], img.size[1], path))
|
log("saving %dx%d jpeg to %s" % (img.size[0], img.size[1], path))
|
||||||
|
img = img.convert("RGB")
|
||||||
img.save(path + IMAGE_EXT, format="JPEG", quality=92)
|
img.save(path + IMAGE_EXT, format="JPEG", quality=92)
|
||||||
# resize:
|
# resize:
|
||||||
img = scale_height(img)
|
img = scale_height(img)
|
||||||
|
@ -341,7 +345,7 @@ def find_new_dir():
|
||||||
|
|
||||||
def copy_portal_photo_to_fs(etud):
|
def copy_portal_photo_to_fs(etud):
|
||||||
"""Copy the photo from portal (distant website) to local fs.
|
"""Copy the photo from portal (distant website) to local fs.
|
||||||
Returns rel. path or None if copy failed, with a diagnotic message
|
Returns rel. path or None if copy failed, with a diagnostic message
|
||||||
"""
|
"""
|
||||||
sco_etud.format_etud_ident(etud)
|
sco_etud.format_etud_ident(etud)
|
||||||
url = photo_portal_url(etud)
|
url = photo_portal_url(etud)
|
||||||
|
@ -353,11 +357,12 @@ def copy_portal_photo_to_fs(etud):
|
||||||
log("copy_portal_photo_to_fs: getting %s" % url)
|
log("copy_portal_photo_to_fs: getting %s" % url)
|
||||||
r = requests.get(url, timeout=portal_timeout)
|
r = requests.get(url, timeout=portal_timeout)
|
||||||
except:
|
except:
|
||||||
log("download failed: exception:\n%s" % traceback.format_exc())
|
# log("download failed: exception:\n%s" % traceback.format_exc())
|
||||||
log("called from:\n" + "".join(traceback.format_stack()))
|
# log("called from:\n" + "".join(traceback.format_stack()))
|
||||||
|
log("copy_portal_photo_to_fs: error.")
|
||||||
return None, "%s: erreur chargement de %s" % (etud["nomprenom"], url)
|
return None, "%s: erreur chargement de %s" % (etud["nomprenom"], url)
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
log("download failed")
|
log(f"copy_portal_photo_to_fs: download failed {r.status_code }")
|
||||||
return None, "%s: erreur chargement de %s" % (etud["nomprenom"], url)
|
return None, "%s: erreur chargement de %s" % (etud["nomprenom"], url)
|
||||||
data = r.content # image bytes
|
data = r.content # image bytes
|
||||||
try:
|
try:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,7 @@ Recapitule tous les semestres validés dans une feuille excel.
|
||||||
"""
|
"""
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
|
@ -211,12 +211,11 @@ def formsemestre_poursuite_report(formsemestre_id, format="html", REQUEST=None):
|
||||||
)
|
)
|
||||||
tab.caption = "Récapitulatif %s." % sem["titreannee"]
|
tab.caption = "Récapitulatif %s." % sem["titreannee"]
|
||||||
tab.html_caption = "Récapitulatif %s." % sem["titreannee"]
|
tab.html_caption = "Récapitulatif %s." % sem["titreannee"]
|
||||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
|
||||||
return tab.make_page(
|
return tab.make_page(
|
||||||
title="""<h2 class="formsemestre">Poursuite d'études</h2>""",
|
title="""<h2 class="formsemestre">Poursuite d'études</h2>""",
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=["js/etud_info.js"],
|
javascripts=["js/etud_info.js"],
|
||||||
format=format,
|
format=format,
|
||||||
REQUEST=REQUEST,
|
|
||||||
with_html_headers=True,
|
with_html_headers=True,
|
||||||
)
|
)
|
||||||
|
|
|
@ -111,7 +111,8 @@ get_base_preferences(formsemestre_id)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
|
@ -180,7 +181,7 @@ def _convert_pref_type(p, pref_spec):
|
||||||
|
|
||||||
def _get_pref_default_value_from_config(name, pref_spec):
|
def _get_pref_default_value_from_config(name, pref_spec):
|
||||||
"""get default value store in application level config.
|
"""get default value store in application level config.
|
||||||
If not found, use defalut value hardcoded in pref_spec.
|
If not found, use default value hardcoded in pref_spec.
|
||||||
"""
|
"""
|
||||||
# XXX va changer avec la nouvelle base
|
# XXX va changer avec la nouvelle base
|
||||||
# search in scu.CONFIG
|
# search in scu.CONFIG
|
||||||
|
@ -1408,7 +1409,7 @@ class BasePreferences(object):
|
||||||
{
|
{
|
||||||
"initvalue": 1,
|
"initvalue": 1,
|
||||||
"title": "Indique si les bulletins sont publiés",
|
"title": "Indique si les bulletins sont publiés",
|
||||||
"explanation": "décocher si vous n'avez pas de portal étudiant publiant les bulletins",
|
"explanation": "décocher si vous n'avez pas de portail étudiant publiant les bulletins",
|
||||||
"input_type": "boolcheckbox",
|
"input_type": "boolcheckbox",
|
||||||
"labels": ["non", "oui"],
|
"labels": ["non", "oui"],
|
||||||
"category": "bul",
|
"category": "bul",
|
||||||
|
@ -1891,7 +1892,7 @@ class BasePreferences(object):
|
||||||
|
|
||||||
def get(self, formsemestre_id, name):
|
def get(self, formsemestre_id, name):
|
||||||
"""Returns preference value.
|
"""Returns preference value.
|
||||||
If global_lookup, when no value defined for this semestre, returns global value.
|
when no value defined for this semestre, returns global value.
|
||||||
"""
|
"""
|
||||||
params = {
|
params = {
|
||||||
"dept_id": self.dept_id,
|
"dept_id": self.dept_id,
|
||||||
|
@ -1901,7 +1902,7 @@ class BasePreferences(object):
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
plist = self._editor.list(cnx, params)
|
plist = self._editor.list(cnx, params)
|
||||||
if not plist:
|
if not plist:
|
||||||
del params["formsemestre_id"]
|
params["formsemestre_id"] = None
|
||||||
plist = self._editor.list(cnx, params)
|
plist = self._editor.list(cnx, params)
|
||||||
if not plist:
|
if not plist:
|
||||||
return self.default[name]
|
return self.default[name]
|
||||||
|
@ -2022,14 +2023,16 @@ class BasePreferences(object):
|
||||||
html_sco_header.sco_header(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(),
|
"<h2>Préférences globales pour %s</h2>" % scu.ScoURL(),
|
||||||
f"""<p><a href="{url_for("scolar.config_logos", scodoc_dept=g.scodoc_dept)
|
f"""<p><a href="{url_for("scolar.config_logos", scodoc_dept=g.scodoc_dept)
|
||||||
}">modification des logos du département (pour documents pdf)</a></p>""",
|
}">modification des logos du département (pour documents pdf)</a></p>"""
|
||||||
|
if current_user.is_administrator()
|
||||||
|
else "",
|
||||||
"""<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="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>
|
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
form = self.build_tf_form()
|
form = self.build_tf_form()
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
initvalues=self.prefs[None],
|
initvalues=self.prefs[None],
|
||||||
|
@ -2151,7 +2154,7 @@ class SemPreferences(object):
|
||||||
) # a bug !
|
) # a bug !
|
||||||
sem = sco_formsemestre.get_formsemestre(self.formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(self.formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(REQUEST, "Préférences du semestre", sem),
|
html_sco_header.html_sem_header("Préférences du semestre", sem),
|
||||||
"""
|
"""
|
||||||
<p class="help">Les paramètres définis ici ne s'appliqueront qu'à ce semestre.</p>
|
<p class="help">Les paramètres définis ici ne s'appliqueront qu'à ce semestre.</p>
|
||||||
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
||||||
|
@ -2194,7 +2197,7 @@ function set_global_pref(el, pref_name) {
|
||||||
form.append(("destination", {"input_type": "hidden"}))
|
form.append(("destination", {"input_type": "hidden"}))
|
||||||
form.append(("formsemestre_id", {"input_type": "hidden"}))
|
form.append(("formsemestre_id", {"input_type": "hidden"}))
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
initvalues=self,
|
initvalues=self,
|
||||||
|
@ -2245,7 +2248,7 @@ function set_global_pref(el, pref_name) {
|
||||||
return flask.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":
|
elif destination == "again":
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
REQUEST.URL0 + "?formsemestre_id=" + str(self.formsemestre_id)
|
request.base_url + "?formsemestre_id=" + str(self.formsemestre_id)
|
||||||
)
|
)
|
||||||
elif destination == "global":
|
elif destination == "global":
|
||||||
return flask.redirect(scu.ScoURL() + "/edit_preferences")
|
return flask.redirect(scu.ScoURL() + "/edit_preferences")
|
||||||
|
@ -2253,7 +2256,7 @@ function set_global_pref(el, pref_name) {
|
||||||
|
|
||||||
#
|
#
|
||||||
def doc_preferences():
|
def doc_preferences():
|
||||||
""" Liste les preferences en MarkDown, pour la documentation"""
|
"""Liste les preferences en MarkDown, pour la documentation"""
|
||||||
L = []
|
L = []
|
||||||
for cat, cat_descr in PREF_CATEGORIES:
|
for cat, cat_descr in PREF_CATEGORIES:
|
||||||
L.append([""])
|
L.append([""])
|
||||||
|
|
|
@ -31,6 +31,9 @@ import time
|
||||||
|
|
||||||
from openpyxl.styles.numbers import FORMAT_NUMBER_00
|
from openpyxl.styles.numbers import FORMAT_NUMBER_00
|
||||||
|
|
||||||
|
from flask import request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
|
@ -318,9 +321,14 @@ def feuille_preparation_jury(formsemestre_id, REQUEST):
|
||||||
% (
|
% (
|
||||||
sco_version.SCONAME,
|
sco_version.SCONAME,
|
||||||
time.strftime("%d/%m/%Y"),
|
time.strftime("%d/%m/%Y"),
|
||||||
REQUEST.BASE0,
|
request.url_root,
|
||||||
REQUEST.AUTHENTICATED_USER,
|
current_user,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
xls = ws.generate_standalone()
|
xls = ws.generate()
|
||||||
return sco_excel.send_excel_file(REQUEST, xls, f"PrepaJury{sn}{scu.XLSX_SUFFIX}")
|
return scu.send_file(
|
||||||
|
xls,
|
||||||
|
f"PrepaJury{sn}",
|
||||||
|
scu.XLSX_SUFFIX,
|
||||||
|
mime=scu.XLSX_MIMETYPE,
|
||||||
|
)
|
||||||
|
|
|
@ -52,7 +52,7 @@ from reportlab.platypus import Paragraph
|
||||||
from reportlab.lib import styles
|
from reportlab.lib import styles
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -535,13 +535,11 @@ def formsemestre_pvjury(formsemestre_id, format="html", publish=True, REQUEST=No
|
||||||
return tab.make_page(
|
return tab.make_page(
|
||||||
format=format,
|
format=format,
|
||||||
with_html_headers=False,
|
with_html_headers=False,
|
||||||
REQUEST=REQUEST,
|
|
||||||
publish=publish,
|
publish=publish,
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Décisions du jury pour le semestre",
|
"Décisions du jury pour le semestre",
|
||||||
sem,
|
sem,
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
|
@ -628,7 +626,6 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids=[], etudid=None, REQUEST=
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Edition du PV de jury %s" % etuddescr,
|
"Edition du PV de jury %s" % etuddescr,
|
||||||
sem=sem,
|
sem=sem,
|
||||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||||
|
@ -658,7 +655,7 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids=[], etudid=None, REQUEST=
|
||||||
else:
|
else:
|
||||||
menu_choix_groupe = "" # un seul etudiant à editer
|
menu_choix_groupe = "" # un seul etudiant à editer
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
|
@ -707,7 +704,7 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids=[], etudid=None, REQUEST=
|
||||||
else:
|
else:
|
||||||
groups_filename = ""
|
groups_filename = ""
|
||||||
filename = "PV-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
filename = "PV-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
||||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
return scu.sendPDFFile(pdfdoc, filename)
|
||||||
|
|
||||||
|
|
||||||
def descrform_pvjury(sem):
|
def descrform_pvjury(sem):
|
||||||
|
@ -806,8 +803,7 @@ def formsemestre_lettres_individuelles(formsemestre_id, group_ids=[], REQUEST=No
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
"Édition des lettres individuelles",
|
||||||
"Edition des lettres individuelles",
|
|
||||||
sem=sem,
|
sem=sem,
|
||||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||||
cssstyles=sco_groups_view.CSSSTYLES,
|
cssstyles=sco_groups_view.CSSSTYLES,
|
||||||
|
@ -827,7 +823,7 @@ def formsemestre_lettres_individuelles(formsemestre_id, group_ids=[], REQUEST=No
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
|
@ -868,7 +864,7 @@ def formsemestre_lettres_individuelles(formsemestre_id, group_ids=[], REQUEST=No
|
||||||
dt = time.strftime("%Y-%m-%d")
|
dt = time.strftime("%Y-%m-%d")
|
||||||
groups_filename = "-" + groups_infos.groups_filename
|
groups_filename = "-" + groups_infos.groups_filename
|
||||||
filename = "lettres-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
filename = "lettres-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
||||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
return scu.sendPDFFile(pdfdoc, filename)
|
||||||
|
|
||||||
|
|
||||||
def descrform_lettres_individuelles():
|
def descrform_lettres_individuelles():
|
||||||
|
|
|
@ -27,10 +27,13 @@
|
||||||
|
|
||||||
"""Tableau recapitulatif des notes d'un semestre
|
"""Tableau recapitulatif des notes d'un semestre
|
||||||
"""
|
"""
|
||||||
import time
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import json
|
||||||
|
import time
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
from flask import request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
|
@ -100,7 +103,7 @@ def formsemestre_recapcomplet(
|
||||||
sco_formsemestre_status.formsemestre_status_head(
|
sco_formsemestre_status.formsemestre_status_head(
|
||||||
formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
formsemestre_id=formsemestre_id, REQUEST=REQUEST
|
||||||
),
|
),
|
||||||
'<form name="f" method="get" action="%s">' % REQUEST.URL0,
|
'<form name="f" method="get" action="%s">' % request.base_url,
|
||||||
'<input type="hidden" name="formsemestre_id" value="%s"></input>'
|
'<input type="hidden" name="formsemestre_id" value="%s"></input>'
|
||||||
% formsemestre_id,
|
% formsemestre_id,
|
||||||
'<input type="hidden" name="pref_override" value="0"></input>',
|
'<input type="hidden" name="pref_override" value="0"></input>',
|
||||||
|
@ -227,11 +230,14 @@ def do_formsemestre_recapcomplet(
|
||||||
if format == "xml" or format == "html":
|
if format == "xml" or format == "html":
|
||||||
return data
|
return data
|
||||||
elif format == "csv":
|
elif format == "csv":
|
||||||
return scu.sendCSVFile(REQUEST, data, filename)
|
return scu.send_file(data, filename=filename, mime=scu.CSV_MIMETYPE)
|
||||||
elif format[:3] == "xls":
|
elif format.startswith("xls") or format.startswith("xlsx"):
|
||||||
return sco_excel.send_excel_file(REQUEST, data, filename)
|
return scu.send_file(data, filename=filename, mime=scu.XLSX_MIMETYPE)
|
||||||
elif format == "json":
|
elif format == "json":
|
||||||
return scu.sendJSON(REQUEST, data)
|
js = json.dumps(data, indent=1, cls=scu.ScoDocJSONEncoder)
|
||||||
|
return scu.send_file(
|
||||||
|
js, filename=filename, suffix=scu.JSON_SUFFIX, mime=scu.JSON_MIMETYPE
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("unknown format %s" % format)
|
raise ValueError("unknown format %s" % format)
|
||||||
|
|
||||||
|
@ -967,4 +973,4 @@ def formsemestres_bulletins(annee_scolaire, REQUEST=None):
|
||||||
)
|
)
|
||||||
jslist.append(J)
|
jslist.append(J)
|
||||||
|
|
||||||
return scu.sendJSON(REQUEST, jslist)
|
return scu.sendJSON(jslist)
|
||||||
|
|
|
@ -37,7 +37,7 @@ import time
|
||||||
import datetime
|
import datetime
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
import pydot
|
import pydot
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -247,7 +247,7 @@ def formsemestre_report(
|
||||||
sem["titreannee"],
|
sem["titreannee"],
|
||||||
)
|
)
|
||||||
tab.html_caption = "Répartition des résultats par %s." % category_name
|
tab.html_caption = "Répartition des résultats par %s." % category_name
|
||||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
|
||||||
if only_primo:
|
if only_primo:
|
||||||
tab.base_url += "&only_primo=on"
|
tab.base_url += "&only_primo=on"
|
||||||
return tab
|
return tab
|
||||||
|
@ -322,7 +322,7 @@ def formsemestre_report_counts(
|
||||||
F = [
|
F = [
|
||||||
"""<form name="f" method="get" action="%s"><p>
|
"""<form name="f" method="get" action="%s"><p>
|
||||||
Colonnes: <select name="result" onchange="document.f.submit()">"""
|
Colonnes: <select name="result" onchange="document.f.submit()">"""
|
||||||
% REQUEST.URL0
|
% request.base_url
|
||||||
]
|
]
|
||||||
for k in keys:
|
for k in keys:
|
||||||
if k == result:
|
if k == result:
|
||||||
|
@ -355,7 +355,6 @@ def formsemestre_report_counts(
|
||||||
t = tab.make_page(
|
t = tab.make_page(
|
||||||
title="""<h2 class="formsemestre">Comptes croisés</h2>""",
|
title="""<h2 class="formsemestre">Comptes croisés</h2>""",
|
||||||
format=format,
|
format=format,
|
||||||
REQUEST=REQUEST,
|
|
||||||
with_html_headers=False,
|
with_html_headers=False,
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
|
@ -718,15 +717,15 @@ def formsemestre_suivi_cohorte(
|
||||||
)
|
)
|
||||||
tab.base_url = (
|
tab.base_url = (
|
||||||
"%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&civilite=%s"
|
"%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&civilite=%s"
|
||||||
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, civilite)
|
% (request.base_url, formsemestre_id, percent, bac, bacspecialite, civilite)
|
||||||
)
|
)
|
||||||
if only_primo:
|
if only_primo:
|
||||||
tab.base_url += "&only_primo=on"
|
tab.base_url += "&only_primo=on"
|
||||||
t = tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
t = tab.make_page(format=format, with_html_headers=False)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return t
|
return t
|
||||||
|
|
||||||
base_url = REQUEST.URL0
|
base_url = request.base_url
|
||||||
burl = "%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s" % (
|
burl = "%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s" % (
|
||||||
base_url,
|
base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
|
@ -816,7 +815,7 @@ def _gen_form_selectetuds(
|
||||||
<p>Bac: <select name="bac" onchange="javascript: submit(this);">
|
<p>Bac: <select name="bac" onchange="javascript: submit(this);">
|
||||||
<option value="" %s>tous</option>
|
<option value="" %s>tous</option>
|
||||||
"""
|
"""
|
||||||
% (REQUEST.URL0, selected)
|
% (request.base_url, selected)
|
||||||
]
|
]
|
||||||
for b in bacs:
|
for b in bacs:
|
||||||
if bac == b:
|
if bac == b:
|
||||||
|
@ -1167,7 +1166,7 @@ def table_suivi_parcours(formsemestre_id, only_primo=False, grouped_parcours=Tru
|
||||||
|
|
||||||
def tsp_form_primo_group(REQUEST, only_primo, no_grouping, formsemestre_id, format):
|
def tsp_form_primo_group(REQUEST, only_primo, no_grouping, formsemestre_id, format):
|
||||||
"""Element de formulaire pour choisir si restriction aux primos entrants et groupement par lycees"""
|
"""Element de formulaire pour choisir si restriction aux primos entrants et groupement par lycees"""
|
||||||
F = ["""<form name="f" method="get" action="%s">""" % REQUEST.URL0]
|
F = ["""<form name="f" method="get" action="%s">""" % request.base_url]
|
||||||
if only_primo:
|
if only_primo:
|
||||||
checked = 'checked="1"'
|
checked = 'checked="1"'
|
||||||
else:
|
else:
|
||||||
|
@ -1205,12 +1204,12 @@ def formsemestre_suivi_parcours(
|
||||||
only_primo=only_primo,
|
only_primo=only_primo,
|
||||||
grouped_parcours=not no_grouping,
|
grouped_parcours=not no_grouping,
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
|
||||||
if only_primo:
|
if only_primo:
|
||||||
tab.base_url += "&only_primo=1"
|
tab.base_url += "&only_primo=1"
|
||||||
if no_grouping:
|
if no_grouping:
|
||||||
tab.base_url += "&no_grouping=1"
|
tab.base_url += "&no_grouping=1"
|
||||||
t = tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
t = tab.make_page(format=format, with_html_headers=False)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return t
|
return t
|
||||||
F = [
|
F = [
|
||||||
|
@ -1492,7 +1491,7 @@ def formsemestre_graph_parcours(
|
||||||
statut=statut,
|
statut=statut,
|
||||||
)
|
)
|
||||||
filename = scu.make_filename("flux " + sem["titreannee"])
|
filename = scu.make_filename("flux " + sem["titreannee"])
|
||||||
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
return scu.sendPDFFile(doc, filename + ".pdf")
|
||||||
elif format == "png":
|
elif format == "png":
|
||||||
#
|
#
|
||||||
(
|
(
|
||||||
|
|
|
@ -9,48 +9,50 @@ from app.scodoc.sco_permissions import Permission as p
|
||||||
SCO_ROLES_DEFAULTS = {
|
SCO_ROLES_DEFAULTS = {
|
||||||
"Observateur": (p.ScoObservateur,),
|
"Observateur": (p.ScoObservateur,),
|
||||||
"Ens": (
|
"Ens": (
|
||||||
p.ScoObservateur,
|
|
||||||
p.ScoView,
|
|
||||||
p.ScoEnsView,
|
|
||||||
p.ScoUsersView,
|
|
||||||
p.ScoEtudAddAnnotations,
|
|
||||||
p.ScoAbsChange,
|
|
||||||
p.ScoAbsAddBillet,
|
p.ScoAbsAddBillet,
|
||||||
|
p.ScoAbsChange,
|
||||||
|
p.ScoEnsView,
|
||||||
p.ScoEntrepriseView,
|
p.ScoEntrepriseView,
|
||||||
|
p.ScoEtudAddAnnotations,
|
||||||
|
p.ScoObservateur,
|
||||||
|
p.ScoUsersView,
|
||||||
|
p.ScoView,
|
||||||
),
|
),
|
||||||
"Secr": (
|
"Secr": (
|
||||||
p.ScoObservateur,
|
|
||||||
p.ScoView,
|
|
||||||
p.ScoUsersView,
|
|
||||||
p.ScoEtudAddAnnotations,
|
|
||||||
p.ScoAbsChange,
|
|
||||||
p.ScoAbsAddBillet,
|
p.ScoAbsAddBillet,
|
||||||
p.ScoEntrepriseView,
|
p.ScoAbsChange,
|
||||||
|
p.ScoEditApo,
|
||||||
p.ScoEntrepriseChange,
|
p.ScoEntrepriseChange,
|
||||||
|
p.ScoEntrepriseView,
|
||||||
|
p.ScoEtudAddAnnotations,
|
||||||
p.ScoEtudChangeAdr,
|
p.ScoEtudChangeAdr,
|
||||||
|
p.ScoObservateur,
|
||||||
|
p.ScoUsersView,
|
||||||
|
p.ScoView,
|
||||||
),
|
),
|
||||||
# Admin est le chef du département, pas le "super admin"
|
# Admin est le chef du département, pas le "super admin"
|
||||||
# on doit donc lister toutes ses permissions:
|
# on doit donc lister toutes ses permissions:
|
||||||
"Admin": (
|
"Admin": (
|
||||||
p.ScoObservateur,
|
|
||||||
p.ScoView,
|
|
||||||
p.ScoEnsView,
|
|
||||||
p.ScoUsersView,
|
|
||||||
p.ScoEtudAddAnnotations,
|
|
||||||
p.ScoAbsChange,
|
|
||||||
p.ScoAbsAddBillet,
|
p.ScoAbsAddBillet,
|
||||||
p.ScoEntrepriseView,
|
p.ScoAbsChange,
|
||||||
p.ScoEntrepriseChange,
|
|
||||||
p.ScoEtudChangeAdr,
|
|
||||||
p.ScoChangeFormation,
|
p.ScoChangeFormation,
|
||||||
p.ScoEditFormationTags,
|
p.ScoChangePreferences,
|
||||||
p.ScoEditAllNotes,
|
|
||||||
p.ScoEditAllEvals,
|
p.ScoEditAllEvals,
|
||||||
p.ScoImplement,
|
p.ScoEditAllNotes,
|
||||||
|
p.ScoEditApo,
|
||||||
|
p.ScoEditFormationTags,
|
||||||
|
p.ScoEnsView,
|
||||||
|
p.ScoEntrepriseChange,
|
||||||
|
p.ScoEntrepriseView,
|
||||||
|
p.ScoEtudAddAnnotations,
|
||||||
|
p.ScoEtudChangeAdr,
|
||||||
p.ScoEtudChangeGroups,
|
p.ScoEtudChangeGroups,
|
||||||
p.ScoEtudInscrit,
|
p.ScoEtudInscrit,
|
||||||
|
p.ScoImplement,
|
||||||
|
p.ScoObservateur,
|
||||||
p.ScoUsersAdmin,
|
p.ScoUsersAdmin,
|
||||||
p.ScoChangePreferences,
|
p.ScoUsersView,
|
||||||
|
p.ScoView,
|
||||||
),
|
),
|
||||||
# RespPE est le responsable poursuites d'études
|
# RespPE est le responsable poursuites d'études
|
||||||
# il peut ajouter des tags sur les formations:
|
# il peut ajouter des tags sur les formations:
|
||||||
|
|
|
@ -35,7 +35,7 @@ import datetime
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for
|
from flask import g, url_for, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -168,7 +168,7 @@ def do_evaluation_upload_xls(REQUEST):
|
||||||
"""
|
"""
|
||||||
Soumission d'un fichier XLS (evaluation_id, notefile)
|
Soumission d'un fichier XLS (evaluation_id, notefile)
|
||||||
"""
|
"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
evaluation_id = int(REQUEST.form["evaluation_id"])
|
evaluation_id = int(REQUEST.form["evaluation_id"])
|
||||||
comment = REQUEST.form["comment"]
|
comment = REQUEST.form["comment"]
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
|
@ -494,9 +494,10 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
||||||
}
|
}
|
||||||
ndb.quote_dict(aa)
|
ndb.quote_dict(aa)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""INSERT INTO notes_notes
|
"""INSERT INTO notes_notes
|
||||||
(etudid,evaluation_id,value,comment,date,uid)
|
(etudid, evaluation_id, value, comment, date, uid)
|
||||||
VALUES (%(etudid)s,%(evaluation_id)s,%(value)s,%(comment)s,%(date)s,%(uid)s)""",
|
VALUES (%(etudid)s,%(evaluation_id)s,%(value)s,%(comment)s,%(date)s,%(uid)s)
|
||||||
|
""",
|
||||||
aa,
|
aa,
|
||||||
)
|
)
|
||||||
changed = True
|
changed = True
|
||||||
|
@ -515,10 +516,10 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
||||||
# recopie l'ancienne note dans notes_notes_log, puis update
|
# recopie l'ancienne note dans notes_notes_log, puis update
|
||||||
if do_it:
|
if do_it:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""INSERT INTO notes_notes_log
|
"""INSERT INTO notes_notes_log
|
||||||
(etudid,evaluation_id,value,comment,date,uid)
|
(etudid,evaluation_id,value,comment,date,uid)
|
||||||
SELECT etudid, evaluation_id, value, comment, date, uid
|
SELECT etudid, evaluation_id, value, comment, date, uid
|
||||||
FROM notes_notes
|
FROM notes_notes
|
||||||
WHERE etudid=%(etudid)s
|
WHERE etudid=%(etudid)s
|
||||||
and evaluation_id=%(evaluation_id)s
|
and evaluation_id=%(evaluation_id)s
|
||||||
""",
|
""",
|
||||||
|
@ -536,8 +537,8 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
||||||
if value != scu.NOTES_SUPPRESS:
|
if value != scu.NOTES_SUPPRESS:
|
||||||
if do_it:
|
if do_it:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""UPDATE notes_notes
|
"""UPDATE notes_notes
|
||||||
SET value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
|
SET value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
|
||||||
WHERE etudid = %(etudid)s
|
WHERE etudid = %(etudid)s
|
||||||
and evaluation_id = %(evaluation_id)s
|
and evaluation_id = %(evaluation_id)s
|
||||||
""",
|
""",
|
||||||
|
@ -550,7 +551,7 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
||||||
% (evaluation_id, etudid, oldval)
|
% (evaluation_id, etudid, oldval)
|
||||||
)
|
)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""DELETE FROM notes_notes
|
"""DELETE FROM notes_notes
|
||||||
WHERE etudid = %(etudid)s
|
WHERE etudid = %(etudid)s
|
||||||
AND evaluation_id = %(evaluation_id)s
|
AND evaluation_id = %(evaluation_id)s
|
||||||
""",
|
""",
|
||||||
|
@ -589,18 +590,17 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
||||||
|
|
||||||
def saisie_notes_tableur(evaluation_id, group_ids=[], REQUEST=None):
|
def saisie_notes_tableur(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
"""Saisie des notes via un fichier Excel"""
|
"""Saisie des notes via un fichier Excel"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
|
||||||
authusername = str(authuser)
|
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
||||||
return (
|
return (
|
||||||
html_sco_header.sco_header()
|
html_sco_header.sco_header()
|
||||||
+ "<h2>Modification des notes impossible pour %s</h2>" % authusername
|
+ "<h2>Modification des notes impossible pour %s</h2>"
|
||||||
|
% current_user.user_name
|
||||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||||
avez l'autorisation d'effectuer cette opération)</p>
|
avez l'autorisation d'effectuer cette opération)</p>
|
||||||
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
||||||
|
@ -657,7 +657,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
nf = TrivialFormulator(
|
nf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
|
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
|
||||||
|
@ -711,7 +711,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
#
|
#
|
||||||
H.append("""</div><h3>Autres opérations</h3><ul>""")
|
H.append("""</div><h3>Autres opérations</h3><ul>""")
|
||||||
if sco_permissions_check.can_edit_notes(
|
if sco_permissions_check.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
):
|
):
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
|
@ -829,7 +829,8 @@ def feuille_saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
|
|
||||||
filename = "notes_%s_%s.xlsx" % (evalname, gr_title_filename)
|
filename = "notes_%s_%s.xlsx" % (evalname, gr_title_filename)
|
||||||
xls = sco_excel.excel_feuille_saisie(E, sem["titreannee"], description, lines=L)
|
xls = sco_excel.excel_feuille_saisie(E, sem["titreannee"], description, lines=L)
|
||||||
return sco_excel.send_excel_file(REQUEST, xls, filename)
|
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)
|
||||||
|
# return sco_excel.send_excel_file(REQUEST, xls, filename)
|
||||||
|
|
||||||
|
|
||||||
def has_existing_decision(M, E, etudid):
|
def has_existing_decision(M, E, etudid):
|
||||||
|
@ -858,9 +859,7 @@ def has_existing_decision(M, E, etudid):
|
||||||
|
|
||||||
def saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
|
def saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
"""Formulaire saisie notes d'une évaluation pour un groupe"""
|
"""Formulaire saisie notes d'une évaluation pour un groupe"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
group_ids = [int(group_id) for group_id in group_ids]
|
||||||
authusername = str(authuser)
|
|
||||||
|
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
|
@ -871,10 +870,11 @@ def saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and responsable_id)
|
||||||
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):
|
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
||||||
return (
|
return (
|
||||||
html_sco_header.sco_header()
|
html_sco_header.sco_header()
|
||||||
+ "<h2>Modification des notes impossible pour %s</h2>" % authusername
|
+ "<h2>Modification des notes impossible pour %s</h2>"
|
||||||
|
% current_user.user_name
|
||||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||||
avez l'autorisation d'effectuer cette opération)</p>
|
avez l'autorisation d'effectuer cette opération)</p>
|
||||||
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
||||||
|
@ -1154,9 +1154,9 @@ def _form_saisie_notes(E, M, group_ids, destination="", REQUEST=None):
|
||||||
"attributes": [
|
"attributes": [
|
||||||
'class="note%s"' % classdem,
|
'class="note%s"' % classdem,
|
||||||
disabled_attr,
|
disabled_attr,
|
||||||
"data-last-saved-value=%s" % e["val"],
|
'data-last-saved-value="%s"' % e["val"],
|
||||||
"data-orig-value=%s" % e["val"],
|
'data-orig-value="%s"' % e["val"],
|
||||||
"data-etudid=%s" % etudid,
|
'data-etudid="%s"' % etudid,
|
||||||
],
|
],
|
||||||
"template": """<tr%(item_dom_attr)s class="etud_elem """
|
"template": """<tr%(item_dom_attr)s class="etud_elem """
|
||||||
+ " ".join(etud_classes)
|
+ " ".join(etud_classes)
|
||||||
|
@ -1222,7 +1222,7 @@ def _form_saisie_notes(E, M, group_ids, destination="", REQUEST=None):
|
||||||
|
|
||||||
def save_note(etudid=None, evaluation_id=None, value=None, comment="", REQUEST=None):
|
def save_note(etudid=None, evaluation_id=None, value=None, comment="", REQUEST=None):
|
||||||
"""Enregistre une note (ajax)"""
|
"""Enregistre une note (ajax)"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
log(
|
log(
|
||||||
"save_note: evaluation_id=%s etudid=%s uid=%s value=%s"
|
"save_note: evaluation_id=%s etudid=%s uid=%s value=%s"
|
||||||
% (evaluation_id, etudid, authuser, value)
|
% (evaluation_id, etudid, authuser, value)
|
||||||
|
@ -1259,7 +1259,7 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment="", REQUEST=N
|
||||||
else:
|
else:
|
||||||
result["history_menu"] = "" # no update needed
|
result["history_menu"] = "" # no update needed
|
||||||
result["status"] = "ok"
|
result["status"] = "ok"
|
||||||
return scu.sendJSON(REQUEST, result)
|
return scu.sendJSON(result)
|
||||||
|
|
||||||
|
|
||||||
def get_note_history_menu(evaluation_id, etudid):
|
def get_note_history_menu(evaluation_id, etudid):
|
||||||
|
@ -1290,7 +1290,7 @@ def get_note_history_menu(evaluation_id, etudid):
|
||||||
nv = "" # ne repete pas la valeur de la note courante
|
nv = "" # ne repete pas la valeur de la note courante
|
||||||
else:
|
else:
|
||||||
# ancienne valeur
|
# ancienne valeur
|
||||||
nv = '<span class="histvalue">: %s</span>' % dispnote
|
nv = ": %s" % dispnote
|
||||||
first = False
|
first = False
|
||||||
if i["comment"]:
|
if i["comment"]:
|
||||||
comment = ' <span class="histcomment">%s</span>' % i["comment"]
|
comment = ' <span class="histcomment">%s</span>' % i["comment"]
|
||||||
|
|
|
@ -171,7 +171,7 @@ class SemSet(dict):
|
||||||
def remove(self, formsemestre_id):
|
def remove(self, formsemestre_id):
|
||||||
ndb.SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
"""DELETE FROM notes_semset_formsemestre
|
"""DELETE FROM notes_semset_formsemestre
|
||||||
WHERE id=%(semset_id)s
|
WHERE semset_id=%(semset_id)s
|
||||||
AND formsemestre_id=%(formsemestre_id)s
|
AND formsemestre_id=%(formsemestre_id)s
|
||||||
""",
|
""",
|
||||||
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
|
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
|
||||||
|
@ -418,7 +418,7 @@ def do_semset_remove_sem(semset_id, formsemestre_id):
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def semset_page(format="html", REQUEST=None):
|
def semset_page(format="html"):
|
||||||
"""Page avec liste semsets:
|
"""Page avec liste semsets:
|
||||||
Table avec : date_debut date_fin titre liste des semestres
|
Table avec : date_debut date_fin titre liste des semestres
|
||||||
"""
|
"""
|
||||||
|
@ -468,7 +468,7 @@ def semset_page(format="html", REQUEST=None):
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
page_title = "Ensembles de semestres"
|
page_title = "Ensembles de semestres"
|
||||||
H = [
|
H = [
|
||||||
|
|
|
@ -32,7 +32,7 @@ import time
|
||||||
import pprint
|
import pprint
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import g, url_for, send_file
|
from flask import g, url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -112,6 +112,7 @@ def formsemestre_synchro_etuds(
|
||||||
base_url = url_for(
|
base_url = url_for(
|
||||||
"notes.formsemestre_synchro_etuds",
|
"notes.formsemestre_synchro_etuds",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=formsemestre_id,
|
||||||
anneeapogee=anneeapogee or None, # si None, le param n'est pas dans l'URL
|
anneeapogee=anneeapogee or None, # si None, le param n'est pas dans l'URL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -146,11 +147,11 @@ def formsemestre_synchro_etuds(
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
read_only=read_only,
|
read_only=read_only,
|
||||||
)
|
)
|
||||||
return send_file(
|
return scu.send_file(
|
||||||
xls,
|
xls,
|
||||||
mimetype=scu.XLS_MIMETYPE,
|
mime=scu.XLS_MIMETYPE,
|
||||||
download_name=scu.sanitize_filename(filename + scu.XLSX_SUFFIX),
|
filename=filename,
|
||||||
as_attachment=True,
|
suffix=scu.XLSX_SUFFIX,
|
||||||
)
|
)
|
||||||
|
|
||||||
H = [header]
|
H = [header]
|
||||||
|
@ -317,7 +318,8 @@ def build_page(
|
||||||
"""
|
"""
|
||||||
% sem,
|
% sem,
|
||||||
"""
|
"""
|
||||||
Année Apogée: <select id="anneeapogee" name="anneeapogee" onchange="document.location='formsemestre_synchro_etuds?formsemestre_id=%s&anneeapogee='+document.getElementById('anneeapogee').value">"""
|
Année Apogée: <select id="anneeapogee" name="anneeapogee"
|
||||||
|
onchange="document.location='formsemestre_synchro_etuds?formsemestre_id=%s&anneeapogee='+document.getElementById('anneeapogee').value">"""
|
||||||
% (sem["formsemestre_id"]),
|
% (sem["formsemestre_id"]),
|
||||||
"\n".join(options),
|
"\n".join(options),
|
||||||
"""
|
"""
|
||||||
|
@ -430,17 +432,20 @@ def list_synch(sem, anneeapogee=None):
|
||||||
return etuds
|
return etuds
|
||||||
|
|
||||||
#
|
#
|
||||||
r = {
|
boites = {
|
||||||
"etuds_ok": {
|
"etuds_a_importer": {
|
||||||
"etuds": set_to_sorted_list(etuds_ok, is_inscrit=True),
|
"etuds": set_to_sorted_list(a_importer, is_inscrit=True, etud_apo=True),
|
||||||
"infos": {
|
"infos": {
|
||||||
"id": "etuds_ok",
|
"id": "etuds_a_importer",
|
||||||
"title": "Etudiants dans Apogée et déjà inscrits",
|
"title": "Etudiants dans Apogée à importer",
|
||||||
"help": "Ces etudiants sont inscrits dans le semestre ScoDoc et sont présents dans Apogée: tout est donc correct. Décocher les étudiants que vous souhaitez désinscrire.",
|
"help": """Ces étudiants sont inscrits dans cette étape Apogée mais ne sont pas connus par ScoDoc:
|
||||||
|
cocher les noms à importer et inscrire puis appuyer sur le bouton "Appliquer".""",
|
||||||
"title_target": "",
|
"title_target": "",
|
||||||
"with_checkbox": True,
|
"with_checkbox": True,
|
||||||
"etud_key": EKEY_SCO,
|
"etud_key": EKEY_APO, # clé à stocker dans le formulaire html
|
||||||
|
"filename": "etuds_a_importer",
|
||||||
},
|
},
|
||||||
|
"nomprenoms": etudsapo_ident,
|
||||||
},
|
},
|
||||||
"etuds_noninscrits": {
|
"etuds_noninscrits": {
|
||||||
"etuds": set_to_sorted_list(etuds_noninscrits, is_inscrit=True),
|
"etuds": set_to_sorted_list(etuds_noninscrits, is_inscrit=True),
|
||||||
|
@ -453,20 +458,9 @@ def list_synch(sem, anneeapogee=None):
|
||||||
"title_target": "",
|
"title_target": "",
|
||||||
"with_checkbox": True,
|
"with_checkbox": True,
|
||||||
"etud_key": EKEY_SCO,
|
"etud_key": EKEY_SCO,
|
||||||
|
"filename": "etuds_non_inscrits",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"etuds_a_importer": {
|
|
||||||
"etuds": set_to_sorted_list(a_importer, is_inscrit=True, etud_apo=True),
|
|
||||||
"infos": {
|
|
||||||
"id": "etuds_a_importer",
|
|
||||||
"title": "Etudiants dans Apogée à importer",
|
|
||||||
"help": """Ces étudiants sont inscrits dans cette étape Apogée mais ne sont pas connus par ScoDoc: cocher les noms à importer et inscrire puis appuyer sur le bouton "Appliquer".""",
|
|
||||||
"title_target": "",
|
|
||||||
"with_checkbox": True,
|
|
||||||
"etud_key": EKEY_APO, # clé à stocker dans le formulaire html
|
|
||||||
},
|
|
||||||
"nomprenoms": etudsapo_ident,
|
|
||||||
},
|
|
||||||
"etuds_nonapogee": {
|
"etuds_nonapogee": {
|
||||||
"etuds": set_to_sorted_list(etuds_nonapogee, is_inscrit=True),
|
"etuds": set_to_sorted_list(etuds_nonapogee, is_inscrit=True),
|
||||||
"infos": {
|
"infos": {
|
||||||
|
@ -478,6 +472,7 @@ def list_synch(sem, anneeapogee=None):
|
||||||
"title_target": "",
|
"title_target": "",
|
||||||
"with_checkbox": True,
|
"with_checkbox": True,
|
||||||
"etud_key": EKEY_SCO,
|
"etud_key": EKEY_SCO,
|
||||||
|
"filename": "etuds_non_apogee",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"inscrits_without_key": {
|
"inscrits_without_key": {
|
||||||
|
@ -489,11 +484,25 @@ def list_synch(sem, anneeapogee=None):
|
||||||
"title_target": "",
|
"title_target": "",
|
||||||
"with_checkbox": True,
|
"with_checkbox": True,
|
||||||
"checkbox_name": "inscrits_without_key",
|
"checkbox_name": "inscrits_without_key",
|
||||||
|
"filename": "inscrits_without_key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"etuds_ok": {
|
||||||
|
"etuds": set_to_sorted_list(etuds_ok, is_inscrit=True),
|
||||||
|
"infos": {
|
||||||
|
"id": "etuds_ok",
|
||||||
|
"title": "Etudiants dans Apogée et déjà inscrits",
|
||||||
|
"help": """Ces etudiants sont inscrits dans le semestre ScoDoc et sont présents dans Apogée:
|
||||||
|
tout est donc correct. Décocher les étudiants que vous souhaitez désinscrire.""",
|
||||||
|
"title_target": "",
|
||||||
|
"with_checkbox": True,
|
||||||
|
"etud_key": EKEY_SCO,
|
||||||
|
"filename": "etuds_inscrits_ok_apo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
r,
|
boites,
|
||||||
a_importer,
|
a_importer,
|
||||||
etuds_noninscrits,
|
etuds_noninscrits,
|
||||||
inscrits_set,
|
inscrits_set,
|
||||||
|
|
|
@ -214,7 +214,7 @@ def module_tag_search(term, REQUEST=None):
|
||||||
)
|
)
|
||||||
data = [x["title"] for x in r]
|
data = [x["title"] for x in r]
|
||||||
|
|
||||||
return scu.sendJSON(REQUEST, data)
|
return scu.sendJSON(data)
|
||||||
|
|
||||||
|
|
||||||
def module_tag_list(module_id=""):
|
def module_tag_list(module_id=""):
|
||||||
|
|
|
@ -44,7 +44,7 @@ from reportlab.lib import colors
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, send_file
|
from flask import url_for, g, send_file, request
|
||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -104,7 +104,7 @@ def _trombino_html_header():
|
||||||
return html_sco_header.sco_header(javascripts=["js/trombino.js"])
|
return html_sco_header.sco_header(javascripts=["js/trombino.js"])
|
||||||
|
|
||||||
|
|
||||||
def trombino_html(groups_infos, REQUEST=None):
|
def trombino_html(groups_infos):
|
||||||
"HTML snippet for trombino (with title and menu)"
|
"HTML snippet for trombino (with title and menu)"
|
||||||
menuTrombi = [
|
menuTrombi = [
|
||||||
{
|
{
|
||||||
|
@ -150,7 +150,7 @@ def trombino_html(groups_infos, REQUEST=None):
|
||||||
% t["etudid"]
|
% t["etudid"]
|
||||||
)
|
)
|
||||||
if sco_photos.etud_photo_is_local(t, size="small"):
|
if sco_photos.etud_photo_is_local(t, size="small"):
|
||||||
foto = sco_photos.etud_photo_html(t, title="", REQUEST=REQUEST)
|
foto = sco_photos.etud_photo_html(t, title="")
|
||||||
else: # la photo n'est pas immédiatement dispo
|
else: # la photo n'est pas immédiatement dispo
|
||||||
foto = (
|
foto = (
|
||||||
'<span class="unloaded_img" id="%s"><img border="0" height="90" alt="en cours" src="/ScoDoc/static/icons/loading.jpg"/></span>'
|
'<span class="unloaded_img" id="%s"><img border="0" height="90" alt="en cours" src="/ScoDoc/static/icons/loading.jpg"/></span>'
|
||||||
|
@ -466,7 +466,7 @@ def _listeappel_photos_pdf(groups_infos, REQUEST):
|
||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = report.getvalue()
|
data = report.getvalue()
|
||||||
|
|
||||||
return scu.sendPDFFile(REQUEST, data, filename)
|
return scu.sendPDFFile(data, filename)
|
||||||
|
|
||||||
|
|
||||||
# --------------------- Upload des photos de tout un groupe
|
# --------------------- Upload des photos de tout un groupe
|
||||||
|
@ -486,7 +486,10 @@ def photos_generate_excel_sample(group_ids=[], REQUEST=None):
|
||||||
],
|
],
|
||||||
extra_cols=["fichier_photo"],
|
extra_cols=["fichier_photo"],
|
||||||
)
|
)
|
||||||
return sco_excel.send_excel_file(REQUEST, data, "ImportPhotos" + scu.XLSX_SUFFIX)
|
return scu.send_file(
|
||||||
|
data, "ImportPhotos", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
|
||||||
|
)
|
||||||
|
# return sco_excel.send_excel_file(REQUEST, data, "ImportPhotos" + scu.XLSX_SUFFIX)
|
||||||
|
|
||||||
|
|
||||||
def photos_import_files_form(group_ids=[], REQUEST=None):
|
def photos_import_files_form(group_ids=[], REQUEST=None):
|
||||||
|
@ -516,7 +519,7 @@ def photos_import_files_form(group_ids=[], REQUEST=None):
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
REQUEST.form["group_ids"] = groups_infos.group_ids
|
REQUEST.form["group_ids"] = groups_infos.group_ids
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("xlsfile", {"title": "Fichier Excel:", "input_type": "file", "size": 40}),
|
("xlsfile", {"title": "Fichier Excel:", "input_type": "file", "size": 40}),
|
||||||
|
|
|
@ -272,7 +272,7 @@ def pdf_trombino_tours(
|
||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = report.getvalue()
|
data = report.getvalue()
|
||||||
|
|
||||||
return scu.sendPDFFile(REQUEST, data, filename)
|
return scu.sendPDFFile(data, filename)
|
||||||
|
|
||||||
|
|
||||||
# Feuille d'absences en pdf avec photos:
|
# Feuille d'absences en pdf avec photos:
|
||||||
|
@ -466,4 +466,4 @@ def pdf_feuille_releve_absences(
|
||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = report.getvalue()
|
data = report.getvalue()
|
||||||
|
|
||||||
return scu.sendPDFFile(REQUEST, data, filename)
|
return scu.sendPDFFile(data, filename)
|
||||||
|
|
|
@ -54,6 +54,7 @@ Solution proposée (nov 2014):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
|
from flask import request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
|
@ -168,7 +169,7 @@ def external_ue_inscrit_et_note(
|
||||||
)
|
)
|
||||||
# Saisie des notes
|
# Saisie des notes
|
||||||
_, _, _ = sco_saisie_notes._notes_add(
|
_, _, _ = sco_saisie_notes._notes_add(
|
||||||
REQUEST.AUTHENTICATED_USER,
|
current_user,
|
||||||
evaluation_id,
|
evaluation_id,
|
||||||
list(notes_etuds.items()),
|
list(notes_etuds.items()),
|
||||||
do_it=True,
|
do_it=True,
|
||||||
|
@ -221,7 +222,6 @@ def external_ue_create_form(formsemestre_id, etudid, REQUEST=None):
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Ajout d'une UE externe pour %(nomprenom)s" % etud,
|
"Ajout d'une UE externe pour %(nomprenom)s" % etud,
|
||||||
sem,
|
sem,
|
||||||
javascripts=["js/sco_ue_external.js"],
|
javascripts=["js/sco_ue_external.js"],
|
||||||
|
@ -248,7 +248,7 @@ def external_ue_create_form(formsemestre_id, etudid, REQUEST=None):
|
||||||
default_label = "Aucune UE externe existante"
|
default_label = "Aucune UE externe existante"
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("formsemestre_id", {"input_type": "hidden"}),
|
("formsemestre_id", {"input_type": "hidden"}),
|
||||||
|
|
|
@ -46,6 +46,8 @@ Opérations:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
from flask import request
|
||||||
|
|
||||||
from app.scodoc.intervals import intervalmap
|
from app.scodoc.intervals import intervalmap
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
@ -167,7 +169,7 @@ def evaluation_list_operations(evaluation_id, REQUEST=None):
|
||||||
% (E["description"], E["jour"]),
|
% (E["description"], E["jour"]),
|
||||||
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
|
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
|
||||||
)
|
)
|
||||||
return tab.make_page(REQUEST=REQUEST)
|
return tab.make_page()
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_list_saisies_notes(formsemestre_id, format="html", REQUEST=None):
|
def formsemestre_list_saisies_notes(formsemestre_id, format="html", REQUEST=None):
|
||||||
|
@ -217,12 +219,12 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html", REQUEST=None
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
caption="Saisies de notes dans %s" % sem["titreannee"],
|
caption="Saisies de notes dans %s" % sem["titreannee"],
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
|
||||||
origin="Généré par %s le " % sco_version.SCONAME
|
origin="Généré par %s le " % sco_version.SCONAME
|
||||||
+ scu.timedate_human_repr()
|
+ scu.timedate_human_repr()
|
||||||
+ "",
|
+ "",
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def get_note_history(evaluation_id, etudid, REQUEST=None, fmt=""):
|
def get_note_history(evaluation_id, etudid, REQUEST=None, fmt=""):
|
||||||
|
@ -261,7 +263,7 @@ def get_note_history(evaluation_id, etudid, REQUEST=None, fmt=""):
|
||||||
x["user_name"] = sco_users.user_info(x["uid"])["nomcomplet"]
|
x["user_name"] = sco_users.user_info(x["uid"])["nomcomplet"]
|
||||||
|
|
||||||
if fmt == "json":
|
if fmt == "json":
|
||||||
return scu.sendJSON(REQUEST, history)
|
return scu.sendJSON(history)
|
||||||
else:
|
else:
|
||||||
return history
|
return history
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
# Anciennement ZScoUsers.py, fonctions de gestion des données réécrite avec flask/SQLAlchemy
|
# Anciennement ZScoUsers.py, fonctions de gestion des données réécrite avec flask/SQLAlchemy
|
||||||
|
|
||||||
from flask import url_for, g
|
from flask import url_for, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import cracklib # pylint: disable=import-error
|
import cracklib # pylint: disable=import-error
|
||||||
|
@ -51,11 +51,7 @@ import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
ScoException,
|
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
ScoInvalidDateError,
|
|
||||||
ScoLockedFormError,
|
|
||||||
ScoGenError,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,7 +82,7 @@ def index_html(REQUEST, all_depts=False, with_inactives=False, format="html"):
|
||||||
all_depts = int(all_depts)
|
all_depts = int(all_depts)
|
||||||
with_inactives = int(with_inactives)
|
with_inactives = int(with_inactives)
|
||||||
|
|
||||||
H = [html_sco_header.html_sem_header(REQUEST, "Gestion des utilisateurs")]
|
H = [html_sco_header.html_sem_header("Gestion des utilisateurs")]
|
||||||
|
|
||||||
if current_user.has_permission(Permission.ScoUsersAdmin, g.scodoc_dept):
|
if current_user.has_permission(Permission.ScoUsersAdmin, g.scodoc_dept):
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -117,7 +113,7 @@ def index_html(REQUEST, all_depts=False, with_inactives=False, format="html"):
|
||||||
<input type="checkbox" name="all_depts" value="1" onchange="document.f.submit();" %s>Tous les départements</input>
|
<input type="checkbox" name="all_depts" value="1" onchange="document.f.submit();" %s>Tous les départements</input>
|
||||||
<input type="checkbox" name="with_inactives" value="1" onchange="document.f.submit();" %s>Avec anciens utilisateurs</input>
|
<input type="checkbox" name="with_inactives" value="1" onchange="document.f.submit();" %s>Avec anciens utilisateurs</input>
|
||||||
</form></p>"""
|
</form></p>"""
|
||||||
% (REQUEST.URL0, checked, olds_checked)
|
% (request.base_url, checked, olds_checked)
|
||||||
)
|
)
|
||||||
|
|
||||||
L = list_users(
|
L = list_users(
|
||||||
|
@ -212,12 +208,12 @@ def list_users(
|
||||||
html_class="table_leftalign list_users",
|
html_class="table_leftalign list_users",
|
||||||
html_with_td_classes=True,
|
html_with_td_classes=True,
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
base_url="%s?all=%s" % (REQUEST.URL0, all),
|
base_url="%s?all=%s" % (request.base_url, all),
|
||||||
pdf_link=False, # table is too wide to fit in a paper page => disable pdf
|
pdf_link=False, # table is too wide to fit in a paper page => disable pdf
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tab.make_page(format=format, with_html_headers=False, REQUEST=REQUEST)
|
return tab.make_page(format=format, with_html_headers=False)
|
||||||
|
|
||||||
|
|
||||||
def get_user_list(dept=None, with_inactives=False):
|
def get_user_list(dept=None, with_inactives=False):
|
||||||
|
|
|
@ -39,21 +39,18 @@ import os
|
||||||
import pydot
|
import pydot
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
import six
|
import _thread
|
||||||
import six.moves._thread
|
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
import types
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import urllib
|
import urllib
|
||||||
from xml.etree import ElementTree
|
from urllib.parse import urlparse, parse_qsl, urlunparse, urlencode
|
||||||
|
|
||||||
from flask import g, current_app
|
from flask import g, current_app
|
||||||
|
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
from flask import g, url_for, request
|
from flask import g, url_for, request, make_response
|
||||||
|
from werkzeug.wrappers import response
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app import log
|
from app import log
|
||||||
|
@ -217,7 +214,7 @@ def group_by_key(d, key):
|
||||||
|
|
||||||
|
|
||||||
# ----- Global lock for critical sections (except notes_tables caches)
|
# ----- Global lock for critical sections (except notes_tables caches)
|
||||||
GSL = six.moves._thread.allocate_lock() # Global ScoDoc Lock
|
GSL = _thread.allocate_lock() # Global ScoDoc Lock
|
||||||
|
|
||||||
SCODOC_DIR = Config.SCODOC_DIR
|
SCODOC_DIR = Config.SCODOC_DIR
|
||||||
|
|
||||||
|
@ -228,7 +225,7 @@ SCODOC_CFG_DIR = os.path.join(Config.SCODOC_VAR_DIR, "config")
|
||||||
SCODOC_VERSION_DIR = os.path.join(SCODOC_CFG_DIR, "version")
|
SCODOC_VERSION_DIR = os.path.join(SCODOC_CFG_DIR, "version")
|
||||||
# ----- Repertoire tmp : /opt/scodoc-data/tmp
|
# ----- Repertoire tmp : /opt/scodoc-data/tmp
|
||||||
SCO_TMP_DIR = os.path.join(Config.SCODOC_VAR_DIR, "tmp")
|
SCO_TMP_DIR = os.path.join(Config.SCODOC_VAR_DIR, "tmp")
|
||||||
if not os.path.exists(SCO_TMP_DIR):
|
if not os.path.exists(SCO_TMP_DIR) and os.path.exists(Config.SCODOC_VAR_DIR):
|
||||||
os.mkdir(SCO_TMP_DIR, 0o755)
|
os.mkdir(SCO_TMP_DIR, 0o755)
|
||||||
# ----- Les logos: /opt/scodoc-data/config/logos
|
# ----- Les logos: /opt/scodoc-data/config/logos
|
||||||
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
||||||
|
@ -296,16 +293,39 @@ SCO_DEV_MAIL = "emmanuel.viennet@gmail.com" # SVP ne pas changer
|
||||||
# Adresse pour l'envoi des dumps (pour assistance technnique):
|
# Adresse pour l'envoi des dumps (pour assistance technnique):
|
||||||
# ne pas changer (ou vous perdez le support)
|
# ne pas changer (ou vous perdez le support)
|
||||||
SCO_DUMP_UP_URL = "https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/upload-dump"
|
SCO_DUMP_UP_URL = "https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/upload-dump"
|
||||||
|
# SCO_DUMP_UP_URL = "http://192.168.56.1:5000/upload_dump"
|
||||||
|
|
||||||
CSV_FIELDSEP = ";"
|
CSV_FIELDSEP = ";"
|
||||||
CSV_LINESEP = "\n"
|
CSV_LINESEP = "\n"
|
||||||
CSV_MIMETYPE = "text/comma-separated-values"
|
CSV_MIMETYPE = "text/comma-separated-values"
|
||||||
|
CSV_SUFFIX = ".csv"
|
||||||
|
JSON_MIMETYPE = "application/json"
|
||||||
|
JSON_SUFFIX = ".json"
|
||||||
|
PDF_MIMETYPE = "application/pdf"
|
||||||
|
PDF_SUFFIX = ".pdf"
|
||||||
XLS_MIMETYPE = "application/vnd.ms-excel"
|
XLS_MIMETYPE = "application/vnd.ms-excel"
|
||||||
|
XLS_SUFFIX = ".xls"
|
||||||
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
XLSX_SUFFIX = ".xlsx"
|
XLSX_SUFFIX = ".xlsx"
|
||||||
PDF_MIMETYPE = "application/pdf"
|
|
||||||
XML_MIMETYPE = "text/xml"
|
XML_MIMETYPE = "text/xml"
|
||||||
JSON_MIMETYPE = "application/json"
|
XML_SUFFIX = ".xml"
|
||||||
|
|
||||||
|
|
||||||
|
def get_mime_suffix(format_code: str) -> tuple[str, str]:
|
||||||
|
"""Returns (MIME, SUFFIX) from format_code == "xls", "xml", ...
|
||||||
|
SUFFIX includes the dot: ".xlsx", ".xml", ...
|
||||||
|
"xls" and "xlsx" format codes give XLSX
|
||||||
|
"""
|
||||||
|
d = {
|
||||||
|
"csv": (CSV_MIMETYPE, CSV_SUFFIX),
|
||||||
|
"xls": (XLSX_MIMETYPE, XLSX_SUFFIX),
|
||||||
|
"xlsx": (XLSX_MIMETYPE, XLSX_SUFFIX),
|
||||||
|
"pdf": (PDF_MIMETYPE, PDF_SUFFIX),
|
||||||
|
"xml": (XML_MIMETYPE, XML_SUFFIX),
|
||||||
|
"json": (JSON_MIMETYPE, JSON_SUFFIX),
|
||||||
|
}
|
||||||
|
return d[format_code]
|
||||||
|
|
||||||
|
|
||||||
# Admissions des étudiants
|
# Admissions des étudiants
|
||||||
# Différents types de voies d'admission:
|
# Différents types de voies d'admission:
|
||||||
|
@ -388,6 +408,18 @@ def unescape_html(s):
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def build_url_query(url: str, **params) -> str:
|
||||||
|
"""Add parameters to existing url, as a query string"""
|
||||||
|
url_parse = urlparse(url)
|
||||||
|
query = url_parse.query
|
||||||
|
url_dict = dict(parse_qsl(query))
|
||||||
|
url_dict.update(params)
|
||||||
|
url_new_query = urlencode(url_dict)
|
||||||
|
url_parse = url_parse._replace(query=url_new_query)
|
||||||
|
new_url = urlunparse(url_parse)
|
||||||
|
return new_url
|
||||||
|
|
||||||
|
|
||||||
# test if obj is iterable (but not a string)
|
# test if obj is iterable (but not a string)
|
||||||
isiterable = lambda obj: getattr(obj, "__iter__", False)
|
isiterable = lambda obj: getattr(obj, "__iter__", False)
|
||||||
|
|
||||||
|
@ -457,14 +489,17 @@ def sanitize_string(s):
|
||||||
return suppress_accents(s.translate(trans)).replace(" ", "_").replace("\t", "_")
|
return suppress_accents(s.translate(trans)).replace(" ", "_").replace("\t", "_")
|
||||||
|
|
||||||
|
|
||||||
_BAD_FILENAME_CHARS = str.maketrans("", "", ":/\\")
|
_BAD_FILENAME_CHARS = str.maketrans("", "", ":/\\&[]*?'")
|
||||||
|
|
||||||
|
|
||||||
def make_filename(name):
|
def make_filename(name):
|
||||||
"""Try to convert name to a reasonable filename
|
"""Try to convert name to a reasonable filename
|
||||||
without spaces, (back)slashes, : and without accents
|
without spaces, (back)slashes, : and without accents
|
||||||
"""
|
"""
|
||||||
return suppress_accents(name.translate(_BAD_FILENAME_CHARS)).replace(" ", "_")
|
return (
|
||||||
|
suppress_accents(name.translate(_BAD_FILENAME_CHARS)).replace(" ", "_")
|
||||||
|
or "scodoc"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
VALID_CARS = (
|
VALID_CARS = (
|
||||||
|
@ -490,7 +525,15 @@ def is_valid_filename(filename):
|
||||||
return VALID_EXP.match(filename)
|
return VALID_EXP.match(filename)
|
||||||
|
|
||||||
|
|
||||||
def sendCSVFile(REQUEST, data, filename):
|
def bul_filename(sem, etud, format):
|
||||||
|
"""Build a filename for this bulletin"""
|
||||||
|
dt = time.strftime("%Y-%m-%d")
|
||||||
|
filename = f"bul-{sem['titre_num']}-{dt}-{etud['nom']}.{format}"
|
||||||
|
filename = make_filename(filename)
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
def sendCSVFile(REQUEST, data, filename): # DEPRECATED ne plus utiliser
|
||||||
"""publication fichier.
|
"""publication fichier.
|
||||||
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
||||||
"""
|
"""
|
||||||
|
@ -504,16 +547,9 @@ def sendCSVFile(REQUEST, data, filename):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def sendPDFFile(REQUEST, data, filename):
|
def sendPDFFile(data, filename):
|
||||||
filename = (
|
filename = make_filename(filename)
|
||||||
unescape_html(suppress_accents(filename)).replace("&", "").replace(" ", "_")
|
return send_file(data, filename=filename, mime=PDF_MIMETYPE, attached=True)
|
||||||
)
|
|
||||||
if REQUEST:
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", PDF_MIMETYPE)
|
|
||||||
REQUEST.RESPONSE.setHeader(
|
|
||||||
"content-disposition", 'attachment; filename="%s"' % filename
|
|
||||||
)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class ScoDocJSONEncoder(json.JSONEncoder):
|
class ScoDocJSONEncoder(json.JSONEncoder):
|
||||||
|
@ -526,38 +562,54 @@ class ScoDocJSONEncoder(json.JSONEncoder):
|
||||||
return json.JSONEncoder.default(self, o)
|
return json.JSONEncoder.default(self, o)
|
||||||
|
|
||||||
|
|
||||||
def sendJSON(REQUEST, data):
|
def sendJSON(data, attached=False):
|
||||||
js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
|
js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
|
||||||
if REQUEST:
|
return send_file(js, filename="sco_data.json", mime=JSON_MIMETYPE, attached=attached)
|
||||||
REQUEST.RESPONSE.setHeader("content-type", JSON_MIMETYPE)
|
|
||||||
return js
|
|
||||||
|
|
||||||
|
|
||||||
def sendXML(REQUEST, data, tagname=None, force_outer_xml_tag=True):
|
def sendXML(data, tagname=None, force_outer_xml_tag=True, attached=False):
|
||||||
if type(data) != list:
|
if type(data) != list:
|
||||||
data = [data] # always list-of-dicts
|
data = [data] # always list-of-dicts
|
||||||
if force_outer_xml_tag:
|
if force_outer_xml_tag:
|
||||||
data = [{tagname: data}]
|
data = [{tagname: data}]
|
||||||
tagname += "_list"
|
tagname += "_list"
|
||||||
doc = sco_xml.simple_dictlist2xml(data, tagname=tagname)
|
doc = sco_xml.simple_dictlist2xml(data, tagname=tagname)
|
||||||
if REQUEST:
|
return send_file(doc, filename="sco_data.xml", mime=XML_MIMETYPE, attached=attached)
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
|
||||||
return doc
|
|
||||||
|
|
||||||
|
|
||||||
def sendResult(REQUEST, data, name=None, format=None, force_outer_xml_tag=True):
|
def sendResult(data, name=None, format=None, force_outer_xml_tag=True, attached=False):
|
||||||
if (format is None) or (format == "html"):
|
if (format is None) or (format == "html"):
|
||||||
return data
|
return data
|
||||||
elif format == "xml": # name is outer tagname
|
elif format == "xml": # name is outer tagname
|
||||||
return sendXML(
|
return sendXML(data, tagname=name, force_outer_xml_tag=force_outer_xml_tag, attached=attached)
|
||||||
REQUEST, data, tagname=name, force_outer_xml_tag=force_outer_xml_tag
|
|
||||||
)
|
|
||||||
elif format == "json":
|
elif format == "json":
|
||||||
return sendJSON(REQUEST, data)
|
return sendJSON(data, attached=attached)
|
||||||
else:
|
else:
|
||||||
raise ValueError("invalid format: %s" % format)
|
raise ValueError("invalid format: %s" % format)
|
||||||
|
|
||||||
|
|
||||||
|
def send_file(data, filename="", suffix="", mime=None, attached=None):
|
||||||
|
"""Build Flask Response for file download of given type
|
||||||
|
By default (attached is None), json and xml are inlined and otrher types are atteched.
|
||||||
|
"""
|
||||||
|
if attached is None:
|
||||||
|
if mime == XML_MIMETYPE or mime == JSON_MIMETYPE:
|
||||||
|
attached = False
|
||||||
|
else:
|
||||||
|
attached = True
|
||||||
|
# if attached and not filename:
|
||||||
|
# raise ValueError("send_file: missing attachement filename")
|
||||||
|
if filename:
|
||||||
|
if suffix:
|
||||||
|
filename += suffix
|
||||||
|
filename = make_filename(filename)
|
||||||
|
response = make_response(data)
|
||||||
|
response.headers["Content-Type"] = mime
|
||||||
|
if attached and filename:
|
||||||
|
response.headers["Content-Disposition"] = 'attachment; filename="%s"' % filename
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get_scodoc_version():
|
def get_scodoc_version():
|
||||||
"return a string identifying ScoDoc version"
|
"return a string identifying ScoDoc version"
|
||||||
return sco_version.SCOVERSION
|
return sco_version.SCOVERSION
|
||||||
|
@ -759,42 +811,13 @@ def AnneeScolaire(sco_year=None):
|
||||||
return year
|
return year
|
||||||
|
|
||||||
|
|
||||||
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", "?")
|
|
||||||
code_ine = REQUEST.form.get("code_ine", "?")
|
|
||||||
log(
|
|
||||||
"unknown student: etudid=%s code_nip=%s code_ine=%s"
|
|
||||||
% (etudid, code_nip, code_ine)
|
|
||||||
)
|
|
||||||
return _sco_error_response("unknown student", format=format, REQUEST=REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
# XXX #sco8 à tester ou ré-écrire
|
|
||||||
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":
|
|
||||||
raise sco_exceptions.ScoValueError(msg)
|
|
||||||
elif format == "xml":
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
|
||||||
doc = ElementTree.Element("error", msg=msg)
|
|
||||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(SCO_ENCODING)
|
|
||||||
elif format == "json":
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", JSON_MIMETYPE)
|
|
||||||
return "undefined" # XXX voir quoi faire en cas d'erreur json
|
|
||||||
else:
|
|
||||||
raise ValueError("ScoErrorResponse: invalid format")
|
|
||||||
|
|
||||||
|
|
||||||
def return_text_if_published(val, REQUEST):
|
def return_text_if_published(val, REQUEST):
|
||||||
"""Pour les méthodes publiées qui ramènent soit du texte (HTML) soit du JSON
|
"""Pour les méthodes publiées qui ramènent soit du texte (HTML) soit du JSON
|
||||||
sauf quand elles sont appellées depuis python.
|
sauf quand elles sont appellées depuis python.
|
||||||
La présence de l'argument REQUEST indique la publication.
|
La présence de l'argument REQUEST indique la publication.
|
||||||
"""
|
"""
|
||||||
if REQUEST and not isinstance(val, str):
|
if REQUEST and not isinstance(val, str):
|
||||||
return sendJSON(REQUEST, val)
|
return sendJSON(val)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
@ -823,9 +846,10 @@ def confirm_dialog(
|
||||||
action = f'action="{dest_url}"'
|
action = f'action="{dest_url}"'
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
f"""<form {action} method="post">""",
|
f"""<form {action} method="POST">
|
||||||
message,
|
{message}
|
||||||
"""<input type="submit" value="%s"/>""" % OK,
|
<input type="submit" value="{OK}"/>
|
||||||
|
""",
|
||||||
]
|
]
|
||||||
if cancel_url:
|
if cancel_url:
|
||||||
H.append(
|
H.append(
|
||||||
|
|
|
@ -154,7 +154,7 @@ div.scovalueerror {
|
||||||
p.footer {
|
p.footer {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: rgb(60,60,60);
|
color: rgb(60,60,60);
|
||||||
margin-top: 10px;
|
margin-top: 15px;
|
||||||
border-top: 1px solid rgb(60,60,60);
|
border-top: 1px solid rgb(60,60,60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,13 +1092,13 @@ h2.formsemestre, .gtrcontent h2 {
|
||||||
#formnotes td.tf-fieldlabel {
|
#formnotes td.tf-fieldlabel {
|
||||||
border-bottom: 1px dotted #fdcaca;
|
border-bottom: 1px dotted #fdcaca;
|
||||||
}
|
}
|
||||||
|
.wtf-field li {
|
||||||
/* Formulaires ScoDoc 9 */
|
display: inline;
|
||||||
form.sco-form {
|
}.wtf-field ul {
|
||||||
margin-top: 1em;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
div.sco-submit {
|
.wtf-field .errors {
|
||||||
margin-top: 2em;
|
color: red ; font-weight: bold;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
.formsemestre_menubar {
|
.formsemestre_menubar {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
ou écrire la liste "notes" <a href="mailto:notes@listes.univ-paris13.fr">notes@listes.univ-paris13.fr</a> en
|
ou écrire la liste "notes" <a href="mailto:notes@listes.univ-paris13.fr">notes@listes.univ-paris13.fr</a> en
|
||||||
indiquant la version du logiciel
|
indiquant la version du logiciel
|
||||||
<br />
|
<br />
|
||||||
(plus d'informations sur les listes de diffusion<a href="https://scodoc.org/ListesDeDiffusion/">voir
|
(plus d'informations sur les listes de diffusion <a href="https://scodoc.org/ListesDeDiffusion/">voir
|
||||||
cette page</a>).
|
cette page</a>).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
|
|
||||||
<h2>Erreur !</h2>
|
<h2>Erreur !</h2>
|
||||||
|
|
||||||
<p>{{ exc }}</p>
|
{{ exc | safe }}
|
||||||
|
|
||||||
<p>
|
<p class="footer">
|
||||||
{% if g.scodoc_dept %}
|
{% if g.scodoc_dept %}
|
||||||
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
|
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">retour page d'accueil
|
||||||
|
departement {{ g.scodoc_dept }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ exc.dest_url or url_for('scodoc.index') }}">continuer</a>
|
<a href="{{ exc.dest_url or url_for('scodoc.index') }}">retour page d'accueil</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
78
app/templates/scodoc/forms/placement.html
Normal file
78
app/templates/scodoc/forms/placement.html
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% macro render_field(field) %}
|
||||||
|
<tr>
|
||||||
|
<td class="wtf-field">{{ field.label }}</td>
|
||||||
|
<td class="wtf-field">{{ field()|safe }}
|
||||||
|
{% if field.errors %}
|
||||||
|
<ul class=errors>
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
<div class="saisienote_etape1 form_placement">
|
||||||
|
<form method=post>
|
||||||
|
{{ form.evaluation_id }}
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<table class="tf">
|
||||||
|
<tbody>
|
||||||
|
{{ render_field(form.surveillants) }}
|
||||||
|
{{ render_field(form.batiment) }}
|
||||||
|
{{ render_field(form.salle) }}
|
||||||
|
{{ render_field(form.nb_rangs) }}
|
||||||
|
{{ render_field(form.etiquetage) }}
|
||||||
|
{% if form.has_groups %}
|
||||||
|
{# {{ render_field(form.groups) }}#}
|
||||||
|
{% for partition in form.groups_tree %}
|
||||||
|
<tr>
|
||||||
|
{% if partition == 'Tous' %}
|
||||||
|
<td rowspan="{{ form.nb_partitions }}">Groupes</td>
|
||||||
|
{% endif %}
|
||||||
|
<td>{{ partition }}</td>
|
||||||
|
<td>
|
||||||
|
{% for groupe in form.groups_tree[partition] %}
|
||||||
|
{{ groupe }}{{ form.get_checkbox(partition, groupe)() }}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{{ render_field(form.file_format) }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<input id="gr_submit" type=submit value="Ok">
|
||||||
|
<input id="gr_cancel" type=submit value="Annuler">
|
||||||
|
</script>
|
||||||
|
</form>
|
||||||
|
<h3>Explications</h3>
|
||||||
|
<ul>
|
||||||
|
<li>préciser les surveillants et la localisation (bâtiment et salle) et indiquer la largeur de la salle (nombre
|
||||||
|
de colonnes);</li>
|
||||||
|
<li>deux types de placements sont possibles :
|
||||||
|
<ul>
|
||||||
|
<li>continue suppose que les tables ont toutes un numéro unique;</li>
|
||||||
|
<li>coordonnées localise chaque table via un numéro de colonne et un numéro de ligne (ou rangée).</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Il est possible de choisir un ou plusieurs groupes (shift/ctrl click) ou de choisir 'tous'.</li>
|
||||||
|
<li>Choisir le format du fichier résultat :
|
||||||
|
<ul>
|
||||||
|
<li>le format pdf consiste en un tableau précisant pour chaque étudiant la localisation de sa table;
|
||||||
|
</li>
|
||||||
|
<li>le format xls produit un classeur avec deux onglets:
|
||||||
|
<ul>
|
||||||
|
<li>le premier onglet donne une vue de la salle avec la localisation des étudiants et
|
||||||
|
peut servir de feuille d'émargement;</li>
|
||||||
|
<li>le second onglet est un tableau similaire à celui du fichier pdf;</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
12
app/templates/sidebar_dept.html
Normal file
12
app/templates/sidebar_dept.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<h2 class="insidebar">Dépt. {{ prefs["DeptName"] }}</h2>
|
||||||
|
<a href="{{ url_for('scodoc.index') }}" class="sidebar">Accueil</a> <br/>
|
||||||
|
{% if prefs["DeptIntranetURL"] %}
|
||||||
|
<a href="{{ prefs["DeptIntranetURL"] }}" class="sidebar">
|
||||||
|
{{ prefs["DeptIntranetTitle"] }}</a>
|
||||||
|
{% endif %}
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
{#
|
||||||
|
# Entreprises pas encore supporté en ScoDoc8
|
||||||
|
# <br/><a href="%(ScoURL)s/Entreprises" class="sidebar">Entreprises</a> <br/>
|
||||||
|
#}
|
|
@ -47,20 +47,18 @@ L'API de plus bas niveau est en gros:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import calendar
|
import calendar
|
||||||
import cgi
|
|
||||||
import datetime
|
import datetime
|
||||||
import dateutil
|
import dateutil
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
import re
|
import re
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
|
||||||
import string
|
|
||||||
import time
|
import time
|
||||||
|
import urllib
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g, request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask import current_app
|
from flask_login import current_user
|
||||||
|
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
scodoc,
|
scodoc,
|
||||||
|
@ -123,11 +121,11 @@ def sco_publish(route, function, permission, methods=["GET"]):
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def index_html(REQUEST=None):
|
def index_html():
|
||||||
"""Gestionnaire absences, page principale"""
|
"""Gestionnaire absences, page principale"""
|
||||||
# crude portage from 1999 DTML
|
# crude portage from 1999 DTML
|
||||||
sems = sco_formsemestre.do_formsemestre_list()
|
sems = sco_formsemestre.do_formsemestre_list()
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
|
@ -164,7 +162,7 @@ def index_html(REQUEST=None):
|
||||||
Saisie par semaine </span> - Choix du groupe:
|
Saisie par semaine </span> - Choix du groupe:
|
||||||
<input name="datelundi" type="hidden" value="x"/>
|
<input name="datelundi" type="hidden" value="x"/>
|
||||||
"""
|
"""
|
||||||
% REQUEST.URL0,
|
% request.base_url,
|
||||||
sco_abs_views.formChoixSemestreGroupe(),
|
sco_abs_views.formChoixSemestreGroupe(),
|
||||||
"</p>",
|
"</p>",
|
||||||
cal_select_week(),
|
cal_select_week(),
|
||||||
|
@ -270,7 +268,6 @@ def doSignaleAbsenceGrSemestre(
|
||||||
dates="",
|
dates="",
|
||||||
etudids="",
|
etudids="",
|
||||||
destination=None,
|
destination=None,
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Enregistre absences aux dates indiquees (abslist et dates).
|
"""Enregistre absences aux dates indiquees (abslist et dates).
|
||||||
dates est une liste de dates ISO (séparées par des ',').
|
dates est une liste de dates ISO (séparées par des ',').
|
||||||
|
@ -295,10 +292,10 @@ def doSignaleAbsenceGrSemestre(
|
||||||
|
|
||||||
# 2- Ajoute les absences
|
# 2- Ajoute les absences
|
||||||
if abslist:
|
if abslist:
|
||||||
sco_abs._add_abslist(abslist, REQUEST, moduleimpl_id)
|
sco_abs.add_abslist(abslist, moduleimpl_id)
|
||||||
return "Absences ajoutées"
|
return "Absences ajoutées"
|
||||||
|
|
||||||
return ""
|
return ("", 204)
|
||||||
|
|
||||||
|
|
||||||
# ------------ HTML Interfaces
|
# ------------ HTML Interfaces
|
||||||
|
@ -307,14 +304,14 @@ def doSignaleAbsenceGrSemestre(
|
||||||
@permission_required(Permission.ScoAbsChange)
|
@permission_required(Permission.ScoAbsChange)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def SignaleAbsenceGrHebdo(
|
def SignaleAbsenceGrHebdo(
|
||||||
datelundi, group_ids=[], destination="", moduleimpl_id=None, REQUEST=None
|
datelundi, group_ids=[], destination="", moduleimpl_id=None, formsemestre_id=None
|
||||||
):
|
):
|
||||||
"Saisie hebdomadaire des absences"
|
"Saisie hebdomadaire des absences"
|
||||||
if not moduleimpl_id:
|
if not moduleimpl_id:
|
||||||
moduleimpl_id = None
|
moduleimpl_id = None
|
||||||
|
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
group_ids, moduleimpl_id=moduleimpl_id
|
group_ids, moduleimpl_id=moduleimpl_id, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
if not groups_infos.members:
|
if not groups_infos.members:
|
||||||
return (
|
return (
|
||||||
|
@ -326,7 +323,7 @@ def SignaleAbsenceGrHebdo(
|
||||||
base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % (
|
base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % (
|
||||||
datelundi,
|
datelundi,
|
||||||
groups_infos.groups_query_args,
|
groups_infos.groups_query_args,
|
||||||
six.moves.urllib.parse.quote(destination),
|
urllib.parse.quote(destination),
|
||||||
)
|
)
|
||||||
|
|
||||||
formsemestre_id = groups_infos.formsemestre_id
|
formsemestre_id = groups_infos.formsemestre_id
|
||||||
|
@ -473,7 +470,6 @@ def SignaleAbsenceGrSemestre(
|
||||||
group_ids=[], # list of groups to display
|
group_ids=[], # list of groups to display
|
||||||
nbweeks=4, # ne montre que les nbweeks dernieres semaines
|
nbweeks=4, # ne montre que les nbweeks dernieres semaines
|
||||||
moduleimpl_id=None,
|
moduleimpl_id=None,
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Saisie des absences sur une journée sur un semestre (ou intervalle de dates) entier"""
|
"""Saisie des absences sur une journée sur un semestre (ou intervalle de dates) entier"""
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
|
||||||
|
@ -510,7 +506,7 @@ def SignaleAbsenceGrSemestre(
|
||||||
datedebut,
|
datedebut,
|
||||||
datefin,
|
datefin,
|
||||||
groups_infos.groups_query_args,
|
groups_infos.groups_query_args,
|
||||||
six.moves.urllib.parse.quote(destination),
|
urllib.parse.quote(destination),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
|
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
|
||||||
|
@ -810,7 +806,7 @@ def _gen_form_saisie_groupe(
|
||||||
H.append('<input type="hidden" name="dates" value="%s"/>' % ",".join(dates))
|
H.append('<input type="hidden" name="dates" value="%s"/>' % ",".join(dates))
|
||||||
H.append(
|
H.append(
|
||||||
'<input type="hidden" name="destination" value="%s"/>'
|
'<input type="hidden" name="destination" value="%s"/>'
|
||||||
% six.moves.urllib.parse.quote(destination)
|
% urllib.parse.quote(destination)
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
# version pour formulaire avec AJAX (Yann LB)
|
# version pour formulaire avec AJAX (Yann LB)
|
||||||
|
@ -843,7 +839,6 @@ def EtatAbsencesGr(
|
||||||
fin="",
|
fin="",
|
||||||
with_boursier=True, # colonne boursier
|
with_boursier=True, # colonne boursier
|
||||||
format="html",
|
format="html",
|
||||||
REQUEST=None,
|
|
||||||
):
|
):
|
||||||
"""Liste les absences de groupes"""
|
"""Liste les absences de groupes"""
|
||||||
datedebut = ndb.DateDMYtoISO(debut)
|
datedebut = ndb.DateDMYtoISO(debut)
|
||||||
|
@ -938,7 +933,7 @@ def EtatAbsencesGr(
|
||||||
javascripts=["js/etud_info.js"],
|
javascripts=["js/etud_info.js"],
|
||||||
),
|
),
|
||||||
html_title=html_sco_header.html_sem_header(
|
html_title=html_sco_header.html_sem_header(
|
||||||
REQUEST, "%s" % title, sem, with_page_header=False
|
"%s" % title, sem, with_page_header=False
|
||||||
)
|
)
|
||||||
+ "<p>Période du %s au %s (nombre de <b>demi-journées</b>)<br/>" % (debut, fin),
|
+ "<p>Période du %s au %s (nombre de <b>demi-journées</b>)<br/>" % (debut, fin),
|
||||||
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
|
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
|
||||||
|
@ -964,9 +959,9 @@ ou entrez une date pour visualiser les absents un jour donné :
|
||||||
<input type="submit" name="" value="visualiser les absences">
|
<input type="submit" name="" value="visualiser les absences">
|
||||||
</form></div>
|
</form></div>
|
||||||
"""
|
"""
|
||||||
% (REQUEST.URL0, formsemestre_id, groups_infos.get_form_elem()),
|
% (request.base_url, formsemestre_id, groups_infos.get_form_elem()),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/EtatAbsencesDate")
|
@bp.route("/EtatAbsencesDate")
|
||||||
|
@ -1062,7 +1057,6 @@ def AddBilletAbsence(
|
||||||
code_nip=None,
|
code_nip=None,
|
||||||
code_ine=None,
|
code_ine=None,
|
||||||
justified=True,
|
justified=True,
|
||||||
REQUEST=None,
|
|
||||||
xml_reply=True,
|
xml_reply=True,
|
||||||
):
|
):
|
||||||
"""Memorise un "billet"
|
"""Memorise un "billet"
|
||||||
|
@ -1072,7 +1066,9 @@ def AddBilletAbsence(
|
||||||
# check etudid
|
# check etudid
|
||||||
etuds = sco_etud.get_etud_info(etudid=etudid, code_nip=code_nip, filled=True)
|
etuds = sco_etud.get_etud_info(etudid=etudid, code_nip=code_nip, filled=True)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
return scu.log_unknown_etud(REQUEST=REQUEST)
|
sco_etud.log_unknown_etud()
|
||||||
|
raise ScoValueError("étudiant inconnu")
|
||||||
|
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
# check dates
|
# check dates
|
||||||
begin_date = dateutil.parser.isoparse(begin) # may raises ValueError
|
begin_date = dateutil.parser.isoparse(begin) # may raises ValueError
|
||||||
|
@ -1096,13 +1092,10 @@ def AddBilletAbsence(
|
||||||
)
|
)
|
||||||
if xml_reply:
|
if xml_reply:
|
||||||
# Renvoie le nouveau billet en XML
|
# Renvoie le nouveau billet en XML
|
||||||
if REQUEST:
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
|
||||||
|
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
||||||
tab = _tableBillets(billets, etud=etud)
|
tab = _tableBillets(billets, etud=etud)
|
||||||
log("AddBilletAbsence: new billet_id=%s (%gs)" % (billet_id, time.time() - t0))
|
log("AddBilletAbsence: new billet_id=%s (%gs)" % (billet_id, time.time() - t0))
|
||||||
return tab.make_page(REQUEST=REQUEST, format="xml")
|
return tab.make_page(format="xml")
|
||||||
else:
|
else:
|
||||||
return billet_id
|
return billet_id
|
||||||
|
|
||||||
|
@ -1122,7 +1115,7 @@ def AddBilletAbsenceForm(etudid, REQUEST=None):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("etudid", {"input_type": "hidden"}),
|
("etudid", {"input_type": "hidden"}),
|
||||||
|
@ -1223,17 +1216,18 @@ def _tableBillets(billets, etud=None, title=""):
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def listeBilletsEtud(etudid=False, REQUEST=None, format="html"):
|
def listeBilletsEtud(etudid=False, format="html"):
|
||||||
"""Liste billets pour un etudiant"""
|
"""Liste billets pour un etudiant"""
|
||||||
etuds = sco_etud.get_etud_info(filled=True, etudid=etudid)
|
etuds = sco_etud.get_etud_info(filled=True, etudid=etudid)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
return scu.log_unknown_etud(format=format, REQUEST=REQUEST)
|
sco_etud.log_unknown_etud()
|
||||||
|
raise ScoValueError("étudiant inconnu")
|
||||||
|
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"etudid": etud["etudid"]})
|
billets = sco_abs.billet_absence_list(cnx, {"etudid": etud["etudid"]})
|
||||||
tab = _tableBillets(billets, etud=etud)
|
tab = _tableBillets(billets, etud=etud)
|
||||||
return tab.make_page(REQUEST=REQUEST, format=format)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route(
|
@bp.route(
|
||||||
|
@ -1242,12 +1236,12 @@ def listeBilletsEtud(etudid=False, REQUEST=None, format="html"):
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required_compat_scodoc7(Permission.ScoView)
|
@permission_required_compat_scodoc7(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def XMLgetBilletsEtud(etudid=False, REQUEST=None):
|
def XMLgetBilletsEtud(etudid=False):
|
||||||
"""Liste billets pour un etudiant"""
|
"""Liste billets pour un etudiant"""
|
||||||
if not sco_preferences.get_preference("handle_billets_abs"):
|
if not sco_preferences.get_preference("handle_billets_abs"):
|
||||||
return ""
|
return ""
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
r = listeBilletsEtud(etudid, REQUEST=REQUEST, format="xml")
|
r = listeBilletsEtud(etudid, format="xml")
|
||||||
log("XMLgetBilletsEtud (%gs)" % (time.time() - t0))
|
log("XMLgetBilletsEtud (%gs)" % (time.time() - t0))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -1259,7 +1253,7 @@ def XMLgetBilletsEtud(etudid=False, REQUEST=None):
|
||||||
def listeBillets(REQUEST=None):
|
def listeBillets(REQUEST=None):
|
||||||
"""Page liste des billets non traités et formulaire recherche d'un billet"""
|
"""Page liste des billets non traités et formulaire recherche d'un billet"""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"etat": 0})
|
billets = sco_abs.billet_absence_list(cnx, {"etat": False})
|
||||||
tab = _tableBillets(billets)
|
tab = _tableBillets(billets)
|
||||||
T = tab.html()
|
T = tab.html()
|
||||||
H = [
|
H = [
|
||||||
|
@ -1268,7 +1262,7 @@ def listeBillets(REQUEST=None):
|
||||||
]
|
]
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("billet_id", {"input_type": "text", "title": "Numéro du billet"}),),
|
(("billet_id", {"input_type": "text", "title": "Numéro du billet"}),),
|
||||||
submitbutton=False,
|
submitbutton=False,
|
||||||
|
@ -1281,11 +1275,11 @@ def listeBillets(REQUEST=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/deleteBilletAbsence")
|
@bp.route("/deleteBilletAbsence", methods=["POST", "GET"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoAbsChange)
|
@permission_required(Permission.ScoAbsChange)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def deleteBilletAbsence(billet_id, REQUEST=None, dialog_confirmed=False):
|
def deleteBilletAbsence(billet_id, dialog_confirmed=False):
|
||||||
"""Supprime un billet."""
|
"""Supprime un billet."""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
billets = sco_abs.billet_absence_list(cnx, {"billet_id": billet_id})
|
||||||
|
@ -1307,7 +1301,7 @@ def deleteBilletAbsence(billet_id, REQUEST=None, dialog_confirmed=False):
|
||||||
return flask.redirect("listeBillets?head_message=Billet%20supprimé")
|
return flask.redirect("listeBillets?head_message=Billet%20supprimé")
|
||||||
|
|
||||||
|
|
||||||
def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
def _ProcessBilletAbsence(billet, estjust, description):
|
||||||
"""Traite un billet: ajoute absence(s) et éventuellement justificatifs,
|
"""Traite un billet: ajoute absence(s) et éventuellement justificatifs,
|
||||||
et change l'état du billet à 1.
|
et change l'état du billet à 1.
|
||||||
NB: actuellement, les heures ne sont utilisées que pour déterminer si matin et/ou après-midi.
|
NB: actuellement, les heures ne sont utilisées que pour déterminer si matin et/ou après-midi.
|
||||||
|
@ -1329,7 +1323,6 @@ def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
||||||
dates[0],
|
dates[0],
|
||||||
0,
|
0,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description=description,
|
description=description,
|
||||||
)
|
)
|
||||||
n += 1
|
n += 1
|
||||||
|
@ -1341,7 +1334,6 @@ def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
||||||
dates[-1],
|
dates[-1],
|
||||||
1,
|
1,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description=description,
|
description=description,
|
||||||
)
|
)
|
||||||
n += 1
|
n += 1
|
||||||
|
@ -1353,7 +1345,6 @@ def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
||||||
jour,
|
jour,
|
||||||
0,
|
0,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description=description,
|
description=description,
|
||||||
)
|
)
|
||||||
sco_abs.add_absence(
|
sco_abs.add_absence(
|
||||||
|
@ -1361,7 +1352,6 @@ def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
||||||
jour,
|
jour,
|
||||||
1,
|
1,
|
||||||
estjust,
|
estjust,
|
||||||
REQUEST,
|
|
||||||
description=description,
|
description=description,
|
||||||
)
|
)
|
||||||
n += 2
|
n += 2
|
||||||
|
@ -1372,7 +1362,7 @@ def _ProcessBilletAbsence(billet, estjust, description, REQUEST):
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/ProcessBilletAbsenceForm")
|
@bp.route("/ProcessBilletAbsenceForm", methods=["POST", "GET"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoAbsChange)
|
@permission_required(Permission.ScoAbsChange)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
|
@ -1401,7 +1391,7 @@ def ProcessBilletAbsenceForm(billet_id, REQUEST=None):
|
||||||
]
|
]
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("billet_id", {"input_type": "hidden"}),
|
("billet_id", {"input_type": "hidden"}),
|
||||||
|
@ -1439,9 +1429,7 @@ def ProcessBilletAbsenceForm(billet_id, REQUEST=None):
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return flask.redirect(scu.ScoURL())
|
return flask.redirect(scu.ScoURL())
|
||||||
else:
|
else:
|
||||||
n = _ProcessBilletAbsence(
|
n = _ProcessBilletAbsence(billet, tf[2]["estjust"], tf[2]["description"])
|
||||||
billet, tf[2]["estjust"], tf[2]["description"], REQUEST
|
|
||||||
)
|
|
||||||
if tf[2]["estjust"]:
|
if tf[2]["estjust"]:
|
||||||
j = "justifiées"
|
j = "justifiées"
|
||||||
else:
|
else:
|
||||||
|
@ -1477,7 +1465,7 @@ def ProcessBilletAbsenceForm(billet_id, REQUEST=None):
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required_compat_scodoc7(Permission.ScoView)
|
@permission_required_compat_scodoc7(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def XMLgetAbsEtud(beg_date="", end_date="", REQUEST=None):
|
def XMLgetAbsEtud(beg_date="", end_date=""):
|
||||||
"""returns list of absences in date interval"""
|
"""returns list of absences in date interval"""
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
etuds = sco_etud.get_etud_info(filled=False)
|
etuds = sco_etud.get_etud_info(filled=False)
|
||||||
|
@ -1493,7 +1481,6 @@ def XMLgetAbsEtud(beg_date="", end_date="", REQUEST=None):
|
||||||
|
|
||||||
abs_list = sco_abs.list_abs_date(etud["etudid"], beg_date, end_date)
|
abs_list = sco_abs.list_abs_date(etud["etudid"], beg_date, end_date)
|
||||||
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
|
||||||
doc = ElementTree.Element(
|
doc = ElementTree.Element(
|
||||||
"absences", etudid=str(etud["etudid"]), beg_date=beg_date, end_date=end_date
|
"absences", etudid=str(etud["etudid"]), beg_date=beg_date, end_date=end_date
|
||||||
)
|
)
|
||||||
|
@ -1509,4 +1496,5 @@ def XMLgetAbsEtud(beg_date="", end_date="", REQUEST=None):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
log("XMLgetAbsEtud (%gs)" % (time.time() - t0))
|
log("XMLgetAbsEtud (%gs)" % (time.time() - t0))
|
||||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
data = sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
||||||
|
return scu.send_file(data, mime=scu.XML_MIMETYPE, attached=False)
|
||||||
|
|
|
@ -38,6 +38,9 @@ import re
|
||||||
import time
|
import time
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
from flask import request
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
# MIGRATION EN COURS => MODULE DESACTIVE !
|
# MIGRATION EN COURS => MODULE DESACTIVE !
|
||||||
|
|
||||||
# A REVOIR
|
# A REVOIR
|
||||||
|
@ -79,7 +82,7 @@ def sidebar(REQUEST):
|
||||||
<ul class="insidebar">"""
|
<ul class="insidebar">"""
|
||||||
% params,
|
% params,
|
||||||
]
|
]
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoEntrepriseChange):
|
if current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
H.append(
|
H.append(
|
||||||
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_create" class="sidebar">Nouvelle entreprise</a> </li>"""
|
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_create" class="sidebar">Nouvelle entreprise</a> </li>"""
|
||||||
% params
|
% params
|
||||||
|
@ -104,9 +107,7 @@ def sidebar(REQUEST):
|
||||||
<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_correspondant_list?entreprise_id=%(entreprise_id)s" class="sidebar">Corresp.</a></li>"""
|
<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_correspondant_list?entreprise_id=%(entreprise_id)s" class="sidebar">Corresp.</a></li>"""
|
||||||
% params
|
% params
|
||||||
) # """
|
) # """
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(
|
if current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
):
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_correspondant_create?entreprise_id=%(entreprise_id)s" class="sidebar">Nouveau Corresp.</a></li>"""
|
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_correspondant_create?entreprise_id=%(entreprise_id)s" class="sidebar">Nouveau Corresp.</a></li>"""
|
||||||
% params
|
% params
|
||||||
|
@ -115,9 +116,7 @@ def sidebar(REQUEST):
|
||||||
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_contact_list?entreprise_id=%(entreprise_id)s" class="sidebar">Contacts</a></li>"""
|
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_contact_list?entreprise_id=%(entreprise_id)s" class="sidebar">Contacts</a></li>"""
|
||||||
% params
|
% params
|
||||||
)
|
)
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(
|
if current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
):
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_contact_create?entreprise_id=%(entreprise_id)s" class="sidebar">Nouveau "contact"</a></li>"""
|
"""<li class="insidebar"><a href="%(ScoURL)s/Entreprises/entreprise_contact_create?entreprise_id=%(entreprise_id)s" class="sidebar">Nouveau "contact"</a></li>"""
|
||||||
% params
|
% params
|
||||||
|
@ -126,7 +125,7 @@ def sidebar(REQUEST):
|
||||||
|
|
||||||
#
|
#
|
||||||
H.append("""<br/><br/>%s""" % scu.icontag("entreprise_side_img"))
|
H.append("""<br/><br/>%s""" % scu.icontag("entreprise_side_img"))
|
||||||
if not REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoEntrepriseChange):
|
if not current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
H.append("""<br/><em>(Lecture seule)</em>""")
|
H.append("""<br/><em>(Lecture seule)</em>""")
|
||||||
H.append("""</div> </div> <!-- end of sidebar -->""")
|
H.append("""</div> </div> <!-- end of sidebar -->""")
|
||||||
return "".join(H)
|
return "".join(H)
|
||||||
|
@ -166,14 +165,14 @@ def index_html(REQUEST=None, etud_nom=None, limit=50, offset="", format="html"):
|
||||||
if offset:
|
if offset:
|
||||||
webparams["offset"] = max((offset or 0) - limit, 0)
|
webparams["offset"] = max((offset or 0) - limit, 0)
|
||||||
prev_lnk = '<a class="stdlink" href="%s">précédentes</a>' % (
|
prev_lnk = '<a class="stdlink" href="%s">précédentes</a>' % (
|
||||||
REQUEST.URL0 + "?" + six.moves.urllib.parse.urlencode(webparams)
|
request.base_url + "?" + six.moves.urllib.parse.urlencode(webparams)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
prev_lnk = ""
|
prev_lnk = ""
|
||||||
if len(entreprises) >= limit:
|
if len(entreprises) >= limit:
|
||||||
webparams["offset"] = (offset or 0) + limit
|
webparams["offset"] = (offset or 0) + limit
|
||||||
next_lnk = '<a class="stdlink" href="%s">suivantes</a>' % (
|
next_lnk = '<a class="stdlink" href="%s">suivantes</a>' % (
|
||||||
REQUEST.URL0 + "?" + six.moves.urllib.parse.urlencode(webparams)
|
request.base_url + "?" + six.moves.urllib.parse.urlencode(webparams)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
next_lnk = ""
|
next_lnk = ""
|
||||||
|
@ -220,11 +219,11 @@ def index_html(REQUEST=None, etud_nom=None, limit=50, offset="", format="html"):
|
||||||
html_class="entreprise_list table_leftalign",
|
html_class="entreprise_list table_leftalign",
|
||||||
html_with_td_classes=True,
|
html_with_td_classes=True,
|
||||||
html_next_section=table_navigation,
|
html_next_section=table_navigation,
|
||||||
base_url=REQUEST.URL0 + "?",
|
base_url=request.base_url + "?",
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
else:
|
else:
|
||||||
H = [
|
H = [
|
||||||
entreprise_header(REQUEST=REQUEST, page_title="Suivi entreprises"),
|
entreprise_header(REQUEST=REQUEST, page_title="Suivi entreprises"),
|
||||||
|
@ -293,15 +292,15 @@ def entreprise_contact_list(entreprise_id=None, format="html", REQUEST=None):
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
html_class="contact_list table_leftalign",
|
html_class="contact_list table_leftalign",
|
||||||
html_with_td_classes=True,
|
html_with_td_classes=True,
|
||||||
base_url=REQUEST.URL0 + "?",
|
base_url=request.base_url + "?",
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
|
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoEntrepriseChange):
|
if current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
if entreprise_id:
|
if entreprise_id:
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="entreprise_create"><a class="entreprise_create" href="entreprise_contact_create?entreprise_id=%(entreprise_id)s">nouveau "contact"</a></p>
|
"""<p class="entreprise_create"><a class="entreprise_create" href="entreprise_contact_create?entreprise_id=%(entreprise_id)s">nouveau "contact"</a></p>
|
||||||
|
@ -399,15 +398,15 @@ def entreprise_correspondant_list(
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
html_class="contact_list table_leftalign",
|
html_class="contact_list table_leftalign",
|
||||||
html_with_td_classes=True,
|
html_with_td_classes=True,
|
||||||
base_url=REQUEST.URL0 + "?",
|
base_url=request.base_url + "?",
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
H.append(tab.html())
|
H.append(tab.html())
|
||||||
|
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoEntrepriseChange):
|
if current_user.has_permission(Permission.ScoEntrepriseChange):
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="entreprise_create"><a class="entreprise_create" href="entreprise_correspondant_create?entreprise_id=%(entreprise_id)s">Ajouter un correspondant dans l'entreprise %(nom)s</a></p>
|
"""<p class="entreprise_create"><a class="entreprise_create" href="entreprise_correspondant_create?entreprise_id=%(entreprise_id)s">Ajouter un correspondant dans l'entreprise %(nom)s</a></p>
|
||||||
"""
|
"""
|
||||||
|
@ -444,7 +443,7 @@ def entreprise_contact_edit(entreprise_contact_id, REQUEST=None):
|
||||||
% E,
|
% E,
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -515,14 +514,12 @@ def entreprise_contact_edit(entreprise_contact_id, REQUEST=None):
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
initvalues=c,
|
initvalues=c,
|
||||||
submitlabel="Modifier les valeurs",
|
submitlabel="Modifier les valeurs",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
if REQUEST.AUTHENTICATED_USER.has_permission(
|
if current_user.has_permission(
|
||||||
Permission.ScoEntrepriseChange,
|
Permission.ScoEntrepriseChange,
|
||||||
):
|
):
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -560,7 +557,7 @@ def entreprise_correspondant_edit(entreprise_corresp_id, REQUEST=None):
|
||||||
"""<h2 class="entreprise_correspondant">Édition contact entreprise</h2>""",
|
"""<h2 class="entreprise_correspondant">Édition contact entreprise</h2>""",
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -641,9 +638,7 @@ def entreprise_correspondant_edit(entreprise_corresp_id, REQUEST=None):
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
initvalues=c,
|
initvalues=c,
|
||||||
submitlabel="Modifier les valeurs",
|
submitlabel="Modifier les valeurs",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -684,7 +679,7 @@ def entreprise_contact_create(entreprise_id, REQUEST=None):
|
||||||
% E,
|
% E,
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("entreprise_id", {"input_type": "hidden", "default": entreprise_id}),
|
("entreprise_id", {"input_type": "hidden", "default": entreprise_id}),
|
||||||
|
@ -750,9 +745,7 @@ def entreprise_contact_create(entreprise_id, REQUEST=None):
|
||||||
),
|
),
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
submitlabel="Ajouter ce contact",
|
submitlabel="Ajouter ce contact",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -783,13 +776,13 @@ def entreprise_contact_delete(entreprise_contact_id, REQUEST=None):
|
||||||
"""<h2>Suppression du contact</h2>""",
|
"""<h2>Suppression du contact</h2>""",
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("entreprise_contact_id", {"input_type": "hidden"}),),
|
(("entreprise_contact_id", {"input_type": "hidden"}),),
|
||||||
initvalues=c,
|
initvalues=c,
|
||||||
submitlabel="Confirmer la suppression",
|
submitlabel="Confirmer la suppression",
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(ScoEntrepriseChange),
|
readonly=not current_user.has_permission(ScoEntrepriseChange),
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -814,7 +807,7 @@ def entreprise_correspondant_create(entreprise_id, REQUEST=None):
|
||||||
% E,
|
% E,
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("entreprise_id", {"input_type": "hidden", "default": entreprise_id}),
|
("entreprise_id", {"input_type": "hidden", "default": entreprise_id}),
|
||||||
|
@ -892,9 +885,7 @@ def entreprise_correspondant_create(entreprise_id, REQUEST=None):
|
||||||
),
|
),
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
submitlabel="Ajouter ce correspondant",
|
submitlabel="Ajouter ce correspondant",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -920,15 +911,13 @@ def entreprise_correspondant_delete(entreprise_corresp_id, REQUEST=None):
|
||||||
"""<h2>Suppression du correspondant %(nom)s %(prenom)s</h2>""" % c,
|
"""<h2>Suppression du correspondant %(nom)s %(prenom)s</h2>""" % c,
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("entreprise_corresp_id", {"input_type": "hidden"}),),
|
(("entreprise_corresp_id", {"input_type": "hidden"}),),
|
||||||
initvalues=c,
|
initvalues=c,
|
||||||
submitlabel="Confirmer la suppression",
|
submitlabel="Confirmer la suppression",
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -976,15 +965,13 @@ def entreprise_delete(entreprise_id, REQUEST=None):
|
||||||
H.append("""<li>%(date)s %(description)s</li>""" % c)
|
H.append("""<li>%(date)s %(description)s</li>""" % c)
|
||||||
H.append("""</ul>""")
|
H.append("""</ul>""")
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("entreprise_id", {"input_type": "hidden"}),),
|
(("entreprise_id", {"input_type": "hidden"}),),
|
||||||
initvalues=E,
|
initvalues=E,
|
||||||
submitlabel="Confirmer la suppression",
|
submitlabel="Confirmer la suppression",
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
|
@ -1008,7 +995,7 @@ def entreprise_create(REQUEST=None):
|
||||||
"""<h2 class="entreprise_new">Création d'une entreprise</h2>""",
|
"""<h2 class="entreprise_new">Création d'une entreprise</h2>""",
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("nom", {"size": 25, "title": "Nom de l'entreprise"}),
|
("nom", {"size": 25, "title": "Nom de l'entreprise"}),
|
||||||
|
@ -1079,9 +1066,7 @@ def entreprise_create(REQUEST=None):
|
||||||
),
|
),
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
submitlabel="Ajouter cette entreprise",
|
submitlabel="Ajouter cette entreprise",
|
||||||
readonly=not REQUEST.AUTHENTICATED_USER.has_permission(
|
readonly=not current_user.has_permission(Permission.ScoEntrepriseChange),
|
||||||
Permission.ScoEntrepriseChange
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + entreprise_footer(REQUEST)
|
return "\n".join(H) + tf[1] + entreprise_footer(REQUEST)
|
||||||
|
@ -1097,7 +1082,7 @@ security.declareProtected(ScoEntrepriseView, "entreprise_edit")
|
||||||
|
|
||||||
def entreprise_edit(entreprise_id, REQUEST=None, start=1):
|
def entreprise_edit(entreprise_id, REQUEST=None, start=1):
|
||||||
"""Form. edit entreprise"""
|
"""Form. edit entreprise"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
readonly = not authuser.has_permission(Permission.ScoEntrepriseChange)
|
readonly = not authuser.has_permission(Permission.ScoEntrepriseChange)
|
||||||
F = sco_entreprises.do_entreprise_list(args={"entreprise_id": entreprise_id})[0]
|
F = sco_entreprises.do_entreprise_list(args={"entreprise_id": entreprise_id})[0]
|
||||||
H = [
|
H = [
|
||||||
|
@ -1105,7 +1090,7 @@ def entreprise_edit(entreprise_id, REQUEST=None, start=1):
|
||||||
"""<h2 class="entreprise">%(nom)s</h2>""" % F,
|
"""<h2 class="entreprise">%(nom)s</h2>""" % F,
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("entreprise_id", {"default": entreprise_id, "input_type": "hidden"}),
|
("entreprise_id", {"default": entreprise_id, "input_type": "hidden"}),
|
||||||
|
|
|
@ -38,8 +38,8 @@ from operator import itemgetter
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g
|
from flask import url_for
|
||||||
from flask import current_app
|
from flask import current_app, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
|
@ -146,23 +146,31 @@ def sco_publish(route, function, permission, methods=["GET"]):
|
||||||
|
|
||||||
|
|
||||||
# --------------------- Quelques essais élémentaires:
|
# --------------------- Quelques essais élémentaires:
|
||||||
@bp.route("/essai")
|
# @bp.route("/essai")
|
||||||
@scodoc
|
# @scodoc
|
||||||
@permission_required(Permission.ScoView)
|
# @permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
# @scodoc7func
|
||||||
def essai(REQUEST=None):
|
# def essai(REQUEST=None):
|
||||||
return essai_(REQUEST)
|
# return essai_(REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def essai_(REQUEST):
|
# def essai_(REQUEST):
|
||||||
return "<html><body><h2>essai !</h2><p>%s</p></body></html>" % (REQUEST,)
|
# return "<html><body><h2>essai !</h2><p>%s</p></body></html>" % (REQUEST,)
|
||||||
|
|
||||||
|
|
||||||
def essai2():
|
# def essai2():
|
||||||
return essai_("sans request")
|
# err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
|
||||||
|
# <p class="help">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.
|
||||||
|
# </p>
|
||||||
|
# <a href="url_for('notes.ue_list', scodoc-dept=g.scodoc_dept, formation_id='XXX')">reprendre</a>
|
||||||
|
# """
|
||||||
|
# raise ScoGenError(err_page)
|
||||||
|
# # raise ScoGenError("une erreur banale")
|
||||||
|
# return essai_("sans request")
|
||||||
|
|
||||||
|
|
||||||
sco_publish("/essai2", essai2, Permission.ScoImplement)
|
# sco_publish("/essai2", essai2, Permission.ScoImplement)
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -406,14 +414,14 @@ sco_publish(
|
||||||
def index_html(REQUEST=None):
|
def index_html(REQUEST=None):
|
||||||
"Page accueil formations"
|
"Page accueil formations"
|
||||||
|
|
||||||
editable = REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoChangeFormation)
|
editable = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Programmes formations"),
|
html_sco_header.sco_header(page_title="Programmes formations"),
|
||||||
"""<h2>Programmes pédagogiques</h2>
|
"""<h2>Programmes pédagogiques</h2>
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
T = sco_formations.formation_list_table(REQUEST=REQUEST)
|
T = sco_formations.formation_list_table()
|
||||||
|
|
||||||
H.append(T.html())
|
H.append(T.html())
|
||||||
|
|
||||||
|
@ -456,22 +464,22 @@ sco_publish(
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def formation_list(format=None, REQUEST=None, formation_id=None, args={}):
|
def formation_list(format=None, formation_id=None, args={}):
|
||||||
"""List formation(s) with given id, or matching args
|
"""List formation(s) with given id, or matching args
|
||||||
(when args is given, formation_id is ignored).
|
(when args is given, formation_id is ignored).
|
||||||
"""
|
"""
|
||||||
r = sco_formations.formation_list(formation_id=formation_id, args=args)
|
r = sco_formations.formation_list(formation_id=formation_id, args=args)
|
||||||
return scu.sendResult(REQUEST, r, name="formation", format=format)
|
return scu.sendResult(r, name="formation", format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formation_export")
|
@bp.route("/formation_export")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def formation_export(formation_id, export_ids=False, format=None, REQUEST=None):
|
def formation_export(formation_id, export_ids=False, format=None):
|
||||||
"Export de la formation au format indiqué (xml ou json)"
|
"Export de la formation au format indiqué (xml ou json)"
|
||||||
return sco_formations.formation_export(
|
return sco_formations.formation_export(
|
||||||
formation_id, export_ids=export_ids, format=format, REQUEST=REQUEST
|
formation_id, export_ids=export_ids, format=format
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,7 +509,7 @@ def formation_import_xml_form(REQUEST):
|
||||||
]
|
]
|
||||||
footer = html_sco_header.sco_footer()
|
footer = html_sco_header.sco_footer()
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("xmlfile", {"input_type": "file", "title": "Fichier XML", "size": 30}),),
|
(("xmlfile", {"input_type": "file", "title": "Fichier XML", "size": 30}),),
|
||||||
submitlabel="Importer",
|
submitlabel="Importer",
|
||||||
|
@ -606,8 +614,7 @@ sco_publish("/ue_move", sco_edit_formation.ue_move, Permission.ScoChangeFormatio
|
||||||
@permission_required_compat_scodoc7(Permission.ScoView)
|
@permission_required_compat_scodoc7(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def formsemestre_list(
|
def formsemestre_list(
|
||||||
format=None,
|
format="json",
|
||||||
REQUEST=None,
|
|
||||||
formsemestre_id=None,
|
formsemestre_id=None,
|
||||||
formation_id=None,
|
formation_id=None,
|
||||||
etape_apo=None,
|
etape_apo=None,
|
||||||
|
@ -624,7 +631,7 @@ def formsemestre_list(
|
||||||
args[argname] = L[argname]
|
args[argname] = L[argname]
|
||||||
sems = sco_formsemestre.do_formsemestre_list(args=args)
|
sems = sco_formsemestre.do_formsemestre_list(args=args)
|
||||||
# log('formsemestre_list: format="%s", %s semestres found' % (format,len(sems)))
|
# log('formsemestre_list: format="%s", %s semestres found' % (format,len(sems)))
|
||||||
return scu.sendResult(REQUEST, sems, name="formsemestre", format=format)
|
return scu.sendResult(sems, name="formsemestre", format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route(
|
@bp.route(
|
||||||
|
@ -637,7 +644,7 @@ def XMLgetFormsemestres(etape_apo=None, formsemestre_id=None, REQUEST=None):
|
||||||
"""List all formsemestres matching etape, XML format
|
"""List all formsemestres matching etape, XML format
|
||||||
DEPRECATED: use formsemestre_list()
|
DEPRECATED: use formsemestre_list()
|
||||||
"""
|
"""
|
||||||
log("Warning: calling deprecated XMLgetFormsemestres")
|
current_app.logger.debug("Warning: calling deprecated XMLgetFormsemestres")
|
||||||
args = {}
|
args = {}
|
||||||
if etape_apo:
|
if etape_apo:
|
||||||
args["etape_apo"] = etape_apo
|
args["etape_apo"] = etape_apo
|
||||||
|
@ -708,7 +715,6 @@ def edit_enseignants_form(REQUEST, moduleimpl_id):
|
||||||
M, sem = sco_moduleimpl.can_change_ens(moduleimpl_id)
|
M, sem = sco_moduleimpl.can_change_ens(moduleimpl_id)
|
||||||
# --
|
# --
|
||||||
header = html_sco_header.html_sem_header(
|
header = html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
'Enseignants du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
'Enseignants du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
||||||
% (moduleimpl_id, M["module"]["titre"]),
|
% (moduleimpl_id, M["module"]["titre"]),
|
||||||
page_title="Enseignants du module %s" % M["module"]["titre"],
|
page_title="Enseignants du module %s" % M["module"]["titre"],
|
||||||
|
@ -778,7 +784,7 @@ def edit_enseignants_form(REQUEST, moduleimpl_id):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
modform,
|
modform,
|
||||||
submitlabel="Ajouter enseignant",
|
submitlabel="Ajouter enseignant",
|
||||||
|
@ -830,7 +836,6 @@ def edit_moduleimpl_resp(REQUEST, moduleimpl_id):
|
||||||
M, sem = sco_moduleimpl.can_change_module_resp(REQUEST, moduleimpl_id)
|
M, sem = sco_moduleimpl.can_change_module_resp(REQUEST, moduleimpl_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
'Modification du responsable du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
'Modification du responsable du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
||||||
% (moduleimpl_id, M["module"]["titre"]),
|
% (moduleimpl_id, M["module"]["titre"]),
|
||||||
sem,
|
sem,
|
||||||
|
@ -875,7 +880,7 @@ def edit_moduleimpl_resp(REQUEST, moduleimpl_id):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
submitlabel="Changer responsable",
|
submitlabel="Changer responsable",
|
||||||
|
@ -952,7 +957,6 @@ def edit_moduleimpl_expr(REQUEST, moduleimpl_id):
|
||||||
M, sem = sco_moduleimpl.can_change_ens(moduleimpl_id)
|
M, sem = sco_moduleimpl.can_change_ens(moduleimpl_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
'Modification règle de calcul du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
'Modification règle de calcul du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
||||||
% (moduleimpl_id, M["module"]["titre"]),
|
% (moduleimpl_id, M["module"]["titre"]),
|
||||||
sem,
|
sem,
|
||||||
|
@ -979,7 +983,7 @@ def edit_moduleimpl_expr(REQUEST, moduleimpl_id):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
submitlabel="Modifier formule de calcul",
|
submitlabel="Modifier formule de calcul",
|
||||||
|
@ -1059,7 +1063,6 @@ def view_module_abs(REQUEST, moduleimpl_id, format="html"):
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
'Absences du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
'Absences du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
|
||||||
% (moduleimpl_id, M["module"]["titre"]),
|
% (moduleimpl_id, M["module"]["titre"]),
|
||||||
page_title="Absences du module %s" % (M["module"]["titre"]),
|
page_title="Absences du module %s" % (M["module"]["titre"]),
|
||||||
|
@ -1083,14 +1086,14 @@ def view_module_abs(REQUEST, moduleimpl_id, format="html"):
|
||||||
columns_ids=("nomprenom", "just", "nojust", "total"),
|
columns_ids=("nomprenom", "just", "nojust", "total"),
|
||||||
rows=T,
|
rows=T,
|
||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
base_url="%s?moduleimpl_id=%s" % (REQUEST.URL0, moduleimpl_id),
|
base_url="%s?moduleimpl_id=%s" % (request.base_url, moduleimpl_id),
|
||||||
filename="absmodule_" + scu.make_filename(M["module"]["titre"]),
|
filename="absmodule_" + scu.make_filename(M["module"]["titre"]),
|
||||||
caption="Absences dans le module %s" % M["module"]["titre"],
|
caption="Absences dans le module %s" % M["module"]["titre"],
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
return "\n".join(H) + tab.html() + html_sco_header.sco_footer()
|
return "\n".join(H) + tab.html() + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
@ -1110,7 +1113,6 @@ def edit_ue_expr(REQUEST, formsemestre_id, ue_id):
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
ue = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Modification règle de calcul de l'UE %s (%s)"
|
"Modification règle de calcul de l'UE %s (%s)"
|
||||||
% (ue["acronyme"], ue["titre"]),
|
% (ue["acronyme"], ue["titre"]),
|
||||||
sem,
|
sem,
|
||||||
|
@ -1139,7 +1141,7 @@ def edit_ue_expr(REQUEST, formsemestre_id, ue_id):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
form,
|
form,
|
||||||
submitlabel="Modifier formule de calcul",
|
submitlabel="Modifier formule de calcul",
|
||||||
|
@ -1251,13 +1253,13 @@ def formsemestre_enseignants_list(REQUEST, formsemestre_id, format="html"):
|
||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
filename=scu.make_filename("Enseignants-" + sem["titreannee"]),
|
filename=scu.make_filename("Enseignants-" + sem["titreannee"]),
|
||||||
html_title=html_sco_header.html_sem_header(
|
html_title=html_sco_header.html_sem_header(
|
||||||
REQUEST, "Enseignants du semestre", sem, with_page_header=False
|
"Enseignants du semestre", sem, with_page_header=False
|
||||||
),
|
),
|
||||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
|
||||||
caption="Tous les enseignants (responsables ou associés aux modules de ce semestre) apparaissent. Le nombre de saisies d'absences est le nombre d'opérations d'ajout effectuées sur ce semestre, sans tenir compte des annulations ou double saisies.",
|
caption="Tous les enseignants (responsables ou associés aux modules de ce semestre) apparaissent. Le nombre de saisies d'absences est le nombre d'opérations d'ajout effectuées sur ce semestre, sans tenir compte des annulations ou double saisies.",
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
)
|
)
|
||||||
return T.make_page(page_title=title, title=title, REQUEST=REQUEST, format=format)
|
return T.make_page(page_title=title, title=title, format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/edit_enseignants_form_delete", methods=["GET", "POST"])
|
@bp.route("/edit_enseignants_form_delete", methods=["GET", "POST"])
|
||||||
|
@ -1320,7 +1322,7 @@ def do_formsemestre_inscription_listinscrits(
|
||||||
r = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
r = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
||||||
formsemestre_id
|
formsemestre_id
|
||||||
)
|
)
|
||||||
return scu.sendResult(REQUEST, r, format=format, name="inscrits")
|
return scu.sendResult(r, format=format, name="inscrits")
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formsemestre_desinscription", methods=["GET", "POST"])
|
@bp.route("/formsemestre_desinscription", methods=["GET", "POST"])
|
||||||
|
@ -1506,7 +1508,7 @@ def evaluation_delete(REQUEST, evaluation_id):
|
||||||
tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
|
tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
|
||||||
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(REQUEST, tit, with_h2=False),
|
html_sco_header.html_sem_header(tit, with_h2=False),
|
||||||
"""<h2 class="formsemestre">Module <tt>%(code)s</tt> %(titre)s</h2>""" % Mod,
|
"""<h2 class="formsemestre">Module <tt>%(code)s</tt> %(titre)s</h2>""" % Mod,
|
||||||
"""<h3>%s</h3>""" % tit,
|
"""<h3>%s</h3>""" % tit,
|
||||||
"""<p class="help">Opération <span class="redboldtext">irréversible</span>. Si vous supprimez l'évaluation, vous ne pourrez pas retrouver les notes associées.</p>""",
|
"""<p class="help">Opération <span class="redboldtext">irréversible</span>. Si vous supprimez l'évaluation, vous ne pourrez pas retrouver les notes associées.</p>""",
|
||||||
|
@ -1538,7 +1540,7 @@ def evaluation_delete(REQUEST, evaluation_id):
|
||||||
H.append("""</div>""")
|
H.append("""</div>""")
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(("evaluation_id", {"input_type": "hidden"}),),
|
(("evaluation_id", {"input_type": "hidden"}),),
|
||||||
initvalues=E,
|
initvalues=E,
|
||||||
|
@ -1645,8 +1647,8 @@ sco_publish(
|
||||||
"/placement_eval_selectetuds",
|
"/placement_eval_selectetuds",
|
||||||
sco_placement.placement_eval_selectetuds,
|
sco_placement.placement_eval_selectetuds,
|
||||||
Permission.ScoEnsView,
|
Permission.ScoEnsView,
|
||||||
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish("/do_placement", sco_placement.do_placement, Permission.ScoEnsView)
|
|
||||||
|
|
||||||
# --- Saisie des notes
|
# --- Saisie des notes
|
||||||
sco_publish(
|
sco_publish(
|
||||||
|
@ -1691,7 +1693,7 @@ def formsemestre_bulletins_pdf(formsemestre_id, REQUEST, version="selectedevals"
|
||||||
pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
||||||
formsemestre_id, REQUEST, version=version
|
formsemestre_id, REQUEST, version=version
|
||||||
)
|
)
|
||||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
return scu.sendPDFFile(pdfdoc, filename)
|
||||||
|
|
||||||
|
|
||||||
_EXPL_BULL = """Versions des bulletins:<ul><li><bf>courte</bf>: moyennes des modules</li><li><bf>intermédiaire</bf>: moyennes des modules et notes des évaluations sélectionnées</li><li><bf>complète</bf>: toutes les notes</li><ul>"""
|
_EXPL_BULL = """Versions des bulletins:<ul><li><bf>courte</bf>: moyennes des modules</li><li><bf>intermédiaire</bf>: moyennes des modules et notes des évaluations sélectionnées</li><li><bf>complète</bf>: toutes les notes</li><ul>"""
|
||||||
|
@ -1707,7 +1709,7 @@ def formsemestre_bulletins_pdf_choice(REQUEST, formsemestre_id, version=None):
|
||||||
pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
||||||
formsemestre_id, REQUEST, version=version
|
formsemestre_id, REQUEST, version=version
|
||||||
)
|
)
|
||||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
return scu.sendPDFFile(pdfdoc, filename)
|
||||||
return formsemestre_bulletins_choice(
|
return formsemestre_bulletins_choice(
|
||||||
REQUEST,
|
REQUEST,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
|
@ -1725,7 +1727,7 @@ def etud_bulletins_pdf(etudid, REQUEST, version="selectedevals"):
|
||||||
pdfdoc, filename = sco_bulletins_pdf.get_etud_bulletins_pdf(
|
pdfdoc, filename = sco_bulletins_pdf.get_etud_bulletins_pdf(
|
||||||
etudid, REQUEST, version=version
|
etudid, REQUEST, version=version
|
||||||
)
|
)
|
||||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
return scu.sendPDFFile(pdfdoc, filename)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formsemestre_bulletins_mailetuds_choice")
|
@bp.route("/formsemestre_bulletins_mailetuds_choice")
|
||||||
|
@ -1771,12 +1773,12 @@ def formsemestre_bulletins_choice(
|
||||||
"""Choix d'une version de bulletin"""
|
"""Choix d'une version de bulletin"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(REQUEST, title, sem),
|
html_sco_header.html_sem_header(title, sem),
|
||||||
"""
|
"""
|
||||||
<form name="f" method="GET" action="%s">
|
<form name="f" method="GET" action="%s">
|
||||||
<input type="hidden" name="formsemestre_id" value="%s"></input>
|
<input type="hidden" name="formsemestre_id" value="%s"></input>
|
||||||
"""
|
"""
|
||||||
% (REQUEST.URL0, formsemestre_id),
|
% (request.base_url, formsemestre_id),
|
||||||
]
|
]
|
||||||
H.append("""<select name="version" class="noprint">""")
|
H.append("""<select name="version" class="noprint">""")
|
||||||
for (v, e) in (
|
for (v, e) in (
|
||||||
|
@ -1928,7 +1930,7 @@ def appreciation_add_form(
|
||||||
else:
|
else:
|
||||||
initvalues = {}
|
initvalues = {}
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
initvalues=initvalues,
|
initvalues=initvalues,
|
||||||
|
@ -2010,8 +2012,7 @@ def formsemestre_validation_etud(
|
||||||
"Enregistre choix jury pour un étudiant"
|
"Enregistre choix jury pour un étudiant"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2043,8 +2044,7 @@ def formsemestre_validation_etud_manu(
|
||||||
"Enregistre choix jury pour un étudiant"
|
"Enregistre choix jury pour un étudiant"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2069,8 +2069,7 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid=None, REQUEST=None
|
||||||
"Form. saisie UE validée hors ScoDoc"
|
"Form. saisie UE validée hors ScoDoc"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
return sco_formsemestre_validation.formsemestre_validate_previous_ue(
|
return sco_formsemestre_validation.formsemestre_validate_previous_ue(
|
||||||
|
@ -2094,8 +2093,7 @@ def formsemestre_ext_edit_ue_validations(formsemestre_id, etudid=None, REQUEST=N
|
||||||
"Form. edition UE semestre extérieur"
|
"Form. edition UE semestre extérieur"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
return sco_formsemestre_exterieurs.formsemestre_ext_edit_ue_validations(
|
return sco_formsemestre_exterieurs.formsemestre_ext_edit_ue_validations(
|
||||||
|
@ -2118,8 +2116,7 @@ def etud_ue_suppress_validation(etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||||
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
return sco_formsemestre_validation.etud_ue_suppress_validation(
|
return sco_formsemestre_validation.etud_ue_suppress_validation(
|
||||||
|
@ -2135,8 +2132,7 @@ def formsemestre_validation_auto(formsemestre_id, REQUEST):
|
||||||
"Formulaire saisie automatisee des decisions d'un semestre"
|
"Formulaire saisie automatisee des decisions d'un semestre"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2153,8 +2149,7 @@ def do_formsemestre_validation_auto(formsemestre_id, REQUEST):
|
||||||
"Formulaire saisie automatisee des decisions d'un semestre"
|
"Formulaire saisie automatisee des decisions d'un semestre"
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2173,8 +2168,7 @@ def formsemestre_validation_suppress_etud(
|
||||||
"""Suppression des decisions de jury pour un etudiant."""
|
"""Suppression des decisions de jury pour un etudiant."""
|
||||||
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
if not sco_permissions_check.can_validate_sem(formsemestre_id):
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
message="<p>Opération non autorisée pour %s</h2>"
|
message="<p>Opération non autorisée pour %s</h2>" % current_user,
|
||||||
% REQUEST.AUTHENTICATED_USER,
|
|
||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
|
@ -2260,11 +2254,13 @@ sco_publish(
|
||||||
"/view_apo_csv_store",
|
"/view_apo_csv_store",
|
||||||
sco_etape_apogee_view.view_apo_csv_store,
|
sco_etape_apogee_view.view_apo_csv_store,
|
||||||
Permission.ScoEditApo,
|
Permission.ScoEditApo,
|
||||||
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/view_apo_csv_download_and_store",
|
"/view_apo_csv_download_and_store",
|
||||||
sco_etape_apogee_view.view_apo_csv_download_and_store,
|
sco_etape_apogee_view.view_apo_csv_download_and_store,
|
||||||
Permission.ScoEditApo,
|
Permission.ScoEditApo,
|
||||||
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/view_apo_csv_delete",
|
"/view_apo_csv_delete",
|
||||||
|
@ -2510,7 +2506,7 @@ def check_form_integrity(formation_id, fix=False, REQUEST=None):
|
||||||
log("check_form_integrity: formation_id=%s\ninconsistencies:" % formation_id)
|
log("check_form_integrity: formation_id=%s\ninconsistencies:" % formation_id)
|
||||||
log(txt)
|
log(txt)
|
||||||
# Notify by e-mail
|
# Notify by e-mail
|
||||||
sendAlarm("Notes: formation incoherente !", txt)
|
send_scodoc_alarm("Notes: formation incoherente !", txt)
|
||||||
else:
|
else:
|
||||||
txth = "OK"
|
txth = "OK"
|
||||||
log("ok")
|
log("ok")
|
||||||
|
|
|
@ -68,13 +68,8 @@ from app.scodoc.sco_exceptions import (
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
ScoException,
|
ScoException,
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
ScoInvalidDateError,
|
|
||||||
ScoLockedFormError,
|
|
||||||
ScoGenError,
|
|
||||||
ScoInvalidDept,
|
|
||||||
)
|
)
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
import sco_version
|
|
||||||
import app
|
import app
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
|
@ -267,7 +262,7 @@ def showEtudLog(etudid, format="html", REQUEST=None):
|
||||||
rows=ops,
|
rows=ops,
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
base_url="%s?etudid=%s" % (REQUEST.URL0, etudid),
|
base_url="%s?etudid=%s" % (request.base_url, etudid),
|
||||||
page_title="Opérations sur %(nomprenom)s" % etud,
|
page_title="Opérations sur %(nomprenom)s" % etud,
|
||||||
html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>" % etud,
|
html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>" % etud,
|
||||||
filename="log_" + scu.make_filename(etud["nomprenom"]),
|
filename="log_" + scu.make_filename(etud["nomprenom"]),
|
||||||
|
@ -279,7 +274,7 @@ def showEtudLog(etudid, format="html", REQUEST=None):
|
||||||
preferences=sco_preferences.SemPreferences(),
|
preferences=sco_preferences.SemPreferences(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
# ---------- PAGE ACCUEIL (listes) --------------
|
# ---------- PAGE ACCUEIL (listes) --------------
|
||||||
|
@ -341,7 +336,7 @@ def getEtudInfo(etudid=False, code_nip=False, filled=False, REQUEST=None, format
|
||||||
if format is None:
|
if format is None:
|
||||||
return etud
|
return etud
|
||||||
else:
|
else:
|
||||||
return scu.sendResult(REQUEST, etud, name="etud", format=format)
|
return scu.sendResult(etud, name="etud", format=format)
|
||||||
|
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
|
@ -396,7 +391,7 @@ def etud_info(etudid=None, format="xml", REQUEST=None):
|
||||||
"error": "code etudiant inconnu",
|
"error": "code etudiant inconnu",
|
||||||
}
|
}
|
||||||
return scu.sendResult(
|
return scu.sendResult(
|
||||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
d, name="etudiant", format=format, force_outer_xml_tag=False
|
||||||
)
|
)
|
||||||
d = {}
|
d = {}
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
|
@ -464,9 +459,7 @@ def etud_info(etudid=None, format="xml", REQUEST=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
log("etud_info (%gs)" % (time.time() - t0))
|
log("etud_info (%gs)" % (time.time() - t0))
|
||||||
return scu.sendResult(
|
return scu.sendResult(d, name="etudiant", format=format, force_outer_xml_tag=False)
|
||||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------- FICHE ETUDIANT --------------------------
|
# -------------------------- FICHE ETUDIANT --------------------------
|
||||||
|
@ -617,7 +610,7 @@ def formChangeCoordonnees(etudid, REQUEST):
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("adresse_id", {"input_type": "hidden"}),
|
("adresse_id", {"input_type": "hidden"}),
|
||||||
|
@ -817,13 +810,13 @@ def formChangePhoto(etudid=None, REQUEST=None):
|
||||||
<p>Photo actuelle (%(photoloc)s):
|
<p>Photo actuelle (%(photoloc)s):
|
||||||
"""
|
"""
|
||||||
% etud,
|
% etud,
|
||||||
sco_photos.etud_photo_html(etud, title="photo actuelle", REQUEST=REQUEST),
|
sco_photos.etud_photo_html(etud, title="photo actuelle"),
|
||||||
"""</p><p>Le fichier ne doit pas dépasser 500Ko (recadrer l'image, format "portrait" de préférence).</p>
|
"""</p><p>Le fichier ne doit pas dépasser 500Ko (recadrer l'image, format "portrait" de préférence).</p>
|
||||||
<p>L'image sera automagiquement réduite pour obtenir une hauteur de 90 pixels.</p>
|
<p>L'image sera automagiquement réduite pour obtenir une hauteur de 90 pixels.</p>
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
("etudid", {"default": etudid, "input_type": "hidden"}),
|
("etudid", {"default": etudid, "input_type": "hidden"}),
|
||||||
|
@ -858,7 +851,7 @@ def formChangePhoto(etudid=None, REQUEST=None):
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formSuppressPhoto")
|
@bp.route("/formSuppressPhoto", methods=["POST", "GET"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoEtudChangeAdr)
|
@permission_required(Permission.ScoEtudChangeAdr)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
|
@ -1496,7 +1489,7 @@ def _etudident_create_or_edit_form(REQUEST, edit):
|
||||||
]
|
]
|
||||||
initvalues["dont_check_homonyms"] = False
|
initvalues["dont_check_homonyms"] = False
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
submitlabel=submitlabel,
|
submitlabel=submitlabel,
|
||||||
|
@ -1647,7 +1640,6 @@ def check_group_apogee(group_id, REQUEST=None, etat=None, fix=False, fixmail=Fal
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
REQUEST,
|
|
||||||
"Etudiants du %s" % (group["group_name"] or "semestre"),
|
"Etudiants du %s" % (group["group_name"] or "semestre"),
|
||||||
sem,
|
sem,
|
||||||
),
|
),
|
||||||
|
@ -1748,7 +1740,7 @@ def check_group_apogee(group_id, REQUEST=None, etat=None, fix=False, fixmail=Fal
|
||||||
<p><a href="Notes/formsemestre_status?formsemestre_id=%s"> Retour au semestre</a>
|
<p><a href="Notes/formsemestre_status?formsemestre_id=%s"> Retour au semestre</a>
|
||||||
"""
|
"""
|
||||||
% (
|
% (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
scu.strnone(group_id),
|
scu.strnone(group_id),
|
||||||
scu.strnone(etat),
|
scu.strnone(etat),
|
||||||
|
@ -1767,7 +1759,7 @@ def check_group_apogee(group_id, REQUEST=None, etat=None, fix=False, fixmail=Fal
|
||||||
<p><a href="Notes/formsemestre_status?formsemestre_id=%s"> Retour au semestre</a>
|
<p><a href="Notes/formsemestre_status?formsemestre_id=%s"> Retour au semestre</a>
|
||||||
"""
|
"""
|
||||||
% (
|
% (
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
scu.strnone(group_id),
|
scu.strnone(group_id),
|
||||||
scu.strnone(etat),
|
scu.strnone(etat),
|
||||||
|
@ -1856,7 +1848,7 @@ def form_students_import_excel(REQUEST, formsemestre_id=None):
|
||||||
|
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -1937,7 +1929,10 @@ def import_generate_excel_sample(REQUEST, with_codesemestre="1"):
|
||||||
data = sco_import_etuds.sco_import_generate_excel_sample(
|
data = sco_import_etuds.sco_import_generate_excel_sample(
|
||||||
format, with_codesemestre, exclude_cols=["photo_filename"]
|
format, with_codesemestre, exclude_cols=["photo_filename"]
|
||||||
)
|
)
|
||||||
return sco_excel.send_excel_file(REQUEST, data, "ImportEtudiants" + scu.XLSX_SUFFIX)
|
return scu.send_file(
|
||||||
|
data, "ImportEtudiants", scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE
|
||||||
|
)
|
||||||
|
# return sco_excel.send_excel_file(REQUEST, data, "ImportEtudiants" + scu.XLSX_SUFFIX)
|
||||||
|
|
||||||
|
|
||||||
# --- Données admission
|
# --- Données admission
|
||||||
|
@ -1955,9 +1950,10 @@ def import_generate_admission_sample(REQUEST, formsemestre_id):
|
||||||
exclude_cols=["nationalite", "foto", "photo_filename"],
|
exclude_cols=["nationalite", "foto", "photo_filename"],
|
||||||
group_ids=[group["group_id"]],
|
group_ids=[group["group_id"]],
|
||||||
)
|
)
|
||||||
return sco_excel.send_excel_file(
|
return scu.send_file(
|
||||||
REQUEST, data, "AdmissionEtudiants" + scu.XLSX_SUFFIX
|
data, "AdmissionEtudiants", scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE
|
||||||
)
|
)
|
||||||
|
# return sco_excel.send_excel_file(REQUEST, data, "AdmissionEtudiants" + scu.XLSX_SUFFIX)
|
||||||
|
|
||||||
|
|
||||||
# --- Données admission depuis fichier excel (version nov 2016)
|
# --- Données admission depuis fichier excel (version nov 2016)
|
||||||
|
@ -1967,7 +1963,7 @@ def import_generate_admission_sample(REQUEST, formsemestre_id):
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def form_students_import_infos_admissions(REQUEST, formsemestre_id=None):
|
def form_students_import_infos_admissions(REQUEST, formsemestre_id=None):
|
||||||
"formulaire import xls"
|
"formulaire import xls"
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = current_user
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
if not authuser.has_permission(Permission.ScoEtudInscrit):
|
if not authuser.has_permission(Permission.ScoEtudInscrit):
|
||||||
# autorise juste l'export
|
# autorise juste l'export
|
||||||
|
@ -2021,7 +2017,7 @@ def form_students_import_infos_admissions(REQUEST, formsemestre_id=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -2084,7 +2080,7 @@ def formsemestre_import_etud_admission(
|
||||||
formsemestre_id, import_identite=True, import_email=import_email
|
formsemestre_id, import_identite=True, import_email=import_email
|
||||||
)
|
)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(REQUEST, "Reimport données admission"),
|
html_sco_header.html_sem_header("Reimport données admission"),
|
||||||
"<h3>Opération effectuée</h3>",
|
"<h3>Opération effectuée</h3>",
|
||||||
]
|
]
|
||||||
if no_nip:
|
if no_nip:
|
||||||
|
|
|
@ -65,8 +65,6 @@ from app import log
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
from app.scodoc.sco_permissions_check import can_handle_passwd
|
from app.scodoc.sco_permissions_check import can_handle_passwd
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
from app.scodoc.sco_excel import send_excel_file
|
|
||||||
from app.scodoc.sco_import_users import generate_excel_sample
|
|
||||||
from app.views import users_bp as bp
|
from app.views import users_bp as bp
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,7 +88,7 @@ def index_html(REQUEST, all_depts=False, with_inactives=False, format="html"):
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def user_info(user_name, format="json", REQUEST=None):
|
def user_info(user_name, format="json", REQUEST=None):
|
||||||
info = sco_users.user_info(user_name)
|
info = sco_users.user_info(user_name)
|
||||||
return scu.sendResult(REQUEST, info, name="user", format=format)
|
return scu.sendResult(info, name="user", format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/create_user_form", methods=["GET", "POST"])
|
@bp.route("/create_user_form", methods=["GET", "POST"])
|
||||||
|
@ -344,7 +342,7 @@ def create_user_form(REQUEST, user_name=None, edit=0, all_roles=1):
|
||||||
)
|
)
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
descr,
|
descr,
|
||||||
initvalues=initvalues,
|
initvalues=initvalues,
|
||||||
|
@ -490,9 +488,7 @@ def create_user_form(REQUEST, user_name=None, edit=0, all_roles=1):
|
||||||
def import_users_generate_excel_sample(REQUEST):
|
def import_users_generate_excel_sample(REQUEST):
|
||||||
"une feuille excel pour importation utilisateurs"
|
"une feuille excel pour importation utilisateurs"
|
||||||
data = sco_import_users.generate_excel_sample()
|
data = sco_import_users.generate_excel_sample()
|
||||||
return sco_excel.send_excel_file(
|
return scu.send_file(data, "ImportUtilisateurs", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
|
||||||
REQUEST, data, "ImportUtilisateurs" + scu.XLSX_SUFFIX
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/import_users_form", methods=["GET", "POST"])
|
@bp.route("/import_users_form", methods=["GET", "POST"])
|
||||||
|
@ -532,7 +528,7 @@ def import_users_form(REQUEST=None):
|
||||||
)
|
)
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
request.base_url,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -546,7 +542,7 @@ def import_users_form(REQUEST=None):
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return flask.redirect(back_url)
|
return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept))
|
||||||
else:
|
else:
|
||||||
# IMPORT
|
# IMPORT
|
||||||
ok, diag, nb_created = sco_import_users.import_excel_file(tf[2]["xlsfile"])
|
ok, diag, nb_created = sco_import_users.import_excel_file(tf[2]["xlsfile"])
|
||||||
|
@ -654,8 +650,8 @@ def change_password(user_name, password, password2, REQUEST):
|
||||||
if not can_handle_passwd(u):
|
if not can_handle_passwd(u):
|
||||||
# access denied
|
# access denied
|
||||||
log(
|
log(
|
||||||
"change_password: access denied (authuser=%s, user_name=%s, ip=%s)"
|
"change_password: access denied (authuser=%s, user_name=%s)"
|
||||||
% (REQUEST.AUTHENTICATED_USER, user_name, REQUEST.REMOTE_ADDR)
|
% (current_user, user_name)
|
||||||
)
|
)
|
||||||
raise AccessDenied("vous n'avez pas la permission de changer ce mot de passe")
|
raise AccessDenied("vous n'avez pas la permission de changer ce mot de passe")
|
||||||
H = []
|
H = []
|
||||||
|
|
|
@ -30,6 +30,8 @@ class Config:
|
||||||
SCODOC_DIR = os.environ.get("SCODOC_DIR", "/opt/scodoc")
|
SCODOC_DIR = os.environ.get("SCODOC_DIR", "/opt/scodoc")
|
||||||
SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "/opt/scodoc-data")
|
SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "/opt/scodoc-data")
|
||||||
SCODOC_LOG_FILE = os.path.join(SCODOC_VAR_DIR, "log", "scodoc.log")
|
SCODOC_LOG_FILE = os.path.join(SCODOC_VAR_DIR, "log", "scodoc.log")
|
||||||
|
# evite confusion avec le log nginx scodoc_error.log:
|
||||||
|
SCODOC_ERR_FILE = os.path.join(SCODOC_VAR_DIR, "log", "scodoc_exc.log")
|
||||||
#
|
#
|
||||||
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # Flask uploads
|
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # Flask uploads
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ class DevConfig(Config):
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
TESTING = False
|
TESTING = False
|
||||||
SQLALCHEMY_DATABASE_URI = (
|
SQLALCHEMY_DATABASE_URI = (
|
||||||
os.environ.get("SCODOC_DEV_DATABASE_URI") or "postgresql:///SCODOC_DEV"
|
os.environ.get("SCODOC_DATABASE_URI") or "postgresql:///SCODOC_DEV"
|
||||||
)
|
)
|
||||||
SECRET_KEY = os.environ.get("DEV_SECRET_KEY") or "bb3faec7d9a34eb68a8e3e710087d87a"
|
SECRET_KEY = os.environ.get("DEV_SECRET_KEY") or "bb3faec7d9a34eb68a8e3e710087d87a"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""Flag bloquage calcul moyennes
|
||||||
|
|
||||||
|
Revision ID: 669065fb2d20
|
||||||
|
Revises: a217bf588f4c
|
||||||
|
Create Date: 2021-09-16 22:04:11.624632
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '669065fb2d20'
|
||||||
|
down_revision = 'a217bf588f4c'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('notes_formsemestre', sa.Column('block_moyennes', sa.Boolean(), server_default='false', nullable=False))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('notes_formsemestre', 'block_moyennes')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""modif contrainte sur formations
|
||||||
|
|
||||||
|
Revision ID: f86c013c9fbd
|
||||||
|
Revises: 669065fb2d20
|
||||||
|
Create Date: 2021-09-19 21:30:42.240422
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f86c013c9fbd'
|
||||||
|
down_revision = '669065fb2d20'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint('notes_formations_acronyme_titre_version_key', 'notes_formations', type_='unique')
|
||||||
|
op.create_unique_constraint(None, 'notes_formations', ['dept_id', 'acronyme', 'titre', 'version'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(None, 'notes_formations', type_='unique')
|
||||||
|
op.create_unique_constraint('notes_formations_acronyme_titre_version_key', 'notes_formations', ['acronyme', 'titre', 'version'])
|
||||||
|
# ### end Alembic commands ###
|
|
@ -1,68 +1,69 @@
|
||||||
|
|
||||||
Notes sur la restauration de la base SQL complete
|
Notes sur la restauration de la base SQL complete (ScoDoc 9)
|
||||||
(dans le cas d'une réinstallation sur une autre machine, par exemple)
|
(dans le cas d'une réinstallation sur une autre machine, par exemple)
|
||||||
|
|
||||||
|
|
||||||
1) Sur la machine origine, faire un dump complet:
|
1) Sur la machine origine, faire un dump complet:
|
||||||
su postgres
|
su postgres
|
||||||
cd /tmp # ou ailleurs...
|
cd /tmp # ou ailleurs...
|
||||||
pg_dumpall > scodoc.dump.txt
|
pg_dumpall | gzip > scodoc.dump.txt.gz
|
||||||
|
|
||||||
On obtient un fichier texte assez volumineux (on peut utiliser gzip pour le compresser avant transfert).
|
On obtient un fichier texte assez volumineux (comprimé par gzip ci-dessus)
|
||||||
|
|
||||||
Le copier sur la machine destination.
|
Le copier sur la machine destination, et le décompresser (gunzip).
|
||||||
|
|
||||||
2) Sur la machine destination:
|
2) Sur la machine destination:
|
||||||
|
|
||||||
Avant toute chose, stopper scodoc:
|
Avant toute chose, stopper scodoc:
|
||||||
/etc/init.d/scodoc stop (ou systemctl stop scodoc))
|
|
||||||
|
systemctl stop scodoc9
|
||||||
|
|
||||||
1.1) Supprimer toutes les bases ScoDoc existantes s'il y en a:
|
1.1) Supprimer toutes les bases ScoDoc existantes s'il y en a:
|
||||||
su postgres
|
su scodoc
|
||||||
psql -l
|
psql -l
|
||||||
liste les bases: celles de ScoDoc sont SCO*
|
liste les bases: celles de ScoDoc sont SCO*
|
||||||
|
|
||||||
Pour chaque base SCO*, faire dropdb
|
Pour chaque base SCO*, faire dropdb
|
||||||
dropdb SCOUSERS
|
dropdb SCODOC
|
||||||
dropdb SCOGEII
|
dropdb SCODOC_DEV
|
||||||
...
|
...
|
||||||
|
|
||||||
Pour les feignants, voici un script (à lancer comme utilisateur postgres):
|
Pour les gens pressés, voici un script (à lancer comme utilisateur postgres):
|
||||||
for f in $(psql -l --no-align --field-separator . | grep SCO | cut -f 1 -d.); do
|
for f in $(psql -l --no-align --field-separator . | grep SCO | cut -f 1 -d.); do
|
||||||
echo dropping $f
|
echo dropping $f
|
||||||
dropdb $f
|
dropdb $f
|
||||||
done
|
done
|
||||||
|
|
||||||
1.2) Charger le dump (toujours comme utilisateur postgres):
|
1.2) Charger le dump (toujours comme utilisateur scodoc):
|
||||||
psql -f scodoc.dump.txt postgres
|
psql -f scodoc.dump.txt scodoc
|
||||||
|
|
||||||
1.3) Recopier les fichiers (photos, config, archives): copier le repertoire complet
|
1.3) Recopier les fichiers (photos, config, archives): copier le repertoire complet
|
||||||
/opt/scodoc/instance/var
|
/opt/scodoc-data
|
||||||
de la machine origine vers la nouvelle
|
de la machine origine vers la nouvelle
|
||||||
|
|
||||||
|
|
||||||
Puis redemarrer ScoDoc:
|
Puis redemarrer ScoDoc:
|
||||||
en tant que root: /etc/init.d/scodoc start (ou systemctl start scodoc)
|
en tant que root: systemctl start scodoc9
|
||||||
|
|
||||||
NB: si la version des sources a changée, lancer imperativement le script de mise a jour
|
NB: si la version des sources a changée, lancer imperativement le script de mise a jour
|
||||||
avant de redemarrer scodoc, afin qu'il change si besoin la base de donnees:
|
avant de redemarrer scodoc, afin qu'il change si besoin la base de donnees:
|
||||||
(en tant que root):
|
(en tant que root):
|
||||||
cd /opt/scodoc/instance/Products/ScoDoc/config
|
apt-get update &&
|
||||||
./upgrade.sh
|
|
||||||
|
|
||||||
|
|
||||||
----
|
----
|
||||||
Cas d'une seule base à copier: (eg un seul département, mais faire
|
Cas d'une seule base à copier (base production ou dev. par exemple)
|
||||||
attention aux utilisateurs definis dans la base SCOUSERS):
|
|
||||||
|
|
||||||
En tant qu'utilisateur "postgres":
|
En tant qu'utilisateur "scodoc":
|
||||||
Dump: (script avec commande de creation de la base)
|
Dump: permettant de la recharger en changeant son nom
|
||||||
pg_dump --create SCOINFO > /tmp/scoinfo.dump
|
pg_dump --format=custom --file=/tmp/SCODOC.dump SCODOC
|
||||||
|
|
||||||
Restore: (si necessaire, utiliser dropdb avant)
|
Restore: (si necessaire, utiliser dropdb avant)
|
||||||
psql -f /tmp/scoinfo.dump postgres
|
createdb SCODOC_IUTV
|
||||||
|
pg_restore -d SCODOC_IUTV SCODOC.dump
|
||||||
|
(si on veut garder le même nom de base que l'origine, utiliser --create )
|
||||||
|
|
||||||
---
|
--- à revoir
|
||||||
Cas d'un dump via sco_dump_db (assistance):
|
Cas d'un dump via sco_dump_db (assistance):
|
||||||
createdb -E UTF-8 SCOXXX
|
createdb -E UTF-8 SCOXXX
|
||||||
zcat xxx | psql SCOXXX
|
zcat xxx | psql SCOXXX
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
-- Creation des tables pour gestion notes
|
-- Creation des tables pour gestion notes ScoDoc 7 (OBSOLETE !)
|
||||||
-- E. Viennet, Sep 2005
|
-- E. Viennet, Sep 2005
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.0.23"
|
SCOVERSION = "9.0.37"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
|
21
scodoc.py
21
scodoc.py
|
@ -264,6 +264,17 @@ def create_dept(dept): # create-dept
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@app.cli.command()
|
||||||
|
@click.argument("depts", nargs=-1)
|
||||||
|
def list_depts(depts=""): # list-dept
|
||||||
|
"""If dept exists, print it, else nothing.
|
||||||
|
Called without arguments, list all depts along with their ids.
|
||||||
|
"""
|
||||||
|
for dept in models.Departement.query.order_by(models.Departement.id):
|
||||||
|
if not depts or dept.acronym in depts:
|
||||||
|
print(f"{dept.id}\t{dept.acronym}")
|
||||||
|
|
||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def import_scodoc7_users(): # import-scodoc7-users
|
def import_scodoc7_users(): # import-scodoc7-users
|
||||||
|
@ -282,12 +293,20 @@ def import_scodoc7_users(): # import-scodoc7-users
|
||||||
@click.argument("dept")
|
@click.argument("dept")
|
||||||
@click.argument("dept_db_name")
|
@click.argument("dept_db_name")
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def import_scodoc7_dept(dept: str, dept_db_name: str): # import-scodoc7-dept
|
def import_scodoc7_dept(dept: str, dept_db_name: str = ""): # import-scodoc7-dept
|
||||||
"""Import département ScoDoc 7: dept: InfoComm, dept_db_name: SCOINFOCOMM"""
|
"""Import département ScoDoc 7: dept: InfoComm, dept_db_name: SCOINFOCOMM"""
|
||||||
dept_db_uri = f"postgresql:///{dept_db_name}"
|
dept_db_uri = f"postgresql:///{dept_db_name}"
|
||||||
tools.import_scodoc7_dept(dept, dept_db_uri)
|
tools.import_scodoc7_dept(dept, dept_db_uri)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cli.command()
|
||||||
|
@click.argument("dept", default="")
|
||||||
|
@with_appcontext
|
||||||
|
def migrate_scodoc7_dept_archive(dept: str): # migrate-scodoc7-dept-archive
|
||||||
|
"""Post-migration: renomme les archives en fonction des id de ScoDoc 9"""
|
||||||
|
tools.migrate_scodoc7_dept_archive(dept)
|
||||||
|
|
||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def clear_cache(): # clear-cache
|
def clear_cache(): # clear-cache
|
||||||
|
|
|
@ -1,62 +1,62 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Scenario: préparation base de données pour tests Selenium
|
Scenario: préparation base de données pour tests Selenium
|
||||||
|
|
||||||
S'utilise comme un test avec pytest, mais n'est pas un test !
|
S'utilise comme un test avec pytest, mais n'est pas un test !
|
||||||
Modifie la base de données du département TEST00
|
Modifie la base de données du département TEST00
|
||||||
|
|
||||||
Usage: pytest tests/scenarios/test_scenario1_formation.py
|
Usage: pytest tests/scenarios/test_scenario1_formation.py
|
||||||
"""
|
"""
|
||||||
# code écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en août 2021
|
# code écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en août 2021
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
|
|
||||||
|
|
||||||
def test_scenario1(test_client):
|
def test_scenario1(test_client):
|
||||||
"""Applique "scenario 1"""
|
"""Applique "scenario 1"""
|
||||||
run_scenario1()
|
run_scenario1()
|
||||||
|
|
||||||
|
|
||||||
def run_scenario1():
|
def run_scenario1():
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
|
||||||
# Lecture fichier XML local:
|
# Lecture fichier XML local:
|
||||||
with open("tests/unit/formation-exemple-1.xml") as f:
|
with open("tests/unit/formation-exemple-1.xml") as f:
|
||||||
doc = f.read()
|
doc = f.read()
|
||||||
|
|
||||||
# --- Création de la formation
|
# --- Création de la formation
|
||||||
f = sco_formations.formation_import_xml(doc=doc)
|
f = sco_formations.formation_import_xml(doc=doc)
|
||||||
|
|
||||||
# --- Création des semestres
|
# --- Création des semestres
|
||||||
formation_id = f[0]
|
formation_id = f[0]
|
||||||
# --- Mise en place de 4 semestres
|
# --- Mise en place de 4 semestres
|
||||||
sems = [
|
sems = [
|
||||||
G.create_formsemestre(
|
G.create_formsemestre(
|
||||||
formation_id=formation_id,
|
formation_id=formation_id,
|
||||||
semestre_id=x[0],
|
semestre_id=x[0],
|
||||||
date_debut=x[1],
|
date_debut=x[1],
|
||||||
date_fin=x[2],
|
date_fin=x[2],
|
||||||
)
|
)
|
||||||
for x in (
|
for x in (
|
||||||
(1, "01/09/2020", "01/02/2021"),
|
(1, "01/09/2020", "01/02/2021"),
|
||||||
(2, "02/02/2021", "01/06/2021"),
|
(2, "02/02/2021", "01/06/2021"),
|
||||||
(3, "01/09/2020", "01/02/2021"),
|
(3, "01/09/2020", "01/02/2021"),
|
||||||
(4, "02/02/2021", "01/06/2021"),
|
(4, "02/02/2021", "01/06/2021"),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# --- Implémentation des modules
|
# --- Implémentation des modules
|
||||||
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
||||||
mods_imp = []
|
mods_imp = []
|
||||||
for mod in modules:
|
for mod in modules:
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
formsemestre_id=sems[mod["semestre_id"] - 1]["formsemestre_id"],
|
formsemestre_id=sems[mod["semestre_id"] - 1]["formsemestre_id"],
|
||||||
)
|
)
|
||||||
mods_imp.append(mi)
|
mods_imp.append(mi)
|
||||||
|
|
|
@ -219,6 +219,7 @@ class ScoFake(object):
|
||||||
etat=None,
|
etat=None,
|
||||||
gestion_compensation=None,
|
gestion_compensation=None,
|
||||||
bul_hide_xml=None,
|
bul_hide_xml=None,
|
||||||
|
block_moyennes=None,
|
||||||
gestion_semestrielle=None,
|
gestion_semestrielle=None,
|
||||||
bul_bgcolor=None,
|
bul_bgcolor=None,
|
||||||
modalite=NotesFormModalite.DEFAULT_MODALITE,
|
modalite=NotesFormModalite.DEFAULT_MODALITE,
|
||||||
|
|
|
@ -1,123 +1,123 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Comptage des absences
|
Comptage des absences
|
||||||
"""
|
"""
|
||||||
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
|
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_abs_views
|
from app.scodoc import sco_abs_views
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.views import absences
|
from app.views import absences
|
||||||
|
|
||||||
|
|
||||||
def test_abs_counts(test_client):
|
def test_abs_counts(test_client):
|
||||||
"""Comptage des absences"""
|
"""Comptage des absences"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
|
||||||
# --- Création d'étudiants
|
# --- Création d'étudiants
|
||||||
etud = G.create_etud(code_nip=None)
|
etud = G.create_etud(code_nip=None)
|
||||||
|
|
||||||
# --- Création d'une formation
|
# --- Création d'une formation
|
||||||
f = G.create_formation(acronyme="")
|
f = G.create_formation(acronyme="")
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
||||||
mod = G.create_module(
|
mod = G.create_module(
|
||||||
matiere_id=mat["matiere_id"],
|
matiere_id=mat["matiere_id"],
|
||||||
code="TSM1",
|
code="TSM1",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
ue_id=ue["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Mise place d'un semestre
|
# --- Mise place d'un semestre
|
||||||
sem = G.create_formsemestre(
|
sem = G.create_formsemestre(
|
||||||
formation_id=f["formation_id"],
|
formation_id=f["formation_id"],
|
||||||
semestre_id=1,
|
semestre_id=1,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
)
|
)
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Inscription des étudiants
|
# --- Inscription des étudiants
|
||||||
G.inscrit_etudiant(sem, etud)
|
G.inscrit_etudiant(sem, etud)
|
||||||
|
|
||||||
# --- Saisie absences
|
# --- Saisie absences
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
for debut, fin, demijournee in [
|
for debut, fin, demijournee in [
|
||||||
("01/01/2020", "31/01/2020", 2), # hors semestre
|
("01/01/2020", "31/01/2020", 2), # hors semestre
|
||||||
("15/01/2021", "15/01/2021", 1),
|
("15/01/2021", "15/01/2021", 1),
|
||||||
("18/01/2021", "18/01/2021", 0),
|
("18/01/2021", "18/01/2021", 0),
|
||||||
("19/01/2021", "19/01/2021", 2),
|
("19/01/2021", "19/01/2021", 2),
|
||||||
("22/01/2021", "22/01/2021", 1),
|
("22/01/2021", "22/01/2021", 1),
|
||||||
("30/06/2021", "30/06/2021", 2), # dernier jour
|
("30/06/2021", "30/06/2021", 2), # dernier jour
|
||||||
]:
|
]:
|
||||||
sco_abs_views.doSignaleAbsence(
|
sco_abs_views.doSignaleAbsence(
|
||||||
datedebut=debut,
|
datedebut=debut,
|
||||||
datefin=fin,
|
datefin=fin,
|
||||||
demijournee=demijournee,
|
demijournee=demijournee,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Justification de certaines absences
|
# --- Justification de certaines absences
|
||||||
|
|
||||||
for debut, fin, demijournee in [
|
for debut, fin, demijournee in [
|
||||||
("15/01/2021", "15/01/2021", 1),
|
("15/01/2021", "15/01/2021", 1),
|
||||||
("18/01/2021", "18/01/2021", 0),
|
("18/01/2021", "18/01/2021", 0),
|
||||||
("19/01/2021", "19/01/2021", 2),
|
("19/01/2021", "19/01/2021", 2),
|
||||||
]:
|
]:
|
||||||
sco_abs_views.doJustifAbsence(
|
sco_abs_views.doJustifAbsence(
|
||||||
datedebut=debut,
|
datedebut=debut,
|
||||||
datefin=fin,
|
datefin=fin,
|
||||||
demijournee=demijournee,
|
demijournee=demijournee,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Utilisation de get_abs_count() de sco_abs
|
# --- Utilisation de get_abs_count() de sco_abs
|
||||||
|
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
|
|
||||||
# --- Utilisation de sco_abs.count_abs()
|
# --- Utilisation de sco_abs.count_abs()
|
||||||
|
|
||||||
nb_abs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
|
nb_abs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
|
||||||
nb_absj2 = sco_abs.count_abs_just(
|
nb_absj2 = sco_abs.count_abs_just(
|
||||||
etudid=etudid, debut="2021-01-01", fin="2021-06-30"
|
etudid=etudid, debut="2021-01-01", fin="2021-06-30"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert nbabs == nb_abs2 == 7
|
assert nbabs == nb_abs2 == 7
|
||||||
assert nbabsjust == nb_absj2 == 4
|
assert nbabsjust == nb_absj2 == 4
|
||||||
|
|
||||||
# --- Nombre de justificatifs:
|
# --- Nombre de justificatifs:
|
||||||
justifs = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
justifs = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
||||||
assert len(justifs) == 4
|
assert len(justifs) == 4
|
||||||
|
|
||||||
# --- Suppression d'absence
|
# --- Suppression d'absence
|
||||||
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
|
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
|
||||||
|
|
||||||
# --- Vérification
|
# --- Vérification
|
||||||
justifs_2 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
justifs_2 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
||||||
assert len(justifs_2) == len(justifs)
|
assert len(justifs_2) == len(justifs)
|
||||||
new_nbabs, _ = sco_abs.get_abs_count(etudid, sem) # version cachée
|
new_nbabs, _ = sco_abs.get_abs_count(etudid, sem) # version cachée
|
||||||
new_nbabs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
|
new_nbabs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
|
||||||
|
|
||||||
assert new_nbabs == new_nbabs2
|
assert new_nbabs == new_nbabs2
|
||||||
assert new_nbabs == (nbabs - 2) # on a supprimé deux absences
|
assert new_nbabs == (nbabs - 2) # on a supprimé deux absences
|
||||||
|
|
||||||
# --- annulation absence sans supprimer le justificatif
|
# --- annulation absence sans supprimer le justificatif
|
||||||
sco_abs_views.AnnuleAbsencesDatesNoJust(etudid, ["2021-01-15"])
|
sco_abs_views.AnnuleAbsencesDatesNoJust(etudid, ["2021-01-15"])
|
||||||
nbabs_3, nbjust_3 = sco_abs.get_abs_count(etudid, sem)
|
nbabs_3, nbjust_3 = sco_abs.get_abs_count(etudid, sem)
|
||||||
assert nbabs_3 == new_nbabs
|
assert nbabs_3 == new_nbabs
|
||||||
justifs_3 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
justifs_3 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
|
||||||
assert len(justifs_3) == len(justifs_2)
|
assert len(justifs_3) == len(justifs_2)
|
||||||
# XXX à continuer
|
# XXX à continuer
|
|
@ -1,335 +1,339 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Créer et justifier des absences en utilisant le parametre demijournee
|
Créer et justifier des absences en utilisant le parametre demijournee
|
||||||
"""
|
"""
|
||||||
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
|
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_abs_views
|
from app.scodoc import sco_abs_views
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.views import absences
|
from app.views import absences
|
||||||
|
|
||||||
|
|
||||||
def test_abs_demijournee(test_client):
|
def test_abs_demijournee(test_client):
|
||||||
"""Opération élémentaires sur les absences, tests demi-journées
|
"""Opération élémentaires sur les absences, tests demi-journées
|
||||||
Travaille dans base TEST00 (defaut)
|
Travaille dans base TEST00 (defaut)
|
||||||
"""
|
"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
|
||||||
# --- Création d'étudiants
|
# --- Création d'étudiants
|
||||||
etud = G.create_etud(code_nip=None)
|
etud = G.create_etud(code_nip=None)
|
||||||
|
|
||||||
# --- Création d'une formation
|
# --- Création d'une formation
|
||||||
f = G.create_formation(acronyme="")
|
f = G.create_formation(acronyme="")
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
||||||
mod = G.create_module(
|
mod = G.create_module(
|
||||||
matiere_id=mat["matiere_id"],
|
matiere_id=mat["matiere_id"],
|
||||||
code="TSM1",
|
code="TSM1",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
ue_id=ue["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Mise place d'un semestre
|
# --- Mise place d'un semestre
|
||||||
sem = G.create_formsemestre(
|
sem = G.create_formsemestre(
|
||||||
formation_id=f["formation_id"],
|
formation_id=f["formation_id"],
|
||||||
semestre_id=1,
|
semestre_id=1,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
)
|
)
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Inscription des étudiants
|
# --- Inscription des étudiants
|
||||||
G.inscrit_etudiant(sem, etud)
|
G.inscrit_etudiant(sem, etud)
|
||||||
|
|
||||||
# --- Saisie absences
|
# --- Saisie absences
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
demijournee=2,
|
demijournee=2,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
demijournee=1,
|
demijournee=1,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
demijournee=0,
|
demijournee=0,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Justification de certaines absences
|
# --- Justification de certaines absences
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
demijournee=1,
|
demijournee=1,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
demijournee=2,
|
demijournee=2,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# NE JUSTIFIE QUE LE MATIN MALGRES LE PARAMETRE demijournee = 2
|
# NE JUSTIFIE QUE LE MATIN MALGRES LE PARAMETRE demijournee = 2
|
||||||
|
|
||||||
# --- Test
|
# --- Test
|
||||||
|
|
||||||
nbabs, nbabs_just = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabs_just = sco_abs.get_abs_count(etudid, sem)
|
||||||
assert (
|
assert (
|
||||||
nbabs == 4
|
nbabs == 4
|
||||||
) # l'étudiant a été absent le 15 journée compléte (2 abs : 1 matin, 1 apres midi) et le 18 (1 matin), et le 19 (1 apres midi).
|
) # l'étudiant a été absent le 15 journée compléte (2 abs : 1 matin, 1 apres midi) et le 18 (1 matin), et le 19 (1 apres midi).
|
||||||
assert nbabs_just == 2 # Justifie abs du matin + abs après midi
|
assert nbabs_just == 2 # Justifie abs du matin + abs après midi
|
||||||
|
|
||||||
|
|
||||||
def test_abs_basic(test_client):
|
def test_abs_basic(test_client):
|
||||||
"""creation de 10 étudiants, formation, semestre, ue, module, absences le matin, l'apres midi, la journée compléte
|
"""creation de 10 étudiants, formation, semestre, ue, module, absences le matin, l'apres midi, la journée compléte
|
||||||
et justification d'absences, supression d'absences, création d'une liste etat absences, creation d'un groupe afin
|
et justification d'absences, supression d'absences, création d'une liste etat absences, creation d'un groupe afin
|
||||||
de tester la fonction EtatAbsencesGroupes
|
de tester la fonction EtatAbsencesGroupes
|
||||||
|
|
||||||
Fonctions de l'API utilisé :
|
Fonctions de l'API utilisé :
|
||||||
- doSignaleAbsence
|
- doSignaleAbsence
|
||||||
- doAnnuleAbsence
|
- doAnnuleAbsence
|
||||||
- doJustifAbsence
|
- doJustifAbsence
|
||||||
- get_partition_groups
|
- get_partition_groups
|
||||||
- get_partitions_list
|
- get_partitions_list
|
||||||
- sco_abs.get_abs_count(etudid, sem)
|
- sco_abs.get_abs_count(etudid, sem)
|
||||||
- ListeAbsEtud
|
- ListeAbsEtud
|
||||||
- partition_create
|
- partition_create
|
||||||
- createGroup
|
- createGroup
|
||||||
- set_group
|
- set_group
|
||||||
- EtatAbsenceGr
|
- EtatAbsenceGr
|
||||||
- AddBilletAbsence
|
- AddBilletAbsence
|
||||||
- listeBilletsEtud
|
- listeBilletsEtud
|
||||||
"""
|
"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
|
||||||
# --- Création d'étudiants
|
# --- Création d'étudiants
|
||||||
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
||||||
|
|
||||||
# --- Création d'une formation
|
# --- Création d'une formation
|
||||||
f = G.create_formation(acronyme="")
|
f = G.create_formation(acronyme="")
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
||||||
mod = G.create_module(
|
mod = G.create_module(
|
||||||
matiere_id=mat["matiere_id"],
|
matiere_id=mat["matiere_id"],
|
||||||
code="TSM1",
|
code="TSM1",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
ue_id=ue["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Mise place d'un semestre
|
# --- Mise place d'un semestre
|
||||||
sem = G.create_formsemestre(
|
sem = G.create_formsemestre(
|
||||||
formation_id=f["formation_id"],
|
formation_id=f["formation_id"],
|
||||||
semestre_id=1,
|
semestre_id=1,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
)
|
)
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Inscription des étudiants
|
# --- Inscription des étudiants
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
G.inscrit_etudiant(sem, etud)
|
G.inscrit_etudiant(sem, etud)
|
||||||
|
|
||||||
# --- Création d'une évaluation
|
# --- Création d'une évaluation
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=mi["moduleimpl_id"],
|
moduleimpl_id=mi["moduleimpl_id"],
|
||||||
jour="22/01/2021",
|
jour="22/01/2021",
|
||||||
description="evaluation test",
|
description="evaluation test",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Saisie absences
|
# --- Saisie absences
|
||||||
etudid = etuds[0]["etudid"]
|
etudid = etuds[0]["etudid"]
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
demijournee=1,
|
demijournee=1,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
demijournee=0,
|
demijournee=0,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
demijournee=2,
|
demijournee=2,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
"22/01/2021",
|
"22/01/2021",
|
||||||
"22/01/2021",
|
"22/01/2021",
|
||||||
demijournee=1,
|
demijournee=1,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Justification de certaines absences
|
# --- Justification de certaines absences
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
"15/01/2021",
|
"15/01/2021",
|
||||||
demijournee=1,
|
demijournee=1,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
"18/01/2021",
|
"18/01/2021",
|
||||||
demijournee=0,
|
demijournee=0,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
"19/01/2021",
|
"19/01/2021",
|
||||||
demijournee=2,
|
demijournee=2,
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Test
|
# --- Test
|
||||||
|
|
||||||
b = sco_abs.is_work_saturday()
|
b = sco_abs.is_work_saturday()
|
||||||
assert b == 0 # samedi ne sont pas compris
|
assert b == 0 # samedi ne sont pas compris
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
# l'étudiant a été absent le 15 (apres midi) , (16 et 17 we),
|
# l'étudiant a été absent le 15 (apres midi) , (16 et 17 we),
|
||||||
# 18 (matin) et 19 janvier (matin et apres midi), et 22 (matin)
|
# 18 (matin) et 19 janvier (matin et apres midi), et 22 (matin)
|
||||||
assert nbabs == 5
|
assert nbabs == 5
|
||||||
# l'étudiant justifie ses abs du 15, 18 et 19
|
# l'étudiant justifie ses abs du 15, 18 et 19
|
||||||
assert nbabsjust == 4
|
assert nbabsjust == 4
|
||||||
|
|
||||||
# --- Suppression d'une absence et d'une justification
|
# --- Suppression d'une absence et d'une justification
|
||||||
|
|
||||||
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
|
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
assert nbabs == 3
|
assert nbabs == 3
|
||||||
assert nbabsjust == 2
|
assert nbabsjust == 2
|
||||||
|
|
||||||
# --- suppression d'une justification pas encore disponible à l'aide de python.
|
# --- suppression d'une justification pas encore disponible à l'aide de python.
|
||||||
|
|
||||||
# --- Création d'une liste d'abs
|
# --- Création d'une liste d'abs
|
||||||
|
|
||||||
liste_abs = sco_abs_views.ListeAbsEtud(
|
liste_abs = sco_abs_views.ListeAbsEtud(
|
||||||
etudid, format="json", absjust_only=1, sco_year="2020"
|
etudid, format="json", absjust_only=1, sco_year="2020"
|
||||||
)
|
).get_data(as_text=True)
|
||||||
liste_abs2 = sco_abs_views.ListeAbsEtud(etudid, format="json", sco_year="2020")
|
liste_abs2 = sco_abs_views.ListeAbsEtud(
|
||||||
|
etudid, format="json", sco_year="2020"
|
||||||
load_liste_abs = json.loads(liste_abs)
|
).get_data(as_text=True)
|
||||||
load_liste_abs2 = json.loads(liste_abs2)
|
|
||||||
|
load_liste_abs = json.loads(liste_abs)
|
||||||
assert len(load_liste_abs2) == 1
|
load_liste_abs2 = json.loads(liste_abs2)
|
||||||
assert len(load_liste_abs) == 2
|
|
||||||
assert load_liste_abs2[0]["ampm"] == 1
|
assert len(load_liste_abs2) == 1
|
||||||
assert load_liste_abs2[0]["datedmy"] == "22/01/2021"
|
assert len(load_liste_abs) == 2
|
||||||
assert load_liste_abs2[0]["exams"] == mod["code"]
|
assert load_liste_abs2[0]["ampm"] == 1
|
||||||
# absjust_only -> seulement les abs justifiés
|
assert load_liste_abs2[0]["datedmy"] == "22/01/2021"
|
||||||
|
assert load_liste_abs2[0]["exams"] == mod["code"]
|
||||||
# --- Création d'un groupe
|
# absjust_only -> seulement les abs justifiés
|
||||||
|
|
||||||
_ = sco_groups.partition_create(
|
# --- Création d'un groupe
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
partition_name="Eleve",
|
_ = sco_groups.partition_create(
|
||||||
)
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
li1 = sco_groups.get_partitions_list(sem["formsemestre_id"])
|
partition_name="Eleve",
|
||||||
_ = sco_groups.createGroup(li1[0]["partition_id"], "Groupe 1")
|
)
|
||||||
|
li1 = sco_groups.get_partitions_list(sem["formsemestre_id"])
|
||||||
# --- Affectation des élèves dans des groupes
|
_ = sco_groups.createGroup(li1[0]["partition_id"], "Groupe 1")
|
||||||
|
|
||||||
li_grp1 = sco_groups.get_partition_groups(li1[0])
|
# --- Affectation des élèves dans des groupes
|
||||||
for etud in etuds:
|
|
||||||
sco_groups.set_group(etud["etudid"], li_grp1[0]["group_id"])
|
li_grp1 = sco_groups.get_partition_groups(li1[0])
|
||||||
|
for etud in etuds:
|
||||||
# --- Test de EtatAbsencesGroupes
|
sco_groups.set_group(etud["etudid"], li_grp1[0]["group_id"])
|
||||||
|
|
||||||
grp1_abs = absences.EtatAbsencesGr(
|
# --- Test de EtatAbsencesGroupes
|
||||||
group_ids=[li_grp1[0]["group_id"]],
|
|
||||||
debut="01/01/2021",
|
grp1_abs = absences.EtatAbsencesGr(
|
||||||
fin="30/06/2021",
|
group_ids=[li_grp1[0]["group_id"]],
|
||||||
format="json",
|
debut="01/01/2021",
|
||||||
)
|
fin="30/06/2021",
|
||||||
# grp1_abs est une Response car on a appelé une vue (1er appel)
|
format="json",
|
||||||
load_grp1_abs = json.loads(grp1_abs.get_data().decode("utf-8"))
|
)
|
||||||
|
# grp1_abs est une Response car on a appelé une vue (1er appel)
|
||||||
assert len(load_grp1_abs) == 10
|
load_grp1_abs = json.loads(grp1_abs.get_data(as_text=True))
|
||||||
|
|
||||||
tab_id = [] # tab des id present dans load_grp1_abs
|
assert len(load_grp1_abs) == 10
|
||||||
for un_etud in load_grp1_abs:
|
|
||||||
tab_id.append(un_etud["etudid"])
|
tab_id = [] # tab des id present dans load_grp1_abs
|
||||||
|
for un_etud in load_grp1_abs:
|
||||||
for (
|
tab_id.append(un_etud["etudid"])
|
||||||
etud
|
|
||||||
) in (
|
for (
|
||||||
etuds
|
etud
|
||||||
): # verification si tous les etudiants sont present dans la liste du groupe d'absence
|
) in (
|
||||||
assert etud["etudid"] in tab_id
|
etuds
|
||||||
|
): # verification si tous les etudiants sont present dans la liste du groupe d'absence
|
||||||
for un_etud in load_grp1_abs:
|
assert etud["etudid"] in tab_id
|
||||||
if un_etud["etudid"] == etudid:
|
|
||||||
assert un_etud["nbabs"] == 3
|
for un_etud in load_grp1_abs:
|
||||||
assert un_etud["nbjustifs_noabs"] == 2
|
if un_etud["etudid"] == etudid:
|
||||||
assert un_etud["nbabsjust"] == 2
|
assert un_etud["nbabs"] == 3
|
||||||
assert un_etud["nbabsnonjust"] == 1
|
assert un_etud["nbjustifs_noabs"] == 2
|
||||||
assert un_etud["nomprenom"] == etuds[0]["nomprenom"]
|
assert un_etud["nbabsjust"] == 2
|
||||||
|
assert un_etud["nbabsnonjust"] == 1
|
||||||
# --- Création de billets
|
assert un_etud["nomprenom"] == etuds[0]["nomprenom"]
|
||||||
|
|
||||||
b1 = absences.AddBilletAbsence(
|
# --- Création de billets
|
||||||
begin="2021-01-22 00:00",
|
|
||||||
end="2021-01-22 23:59",
|
b1 = absences.AddBilletAbsence(
|
||||||
etudid=etudid,
|
begin="2021-01-22 00:00",
|
||||||
description="abs du 22",
|
end="2021-01-22 23:59",
|
||||||
justified=False,
|
etudid=etudid,
|
||||||
code_nip=etuds[0]["code_nip"],
|
description="abs du 22",
|
||||||
code_ine=etuds[0]["code_ine"],
|
justified=False,
|
||||||
)
|
code_nip=etuds[0]["code_nip"],
|
||||||
|
code_ine=etuds[0]["code_ine"],
|
||||||
b2 = absences.AddBilletAbsence(
|
)
|
||||||
begin="2021-01-15 00:00",
|
|
||||||
end="2021-01-15 23:59",
|
b2 = absences.AddBilletAbsence(
|
||||||
etudid=etudid,
|
begin="2021-01-15 00:00",
|
||||||
description="abs du 15",
|
end="2021-01-15 23:59",
|
||||||
code_nip=etuds[0]["code_nip"],
|
etudid=etudid,
|
||||||
code_ine=etuds[0]["code_ine"],
|
description="abs du 15",
|
||||||
)
|
code_nip=etuds[0]["code_nip"],
|
||||||
|
code_ine=etuds[0]["code_ine"],
|
||||||
li_bi = absences.listeBilletsEtud(etudid=etudid, format="json")
|
)
|
||||||
assert isinstance(li_bi, str)
|
|
||||||
load_li_bi = json.loads(li_bi)
|
li_bi = absences.listeBilletsEtud(etudid=etudid, format="json").get_data(
|
||||||
|
as_text=True
|
||||||
assert len(load_li_bi) == 2
|
)
|
||||||
assert load_li_bi[1]["description"] == "abs du 22"
|
assert isinstance(li_bi, str)
|
||||||
|
load_li_bi = json.loads(li_bi)
|
||||||
|
|
||||||
|
assert len(load_li_bi) == 2
|
||||||
|
assert load_li_bi[1]["description"] == "abs du 22"
|
||||||
|
|
|
@ -1,375 +1,379 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
""" Test creation/edition/import/export formations
|
""" Test creation/edition/import/export formations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
||||||
|
|
||||||
# Créer 2 formations, une test et une normale. Créer 2 semestres dans la formation normale et un
|
# Créer 2 formations, une test et une normale. Créer 2 semestres dans la formation normale et un
|
||||||
# dans la formation test, créer 2 semestres dans la formation normale (un test et un normal),
|
# dans la formation test, créer 2 semestres dans la formation normale (un test et un normal),
|
||||||
# 2 ue (un test et un normal), 2 modules (un test et un normal) et 2 matieres (test et normal).
|
# 2 ue (un test et un normal), 2 modules (un test et un normal) et 2 matieres (test et normal).
|
||||||
# Et dans la formations test, un semestre, un module, un ue et une matiere.
|
# Et dans la formations test, un semestre, un module, un ue et une matiere.
|
||||||
# Afficher la liste de tout ca puis supprimer les ue, mod, mat et sem test ainsi
|
# Afficher la liste de tout ca puis supprimer les ue, mod, mat et sem test ainsi
|
||||||
# que la formation test. Afficher la liste des UE, formations et modules restante.
|
# que la formation test. Afficher la liste des UE, formations et modules restante.
|
||||||
#
|
#
|
||||||
# Vérification :
|
# Vérification :
|
||||||
#
|
#
|
||||||
# - Les listes initiales comprennent bien tout les éléments créés avec les bon noms etc
|
# - Les listes initiales comprennent bien tout les éléments créés avec les bon noms etc
|
||||||
# - La supression s'est bien effectué au niveau de scodoc web et en python
|
# - La supression s'est bien effectué au niveau de scodoc web et en python
|
||||||
# - Vérifier que les fonctions listes font bien la mise à jour après supression
|
# - Vérifier que les fonctions listes font bien la mise à jour après supression
|
||||||
#
|
#
|
||||||
# Fonction de l'API utilisé :
|
# Fonction de l'API utilisé :
|
||||||
#
|
#
|
||||||
# - create_formation
|
# - create_formation
|
||||||
# - create_ue
|
# - create_ue
|
||||||
# - create_matiere
|
# - create_matiere
|
||||||
# - create_module
|
# - create_module
|
||||||
# - create_formsemestre
|
# - create_formsemestre
|
||||||
# - create_moduleimpl
|
# - create_moduleimpl
|
||||||
# - formation_list
|
# - formation_list
|
||||||
# - formation_export
|
# - formation_export
|
||||||
# - formsemestre_list
|
# - formsemestre_list
|
||||||
# - do_moduleimpl_list
|
# - do_moduleimpl_list
|
||||||
# - do_module_impl_with_module_list
|
# - do_module_impl_with_module_list
|
||||||
# - do_formsemestre_delete
|
# - do_formsemestre_delete
|
||||||
# - do_module_list
|
# - do_module_list
|
||||||
# - do_module_delete
|
# - do_module_delete
|
||||||
# - do_matiere_list
|
# - do_matiere_list
|
||||||
# - do_matiere_delete
|
# - do_matiere_delete
|
||||||
# - do_ue_list
|
# - do_ue_list
|
||||||
# - do_ue_delete
|
# - do_ue_delete
|
||||||
# - do_formation_delete
|
# - do_formation_delete
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
|
|
||||||
from app.scodoc import sco_edit_formation
|
from app.scodoc import sco_edit_formation
|
||||||
from app.scodoc import sco_edit_matiere
|
from app.scodoc import sco_edit_matiere
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre_edit
|
from app.scodoc import sco_formsemestre_edit
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.views import notes
|
from app.views import notes
|
||||||
|
|
||||||
|
|
||||||
def test_formations(test_client):
|
def test_formations(test_client):
|
||||||
"""Test création/édition/import/export formations"""
|
"""Test création/édition/import/export formations"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
|
||||||
# --- Création de formations
|
# --- Création de formations
|
||||||
|
|
||||||
f = G.create_formation(
|
f = G.create_formation(
|
||||||
acronyme="F1", titre="Formation 1", titre_officiel="Titre officiel 1"
|
acronyme="F1", titre="Formation 1", titre_officiel="Titre officiel 1"
|
||||||
)
|
)
|
||||||
|
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
||||||
mod = G.create_module(
|
mod = G.create_module(
|
||||||
matiere_id=mat["matiere_id"],
|
matiere_id=mat["matiere_id"],
|
||||||
code="TSM1",
|
code="TSM1",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
ue_id=ue["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
ue2 = G.create_ue(formation_id=f["formation_id"], acronyme="TST2", titre="ue test2")
|
ue2 = G.create_ue(formation_id=f["formation_id"], acronyme="TST2", titre="ue test2")
|
||||||
mat2 = G.create_matiere(ue_id=ue2["ue_id"], titre="matière test2")
|
mat2 = G.create_matiere(ue_id=ue2["ue_id"], titre="matière test2")
|
||||||
mod2 = G.create_module(
|
mod2 = G.create_module(
|
||||||
matiere_id=mat2["matiere_id"],
|
matiere_id=mat2["matiere_id"],
|
||||||
code="TSM2",
|
code="TSM2",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=ue2["ue_id"], # faiblesse de l'API
|
ue_id=ue2["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
uet = G.create_ue(formation_id=f["formation_id"], acronyme="TSTt", titre="ue testt")
|
uet = G.create_ue(formation_id=f["formation_id"], acronyme="TSTt", titre="ue testt")
|
||||||
matt = G.create_matiere(ue_id=uet["ue_id"], titre="matière testt")
|
matt = G.create_matiere(ue_id=uet["ue_id"], titre="matière testt")
|
||||||
modt = G.create_module(
|
modt = G.create_module(
|
||||||
matiere_id=matt["matiere_id"],
|
matiere_id=matt["matiere_id"],
|
||||||
code="TSMt",
|
code="TSMt",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=uet["ue_id"], # faiblesse de l'API
|
ue_id=uet["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
f2 = G.create_formation(acronyme="", titre="Formation test")
|
f2 = G.create_formation(acronyme="", titre="Formation test")
|
||||||
|
|
||||||
ue3 = G.create_ue(
|
ue3 = G.create_ue(
|
||||||
formation_id=f2["formation_id"], acronyme="TST3", titre="ue test3"
|
formation_id=f2["formation_id"], acronyme="TST3", titre="ue test3"
|
||||||
)
|
)
|
||||||
mat3 = G.create_matiere(ue_id=ue3["ue_id"], titre="matière test3")
|
mat3 = G.create_matiere(ue_id=ue3["ue_id"], titre="matière test3")
|
||||||
mod3 = G.create_module(
|
mod3 = G.create_module(
|
||||||
matiere_id=mat3["matiere_id"],
|
matiere_id=mat3["matiere_id"],
|
||||||
code="TSM3",
|
code="TSM3",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
titre="module test3",
|
titre="module test3",
|
||||||
ue_id=ue3["ue_id"], # faiblesse de l'API
|
ue_id=ue3["ue_id"], # faiblesse de l'API
|
||||||
formation_id=f2["formation_id"], # faiblesse de l'API
|
formation_id=f2["formation_id"], # faiblesse de l'API
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Création et implémentation des semestres
|
# --- Création et implémentation des semestres
|
||||||
|
|
||||||
sem1 = G.create_formsemestre(
|
sem1 = G.create_formsemestre(
|
||||||
formation_id=f["formation_id"],
|
formation_id=f["formation_id"],
|
||||||
semestre_id=1,
|
semestre_id=1,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
)
|
)
|
||||||
|
|
||||||
sem2 = G.create_formsemestre(
|
sem2 = G.create_formsemestre(
|
||||||
formation_id=f["formation_id"],
|
formation_id=f["formation_id"],
|
||||||
semestre_id=2,
|
semestre_id=2,
|
||||||
date_debut="01/09/2020",
|
date_debut="01/09/2020",
|
||||||
date_fin="31/12/2020",
|
date_fin="31/12/2020",
|
||||||
)
|
)
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
formsemestre_id=sem1["formsemestre_id"],
|
formsemestre_id=sem1["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
mi2 = G.create_moduleimpl(
|
mi2 = G.create_moduleimpl(
|
||||||
module_id=mod2["module_id"],
|
module_id=mod2["module_id"],
|
||||||
formsemestre_id=sem1["formsemestre_id"],
|
formsemestre_id=sem1["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
mit = G.create_moduleimpl(
|
mit = G.create_moduleimpl(
|
||||||
module_id=modt["module_id"],
|
module_id=modt["module_id"],
|
||||||
formsemestre_id=sem2["formsemestre_id"],
|
formsemestre_id=sem2["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
semt = G.create_formsemestre(
|
semt = G.create_formsemestre(
|
||||||
formation_id=f2["formation_id"],
|
formation_id=f2["formation_id"],
|
||||||
semestre_id=3,
|
semestre_id=3,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
)
|
)
|
||||||
|
|
||||||
mi3 = G.create_moduleimpl(
|
mi3 = G.create_moduleimpl(
|
||||||
module_id=mod3["module_id"],
|
module_id=mod3["module_id"],
|
||||||
formsemestre_id=semt["formsemestre_id"],
|
formsemestre_id=semt["formsemestre_id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Afficher la liste des formations
|
# --- Afficher la liste des formations
|
||||||
|
|
||||||
lif = notes.formation_list(format="json", formation_id=f["formation_id"])
|
lif = notes.formation_list(format="json", formation_id=f["formation_id"])
|
||||||
# lif est une Response car on a appelé une vue (1er appel)
|
# lif est une Response car on a appelé une vue (1er appel)
|
||||||
assert isinstance(lif, flask.Response)
|
assert isinstance(lif, flask.Response)
|
||||||
load_lif = json.loads(lif.get_data().decode("utf-8"))
|
load_lif = json.loads(lif.get_data().decode("utf-8"))
|
||||||
assert len(load_lif) == 1
|
assert len(load_lif) == 1
|
||||||
assert load_lif[0]["acronyme"] == f["acronyme"]
|
assert load_lif[0]["acronyme"] == f["acronyme"]
|
||||||
assert load_lif[0]["titre_officiel"] == f["titre_officiel"]
|
assert load_lif[0]["titre_officiel"] == f["titre_officiel"]
|
||||||
assert load_lif[0]["formation_id"] == f["formation_id"]
|
assert load_lif[0]["formation_id"] == f["formation_id"]
|
||||||
assert load_lif[0]["titre"] == f["titre"]
|
assert load_lif[0]["titre"] == f["titre"]
|
||||||
|
|
||||||
lif2 = notes.formation_list(format="json")
|
lif2 = notes.formation_list(format="json").get_data(as_text=True)
|
||||||
# lif2 est un chaine
|
# lif2 est un chaine
|
||||||
assert isinstance(lif2, str)
|
assert isinstance(lif2, str)
|
||||||
load_lif2 = json.loads(lif2)
|
load_lif2 = json.loads(lif2)
|
||||||
assert len(load_lif2) == 2
|
assert len(load_lif2) == 2
|
||||||
assert load_lif2[0] == load_lif[0]
|
assert load_lif2[0] == load_lif[0]
|
||||||
assert load_lif2[1]["titre"] == f2["titre"]
|
assert load_lif2[1]["titre"] == f2["titre"]
|
||||||
|
|
||||||
# --- Export de formation_id
|
# --- Export de formation_id
|
||||||
|
|
||||||
exp = sco_formations.formation_export(formation_id=f["formation_id"], format="json")
|
exp = sco_formations.formation_export(
|
||||||
assert isinstance(exp, str)
|
formation_id=f["formation_id"], format="json"
|
||||||
load_exp = json.loads(exp)
|
).get_data(as_text=True)
|
||||||
|
assert isinstance(exp, str)
|
||||||
assert load_exp["acronyme"] == "F1"
|
load_exp = json.loads(exp)
|
||||||
assert load_exp["titre_officiel"] == "Titre officiel 1"
|
|
||||||
assert load_exp["titre"] == "Formation 1"
|
assert load_exp["acronyme"] == "F1"
|
||||||
assert load_exp["formation_code"] == f["formation_code"]
|
assert load_exp["titre_officiel"] == "Titre officiel 1"
|
||||||
assert len(load_exp["ue"]) == 3
|
assert load_exp["titre"] == "Formation 1"
|
||||||
assert load_exp["ue"][0]["acronyme"] == "TST1"
|
assert load_exp["formation_code"] == f["formation_code"]
|
||||||
assert load_exp["ue"][0]["titre"] == "ue test"
|
assert len(load_exp["ue"]) == 3
|
||||||
assert load_exp["formation_id"] == f["formation_id"]
|
assert load_exp["ue"][0]["acronyme"] == "TST1"
|
||||||
assert load_exp["formation_code"] == f["formation_code"]
|
assert load_exp["ue"][0]["titre"] == "ue test"
|
||||||
|
assert load_exp["formation_id"] == f["formation_id"]
|
||||||
# --- Liste des semestres
|
assert load_exp["formation_code"] == f["formation_code"]
|
||||||
|
|
||||||
li_sem1 = notes.formsemestre_list(
|
# --- Liste des semestres
|
||||||
formsemestre_id=sem1["formsemestre_id"], format="json"
|
|
||||||
)
|
li_sem1 = notes.formsemestre_list(
|
||||||
assert isinstance(li_sem1, str)
|
formsemestre_id=sem1["formsemestre_id"], format="json"
|
||||||
load_li_sem1 = json.loads(li_sem1) # uniquement le semestre 1 dans la liste
|
).get_data(as_text=True)
|
||||||
|
assert isinstance(li_sem1, str)
|
||||||
assert len(load_li_sem1) == 1
|
load_li_sem1 = json.loads(li_sem1) # uniquement le semestre 1 dans la liste
|
||||||
assert load_li_sem1[0]["date_fin"] == sem1["date_fin"]
|
|
||||||
assert load_li_sem1[0]["semestre_id"] == sem1["semestre_id"]
|
assert len(load_li_sem1) == 1
|
||||||
assert load_li_sem1[0]["formation_id"] == sem1["formation_id"]
|
assert load_li_sem1[0]["date_fin"] == sem1["date_fin"]
|
||||||
|
assert load_li_sem1[0]["semestre_id"] == sem1["semestre_id"]
|
||||||
li_semf = notes.formsemestre_list(
|
assert load_li_sem1[0]["formation_id"] == sem1["formation_id"]
|
||||||
formation_id=f["formation_id"],
|
|
||||||
format="json",
|
li_semf = notes.formsemestre_list(
|
||||||
)
|
formation_id=f["formation_id"],
|
||||||
assert isinstance(li_semf, str)
|
format="json",
|
||||||
load_li_semf = json.loads(li_semf)
|
).get_data(as_text=True)
|
||||||
|
assert isinstance(li_semf, str)
|
||||||
assert load_li_sem1[0] in load_li_semf
|
load_li_semf = json.loads(li_semf)
|
||||||
assert len(load_li_semf) == 2
|
|
||||||
assert load_li_semf[1]["semestre_id"] == sem2["semestre_id"]
|
assert load_li_sem1[0] in load_li_semf
|
||||||
|
assert len(load_li_semf) == 2
|
||||||
li_sem = notes.formsemestre_list(format="json")
|
assert load_li_semf[1]["semestre_id"] == sem2["semestre_id"]
|
||||||
load_li_sem = json.loads(li_sem)
|
|
||||||
|
li_sem = notes.formsemestre_list(format="json").get_data(as_text=True)
|
||||||
assert len(load_li_sem) == 3
|
load_li_sem = json.loads(li_sem)
|
||||||
assert load_li_semf[0] and load_li_semf[1] in load_li_sem
|
|
||||||
assert load_li_sem[0]["semestre_id"] == semt["semestre_id"]
|
assert len(load_li_sem) == 3
|
||||||
|
assert load_li_semf[0] and load_li_semf[1] in load_li_sem
|
||||||
# --- Liste des modules
|
assert load_li_sem[0]["semestre_id"] == semt["semestre_id"]
|
||||||
|
|
||||||
lim_sem1 = sco_moduleimpl.do_moduleimpl_list(
|
# --- Liste des modules
|
||||||
formsemestre_id=sem1["formsemestre_id"]
|
|
||||||
)
|
lim_sem1 = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
formsemestre_id=sem1["formsemestre_id"]
|
||||||
assert len(lim_sem1) == 2
|
)
|
||||||
assert mod["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
|
||||||
assert mod2["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
assert len(lim_sem1) == 2
|
||||||
|
assert mod["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
||||||
lim_modid = sco_moduleimpl.do_moduleimpl_list(module_id=mod["module_id"])
|
assert mod2["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
||||||
|
|
||||||
assert len(lim_modid) == 1
|
lim_modid = sco_moduleimpl.do_moduleimpl_list(module_id=mod["module_id"])
|
||||||
|
|
||||||
lim_modimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
assert len(lim_modid) == 1
|
||||||
moduleimpl_id=mi["moduleimpl_id"]
|
|
||||||
)
|
lim_modimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
||||||
# print(lim_modimpl_id)
|
moduleimpl_id=mi["moduleimpl_id"]
|
||||||
|
)
|
||||||
# ---- Test de do_moduleimpl_withmodule_list
|
# print(lim_modimpl_id)
|
||||||
|
|
||||||
assert lim_modid == lim_modimpl_id # doit etre le meme resultat
|
# ---- Test de do_moduleimpl_withmodule_list
|
||||||
|
|
||||||
liimp_sem1 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
assert lim_modid == lim_modimpl_id # doit etre le meme resultat
|
||||||
formsemestre_id=sem1["formsemestre_id"]
|
|
||||||
)
|
liimp_sem1 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
formsemestre_id=sem1["formsemestre_id"]
|
||||||
assert len(liimp_sem1) == 2
|
)
|
||||||
assert mod["module_id"] in (liimp_sem1[0]["module_id"], liimp_sem1[1]["module_id"])
|
|
||||||
assert mod2["module_id"] in (
|
assert len(liimp_sem1) == 2
|
||||||
liimp_sem1[0]["module_id"],
|
assert mod["module_id"] in (liimp_sem1[0]["module_id"], liimp_sem1[1]["module_id"])
|
||||||
liimp_sem1[1]["module_id"],
|
assert mod2["module_id"] in (
|
||||||
)
|
liimp_sem1[0]["module_id"],
|
||||||
liimp_sem2 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
liimp_sem1[1]["module_id"],
|
||||||
formsemestre_id=sem2["formsemestre_id"]
|
)
|
||||||
)
|
liimp_sem2 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
assert modt["module_id"] == liimp_sem2[0]["module_id"]
|
formsemestre_id=sem2["formsemestre_id"]
|
||||||
liimp_modid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
)
|
||||||
module_id=mod["module_id"]
|
assert modt["module_id"] == liimp_sem2[0]["module_id"]
|
||||||
)
|
liimp_modid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
assert len(liimp_modid) == 1
|
module_id=mod["module_id"]
|
||||||
|
)
|
||||||
liimp_modimplid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
assert len(liimp_modid) == 1
|
||||||
moduleimpl_id=mi["moduleimpl_id"]
|
|
||||||
)
|
liimp_modimplid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
moduleimpl_id=mi["moduleimpl_id"]
|
||||||
assert liimp_modid == liimp_modimplid
|
)
|
||||||
|
|
||||||
# --- Suppression du module, matiere et ue test du semestre 2
|
assert liimp_modid == liimp_modimplid
|
||||||
|
|
||||||
# on doit d'abbord supprimer le semestre
|
# --- Suppression du module, matiere et ue test du semestre 2
|
||||||
|
|
||||||
# sco_formsemestre_edit.formsemestre_delete( formsemestre_id=sem2["formsemestre_id"], REQUEST=REQUEST)
|
# on doit d'abbord supprimer le semestre
|
||||||
# sco_formsemestre_edit.formsemestre_createwithmodules( formsemestre_id=sem2["formsemestre_id"], REQUEST=REQUEST)
|
|
||||||
|
# sco_formsemestre_edit.formsemestre_delete( formsemestre_id=sem2["formsemestre_id"], REQUEST=REQUEST)
|
||||||
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
# sco_formsemestre_edit.formsemestre_createwithmodules( formsemestre_id=sem2["formsemestre_id"], REQUEST=REQUEST)
|
||||||
|
|
||||||
sco_formsemestre_edit.do_formsemestre_delete(
|
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
||||||
formsemestre_id=sem2["formsemestre_id"]
|
|
||||||
)
|
sco_formsemestre_edit.do_formsemestre_delete(
|
||||||
|
formsemestre_id=sem2["formsemestre_id"]
|
||||||
# sco_edit_module.module_delete( module_id=modt["module_id"], REQUEST=REQUEST)
|
)
|
||||||
# sco_edit_matiere.matiere_delete( matiere_id=matt["matiere_id"], REQUEST=REQUEST)
|
|
||||||
# sco_edit_ue.ue_delete( ue_id=uet["ue_id"], REQUEST=REQUEST)
|
# sco_edit_module.module_delete( module_id=modt["module_id"], REQUEST=REQUEST)
|
||||||
|
# sco_edit_matiere.matiere_delete( matiere_id=matt["matiere_id"], REQUEST=REQUEST)
|
||||||
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
# sco_edit_ue.ue_delete( ue_id=uet["ue_id"], REQUEST=REQUEST)
|
||||||
|
|
||||||
li_module = sco_edit_module.do_module_list()
|
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
||||||
assert len(li_module) == 4
|
|
||||||
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre
|
li_module = sco_edit_module.do_module_list()
|
||||||
# sco_formsemestre_edit.formsemestre_delete_moduleimpls( formsemestre_id=sem2["formsemestre_id"], module_ids_to_del=[modt["module_id"]])
|
assert len(li_module) == 4
|
||||||
# deuxieme methode de supression d'un module
|
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre
|
||||||
li_module2 = sco_edit_module.do_module_list()
|
# sco_formsemestre_edit.formsemestre_delete_moduleimpls( formsemestre_id=sem2["formsemestre_id"], module_ids_to_del=[modt["module_id"]])
|
||||||
|
# deuxieme methode de supression d'un module
|
||||||
assert len(li_module2) == 3 # verification de la suppression du module
|
li_module2 = sco_edit_module.do_module_list()
|
||||||
|
|
||||||
lim_sem2 = sco_moduleimpl.do_moduleimpl_list(
|
assert len(li_module2) == 3 # verification de la suppression du module
|
||||||
formsemestre_id=sem2["formsemestre_id"]
|
|
||||||
)
|
lim_sem2 = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
formsemestre_id=sem2["formsemestre_id"]
|
||||||
assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup
|
)
|
||||||
|
|
||||||
li_mat = sco_edit_matiere.do_matiere_list()
|
assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup
|
||||||
assert len(li_mat) == 4
|
|
||||||
sco_edit_matiere.do_matiere_delete(oid=matt["matiere_id"]) # on supprime la matiere
|
li_mat = sco_edit_matiere.do_matiere_list()
|
||||||
li_mat2 = sco_edit_matiere.do_matiere_list()
|
assert len(li_mat) == 4
|
||||||
assert len(li_mat2) == 3 # verification de la suppression de la matiere
|
sco_edit_matiere.do_matiere_delete(oid=matt["matiere_id"]) # on supprime la matiere
|
||||||
|
li_mat2 = sco_edit_matiere.do_matiere_list()
|
||||||
li_ue = sco_edit_ue.do_ue_list()
|
assert len(li_mat2) == 3 # verification de la suppression de la matiere
|
||||||
assert len(li_ue) == 4
|
|
||||||
sco_edit_ue.ue_delete(ue_id=uet["ue_id"], dialog_confirmed=True)
|
li_ue = sco_edit_ue.do_ue_list()
|
||||||
li_ue2 = sco_edit_ue.do_ue_list()
|
assert len(li_ue) == 4
|
||||||
assert len(li_ue2) == 3 # verification de la suppression de l'UE
|
sco_edit_ue.ue_delete(ue_id=uet["ue_id"], dialog_confirmed=True)
|
||||||
|
li_ue2 = sco_edit_ue.do_ue_list()
|
||||||
# --- Suppression d'une formation
|
assert len(li_ue2) == 3 # verification de la suppression de l'UE
|
||||||
# Il faut d'abbord supprimer le semestre aussi.
|
|
||||||
sco_formsemestre_edit.do_formsemestre_delete(
|
# --- Suppression d'une formation
|
||||||
formsemestre_id=semt["formsemestre_id"]
|
# Il faut d'abbord supprimer le semestre aussi.
|
||||||
)
|
sco_formsemestre_edit.do_formsemestre_delete(
|
||||||
|
formsemestre_id=semt["formsemestre_id"]
|
||||||
sco_edit_formation.do_formation_delete(oid=f2["formation_id"])
|
)
|
||||||
lif3 = notes.formation_list(format="json")
|
|
||||||
assert isinstance(lif3, str)
|
sco_edit_formation.do_formation_delete(oid=f2["formation_id"])
|
||||||
load_lif3 = json.loads(lif3)
|
lif3 = notes.formation_list(format="json").get_data(as_text=True)
|
||||||
assert len(load_lif3) == 1
|
assert isinstance(lif3, str)
|
||||||
|
load_lif3 = json.loads(lif3)
|
||||||
|
assert len(load_lif3) == 1
|
||||||
def test_import_formation(test_client):
|
|
||||||
"""Test import/export formations"""
|
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
def test_import_formation(test_client):
|
||||||
# Lecture fichier XML local:
|
"""Test import/export formations"""
|
||||||
with open("tests/unit/formation-exemple-1.xml") as f:
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
doc = f.read()
|
# Lecture fichier XML local:
|
||||||
|
with open("tests/unit/formation-exemple-1.xml") as f:
|
||||||
# --- Création de la formation
|
doc = f.read()
|
||||||
f = sco_formations.formation_import_xml(doc)
|
|
||||||
assert len(f) == 3 # 3-uple
|
# --- Création de la formation
|
||||||
formation_id = f[0]
|
f = sco_formations.formation_import_xml(doc)
|
||||||
# --- Mise en place de 4 semestres
|
assert len(f) == 3 # 3-uple
|
||||||
sems = [
|
formation_id = f[0]
|
||||||
G.create_formsemestre(
|
# --- Mise en place de 4 semestres
|
||||||
formation_id=formation_id,
|
sems = [
|
||||||
semestre_id=x[0],
|
G.create_formsemestre(
|
||||||
date_debut=x[1],
|
formation_id=formation_id,
|
||||||
date_fin=x[2],
|
semestre_id=x[0],
|
||||||
)
|
date_debut=x[1],
|
||||||
for x in (
|
date_fin=x[2],
|
||||||
(1, "05/09/2019", "05/01/2020"),
|
)
|
||||||
(2, "06/01/2020", "30/06/2020"),
|
for x in (
|
||||||
(3, "01/09/2020", "05/01/2021"),
|
(1, "05/09/2019", "05/01/2020"),
|
||||||
(4, "06/01/2021", "30/06/2021"),
|
(2, "06/01/2020", "30/06/2020"),
|
||||||
)
|
(3, "01/09/2020", "05/01/2021"),
|
||||||
]
|
(4, "06/01/2021", "30/06/2021"),
|
||||||
# et les modules
|
)
|
||||||
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
]
|
||||||
for mod in modules:
|
# et les modules
|
||||||
mi = G.create_moduleimpl(
|
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
||||||
module_id=mod["module_id"],
|
for mod in modules:
|
||||||
formsemestre_id=sems[mod["semestre_id"] - 1]["formsemestre_id"],
|
mi = G.create_moduleimpl(
|
||||||
)
|
module_id=mod["module_id"],
|
||||||
assert mi["ens"] == []
|
formsemestre_id=sems[mod["semestre_id"] - 1]["formsemestre_id"],
|
||||||
assert mi["module_id"] == mod["module_id"]
|
)
|
||||||
|
assert mi["ens"] == []
|
||||||
# --- Export formation en XML
|
assert mi["module_id"] == mod["module_id"]
|
||||||
doc1 = sco_formations.formation_export(formation_id, format="xml")
|
|
||||||
assert isinstance(doc1, str)
|
# --- Export formation en XML
|
||||||
|
doc1 = sco_formations.formation_export(formation_id, format="xml").get_data(
|
||||||
|
as_text=True
|
||||||
|
)
|
||||||
|
assert isinstance(doc1, str)
|
||||||
|
|
|
@ -6,3 +6,4 @@
|
||||||
|
|
||||||
from tools.import_scodoc7_user_db import import_scodoc7_user_db
|
from tools.import_scodoc7_user_db import import_scodoc7_user_db
|
||||||
from tools.import_scodoc7_dept import import_scodoc7_dept
|
from tools.import_scodoc7_dept import import_scodoc7_dept
|
||||||
|
from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archive
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/opt/zope213/bin/python
|
#!/opt/scodoc/venv/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
|
|
||||||
|
@ -68,42 +68,51 @@ anonymize_null = "NULL"
|
||||||
ANONYMIZED_FIELDS = {
|
ANONYMIZED_FIELDS = {
|
||||||
"identite.nom": anonymize_name,
|
"identite.nom": anonymize_name,
|
||||||
"identite.prenom": anonymize_name,
|
"identite.prenom": anonymize_name,
|
||||||
|
"identite.nom_usuel": anonymize_null,
|
||||||
|
"identite.civilite": "'X'",
|
||||||
"identite.date_naissance": anonymize_date,
|
"identite.date_naissance": anonymize_date,
|
||||||
"identite.lieu_naissance": anonymize_question_str,
|
"identite.lieu_naissance": anonymize_question_str,
|
||||||
|
"identite.dept_naissance": anonymize_question_str,
|
||||||
"identite.nationalite": anonymize_question_str,
|
"identite.nationalite": anonymize_question_str,
|
||||||
"identite.foto": anonymize_null,
|
"identite.statut": anonymize_null,
|
||||||
|
"identite.boursier": anonymize_null,
|
||||||
|
"identite.photo_filename": anonymize_null,
|
||||||
"identite.code_nip": anonymize_null,
|
"identite.code_nip": anonymize_null,
|
||||||
"identite.code_ine": anonymize_null,
|
"identite.code_ine": anonymize_null,
|
||||||
"identite.nom_usuel": anonymize_null,
|
"identite.scodoc7_id": anonymize_null,
|
||||||
"adresse.email": "'ano@nyme.fr'",
|
"adresse.email": "'ano@nyme.fr'",
|
||||||
"adresse.emailperso": anonymize_null,
|
"adresse.emailperso": anonymize_null,
|
||||||
"adresse.domicile": anonymize_null,
|
"adresse.domicile": anonymize_null,
|
||||||
|
"adresse.codepostaldomicile": anonymize_null,
|
||||||
|
"adresse.villedomicile": anonymize_null,
|
||||||
|
"adresse.paysdomicile": anonymize_null,
|
||||||
"adresse.telephone": anonymize_null,
|
"adresse.telephone": anonymize_null,
|
||||||
"adresse.telephonemobile": anonymize_null,
|
"adresse.telephonemobile": anonymize_null,
|
||||||
"adresse.fax": anonymize_null,
|
"adresse.fax": anonymize_null,
|
||||||
|
"admissions.nomlycee": anonymize_name,
|
||||||
"billet_absence.description": anonymize_null,
|
"billet_absence.description": anonymize_null,
|
||||||
"etud_annotations.comment": anonymize_name,
|
"etud_annotations.comment": anonymize_name,
|
||||||
"entreprises.nom": anonymize_name,
|
# "entreprises.nom": anonymize_name,
|
||||||
"entreprises.adresse": anonymize_null,
|
# "entreprises.adresse": anonymize_null,
|
||||||
"entreprises.ville": anonymize_null,
|
# "entreprises.ville": anonymize_null,
|
||||||
"entreprises.codepostal": anonymize_null,
|
# "entreprises.codepostal": anonymize_null,
|
||||||
"entreprises.pays": anonymize_null,
|
# "entreprises.pays": anonymize_null,
|
||||||
"entreprises.contact_origine": anonymize_null,
|
# "entreprises.contact_origine": anonymize_null,
|
||||||
"entreprises.secteur": anonymize_null,
|
# "entreprises.secteur": anonymize_null,
|
||||||
"entreprises.note": anonymize_null,
|
# "entreprises.note": anonymize_null,
|
||||||
"entreprises.privee": anonymize_null,
|
# "entreprises.privee": anonymize_null,
|
||||||
"entreprises.localisation": anonymize_null,
|
# "entreprises.localisation": anonymize_null,
|
||||||
"entreprise_correspondant.nom": anonymize_name,
|
# "entreprise_correspondant.nom": anonymize_name,
|
||||||
"entreprise_correspondant.prenom": anonymize_name,
|
# "entreprise_correspondant.prenom": anonymize_name,
|
||||||
"entreprise_correspondant.phone1": anonymize_null,
|
# "entreprise_correspondant.phone1": anonymize_null,
|
||||||
"entreprise_correspondant.phone2": anonymize_null,
|
# "entreprise_correspondant.phone2": anonymize_null,
|
||||||
"entreprise_correspondant.mobile": anonymize_null,
|
# "entreprise_correspondant.mobile": anonymize_null,
|
||||||
"entreprise_correspondant.mail1": anonymize_null,
|
# "entreprise_correspondant.mail1": anonymize_null,
|
||||||
"entreprise_correspondant.mail2": anonymize_null,
|
# "entreprise_correspondant.mail2": anonymize_null,
|
||||||
"entreprise_correspondant.note": anonymize_null,
|
# "entreprise_correspondant.note": anonymize_null,
|
||||||
"entreprise_correspondant.fax": anonymize_null,
|
# "entreprise_correspondant.fax": anonymize_null,
|
||||||
"entreprise_contact.description": anonymize_null,
|
# "entreprise_contact.description": anonymize_null,
|
||||||
"entreprise_contact.enseignant": anonymize_null,
|
# "entreprise_contact.enseignant": anonymize_null,
|
||||||
"notes_appreciations.comment": anonymize_name,
|
"notes_appreciations.comment": anonymize_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user