diff --git a/README.md b/README.md index 9e79af1e..b2955bb9 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ de votre installation ScoDoc 7 pour passer à ScoDoc 8 (*ne pas utiliser en prod su scodoc # si besoin cd /opt/scodoc source venv/bin/activate - flask sco-create-dept DEPT + flask create-dept DEPT où `DEPT` est le nom du département (un acronyme en majuscule, comme "RT", "GEA", ...). @@ -181,7 +181,7 @@ où `DEPT` est le nom du département (un acronyme en majuscule, comme "RT", "GE su scodoc # si besoin cd /opt/scodoc source venv/bin/activate - flask sco-delete-dept DEPT + flask delete-dept DEPT ## Lancement serveur (développement, sur VM Linux) diff --git a/app/auth/models.py b/app/auth/models.py index 758a836d..84b802d1 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -194,7 +194,7 @@ class User(UserMixin, db.Model): return user # Permissions management: - def has_permission(self, perm, dept=False): + def has_permission(self, perm: int, dept=False): """Check if user has permission `perm` in given `dept`. Similar to Zope ScoDoc7 `has_permission`` @@ -382,7 +382,7 @@ class UserRole(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id")) role_id = db.Column(db.Integer, db.ForeignKey("role.id")) - dept = db.Column(db.String(64)) + dept = db.Column(db.String(64)) # dept acronym user = db.relationship( User, backref=db.backref("user_roles", cascade="all, delete-orphan") ) diff --git a/app/auth/routes.py b/app/auth/routes.py index 410c5f43..b4b98a4e 100644 --- a/app/auth/routes.py +++ b/app/auth/routes.py @@ -34,7 +34,7 @@ def login(): if form.validate_on_submit(): user = User.query.filter_by(user_name=form.user_name.data).first() if user is None or not user.check_password(form.password.data): - flash(_("Invalid user_name or password")) + flash(_("Invalid user name or password")) return redirect(url_for("auth.login")) login_user(user, remember=form.remember_me.data) next_page = request.args.get("next") diff --git a/app/scodoc/VERSION.py b/app/scodoc/VERSION.py index bd1ed9d9..4bbb7929 100644 --- a/app/scodoc/VERSION.py +++ b/app/scodoc/VERSION.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "8.0.1" +SCOVERSION = "8.1" SCONAME = "ScoDoc" diff --git a/app/scodoc/sco_abs.py b/app/scodoc/sco_abs.py index 3d9cac17..567a1c40 100644 --- a/app/scodoc/sco_abs.py +++ b/app/scodoc/sco_abs.py @@ -37,7 +37,6 @@ import datetime import calendar import cgi -from scodoc_manager import sco_mgr from app.scodoc import notesdb as ndb from app.scodoc.notes_log import log from app.scodoc.scolog import logdb diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py index 5847ba51..ba08ff8e 100644 --- a/app/scodoc/sco_find_etud.py +++ b/app/scodoc/sco_find_etud.py @@ -31,8 +31,8 @@ import flask from flask import url_for, g from flask_login import current_user -from scodoc_manager import sco_mgr import app +from app.models import Departement import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc.gen_tables import GenTable @@ -270,12 +270,12 @@ def search_etud_in_accessible_depts(expnom=None, code_nip=None): """ result = [] accessible_depts = [] - depts = sco_mgr.get_dept_ids() + depts = Departement.query.filter_by(visible=True).all() for dept in depts: - if current_user.has_permission(Permission.ScoView, dept=dept): + if current_user.has_permission(Permission.ScoView, dept=dept.acronym): if expnom or code_nip: - accessible_depts.append(dept) - app.set_sco_dept(dept) + accessible_depts.append(dept.acronym) + app.set_sco_dept(dept.acronym) etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip) else: etuds = [] diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py index af6f77d2..f09a374f 100644 --- a/app/scodoc/sco_formsemestre.py +++ b/app/scodoc/sco_formsemestre.py @@ -30,7 +30,8 @@ import time from operator import itemgetter -from scodoc_manager import sco_mgr +import app +from app.models import Departement from app.scodoc import sco_codes_parcours from app.scodoc import sco_cache from app.scodoc import sco_formations @@ -474,16 +475,23 @@ def sem_est_courant(context, sem): return (debut <= now) and (now <= fin) -def scodoc_get_all_unlocked_sems(context): - """Liste de tous les semestres non verrouillés de tous les départements""" - depts = sco_mgr.get_dept_ids() +def scodoc_get_all_unlocked_sems(): + """Liste de tous les semestres non verrouillés de _tous_ les départements + (utilisé pour rapports d'activités) + """ + cur_dept = g.scodoc_dept + depts = Departement.query.filter_by(visible=True).all() semdepts = [] - for dept in depts: - semdepts += [ - (sem, dept.Scolarite.Notes) - for sem in do_formsemestre_list(dept.Scolarite.Notes) - if sem["etat"] - ] + try: + for dept in depts: + app.set_sco_dept(dept.acronym) + semdepts += [ + (sem, dept) + for sem in do_formsemestre_list(dept.Scolarite.Notes) + if sem["etat"] + ] + finally: + app.set_sco_dept(cur_dept) return semdepts diff --git a/app/scodoc/sco_lycee.py b/app/scodoc/sco_lycee.py index 60e87dbd..14713021 100644 --- a/app/scodoc/sco_lycee.py +++ b/app/scodoc/sco_lycee.py @@ -33,6 +33,7 @@ from operator import itemgetter from flask import url_for, g +import app import app.scodoc.sco_utils as scu from app.scodoc import html_sco_header from app.scodoc import sco_formsemestre @@ -64,11 +65,18 @@ def formsemestre_table_etuds_lycees( def scodoc_table_etuds_lycees(context, format="html", REQUEST=None): - """Table avec _tous_ les étudiants des semestres non verrouillés de _tous_ les départements.""" - semdepts = sco_formsemestre.scodoc_get_all_unlocked_sems(context) + """Table avec _tous_ les étudiants des semestres non verrouillés + de _tous_ les départements. + """ + cur_dept = g.scodoc_dept + semdepts = sco_formsemestre.scodoc_get_all_unlocked_sems() etuds = [] - for (sem, deptcontext) in semdepts: - etuds += sco_report.tsp_etud_list(deptcontext, sem["formsemestre_id"])[0] + try: + for (sem, dept) in semdepts: + app.set_sco_dept(dept.acronym) + etuds += sco_report.tsp_etud_list(context, sem["formsemestre_id"])[0] + finally: + app.set_sco_dept(cur_dept) tab, etuds_by_lycee = _table_etuds_lycees( context, diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 963202da..deb258bf 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -54,8 +54,6 @@ from PIL import Image as PILImage from flask import g, url_for, request -from scodoc_manager import sco_mgr - from config import Config from app.scodoc.notes_log import log diff --git a/app/templates/scodoc.html b/app/templates/scodoc.html index 8325544f..c5fe5c81 100644 --- a/app/templates/scodoc.html +++ b/app/templates/scodoc.html @@ -11,11 +11,11 @@ {% endif %} diff --git a/app/views/absences.py b/app/views/absences.py index 0f5d0dcf..ffde5f83 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -110,7 +110,7 @@ def sco_publish(route, function, permission, methods=["GET"]): protected by permission and called following ScoDoc 7 Zope standards. """ return bp.route(route, methods=methods)( - permission_required(permission)(scodoc7func(context)(scodoc(function))) + scodoc(permission_required(permission)(scodoc7func(context)(function))) ) diff --git a/app/views/notes.py b/app/views/notes.py index 5bca5326..3d41ea05 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -43,7 +43,6 @@ from flask import current_app from flask_login import current_user from config import Config -import scodoc_manager from app.auth.models import User @@ -145,7 +144,7 @@ def sco_publish(route, function, permission, methods=["GET"]): protected by permission and called following ScoDoc 7 Zope standards. """ return bp.route(route, methods=methods)( - permission_required(permission)(scodoc7func(context)(function)) + scodoc(permission_required(permission)(scodoc7func(context)(function))) ) diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 855a418f..6b4ee01c 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -35,23 +35,23 @@ from flask import render_template from flask import request from flask_login.utils import login_required -from scodoc_manager import sco_mgr - -from app.views import scodoc_bp as bp +from app.models import Departement from app.scodoc import VERSION from app.scodoc import sco_find_etud from app.scodoc.sco_permissions import Permission +from app.views import scodoc_bp as bp @bp.route("/ScoDoc") @bp.route("/ScoDoc/index") -def index(): # XXX TODO A REECRIRE - dept_ids = sco_mgr.get_dept_ids() +def index(): + "Page d'accueil: liste des départements" + depts = Departement.query.filter_by(visible=True).all() return render_template( "scodoc.html", title=VERSION.SCONAME, current_app=flask.current_app, - dept_ids=dept_ids, + depts=depts, Permission=Permission, ) diff --git a/app/views/scolar.py b/app/views/scolar.py index 82ecc27c..dfd76c41 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -46,7 +46,6 @@ from flask import current_app from flask_login import current_user from config import Config -import scodoc_manager from app.decorators import ( scodoc, scodoc7func, @@ -116,12 +115,12 @@ from app.scodoc import sco_etud context = ScoDoc7Context("scolar") -def sco_publish(route, function, permission, methods=("GET",)): +def sco_publish(route, function, permission, methods=["GET"]): """Declare a route for a python function, protected by permission and called following ScoDoc 7 Zope standards. """ return bp.route(route, methods=methods)( - permission_required(permission)(scodoc7func(context)(scodoc(function))) + scodoc(permission_required(permission)(scodoc7func(context)(function))) ) @@ -257,7 +256,6 @@ def showEtudLog(context, etudid, format="html", REQUEST=None): # @bp.route("/") @bp.route("/kimo") @scodoc -@scodoc @permission_required(Permission.ScoView) @scodoc7func(context) def kimo(context, REQUEST=None, showcodes=0, showsemtable=0): @@ -266,9 +264,8 @@ def kimo(context, REQUEST=None, showcodes=0, showsemtable=0): return f"{time.time()} := {g.scodoc_dept}" -# @bp.route("/") -@bp.route("/index_html2") -@scodoc +@bp.route("/") +@bp.route("/index_html") @scodoc @permission_required(Permission.ScoView) @scodoc7func(context) diff --git a/app/views/users.py b/app/views/users.py index 17c68411..9b876b2f 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -42,11 +42,12 @@ from flask import g from flask_login import current_user from app import db - from app.auth.models import Permission from app.auth.models import User from app.auth.models import Role from app.auth.models import UserRole +from app.models import Departement + from app.decorators import ( scodoc, scodoc7func, @@ -63,8 +64,6 @@ from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc.sco_permissions_check import can_handle_passwd from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.views import users_bp as bp -from scodoc_manager import sco_mgr -from six.moves import range context = ScoDoc7Context("users") # sco8 @@ -128,7 +127,7 @@ def create_user_form(context, REQUEST, user_name=None, edit=0): # sinon, les départements dans lesquels l'utilisateur a le droit if is_super_admin: log("create_user_form called by %s (super admin)" % (current_user.user_name,)) - dept_ids = sco_mgr.get_dept_ids() + dept_ids = [d.acronym for d in Departement.query.all()] else: # Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la # permission ScoUsersAdmin diff --git a/scodoc.py b/scodoc.py index a0fe96da..c1e7a60d 100755 --- a/scodoc.py +++ b/scodoc.py @@ -145,7 +145,7 @@ def user_password(username, password=None): # user-password @app.cli.command() @click.argument("dept") -def sco_delete_dept(dept): # sco-delete-dept +def delete_dept(dept): # delete-dept """Delete existing departement""" click.confirm( f"""Attention: Cela va effacer toutes les données du département {dept} @@ -167,7 +167,7 @@ def sco_delete_dept(dept): # sco-delete-dept @app.cli.command() @click.argument("dept") -def sco_create_dept(dept): # sco-create-dept +def create_dept(dept): # create-dept "Create new departement" d = models.Departement(acronym=dept) db.session.add(d) diff --git a/scodoc_manager.py b/scodoc_manager.py deleted file mode 100755 index 6c301b54..00000000 --- a/scodoc_manager.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: UTF-8 -* - -""" -Manage departments, databases. - -Each departement `X` has its own database, `SCOX` -and a small configuration file `.../config/depts/X.cfg` -containing the database URI -Old ScoDoc7 installs config files contained `dbname=SCOX` -which translates as -"postgresql://@localhost:5432/" - being given by `SCODOC7_SQL_USER` env variable. -""" -import os -import re -import glob -import logging - -from flask import g - -from config import Config - -from app.scodoc.sco_exceptions import ScoConfigurationError - - -class ScoDeptDescription(object): - """Description d'un département - .dept_id : eg "RT" - .db_uri : dept database URI - """ - - def __init__(self, filename): - """Read dept description from dept file""" - if os.path.split(filename)[1][-4:] != ".cfg": - raise ScoConfigurationError("Invalid dept config filename: %s" % filename) - self.dept_id = os.path.split(filename)[1][:-4] - if not self.dept_id: - raise ScoConfigurationError("Invalid dept config filename: %s" % filename) - try: - db_uri = open(filename).read().strip() - except: - raise ScoConfigurationError("Department config file missing: %s" % filename) - m = re.match(r"dbname=SCO([a-zA-Z0-9]+$)", db_uri) - if m: - # ScoDoc7 backward compat - dept = m.group(1) # unused in ScoDoc7 - db_name = "SCO" + self.dept_id.upper() - db_uri = "postgresql://%(db_user)s@localhost:%(db_port)s/%(db_name)s" % { - "db_user": Config.SCODOC7_SQL_USER, - "db_name": db_name, - "db_port": Config.DEFAULT_SQL_PORT, - } - self.db_uri = db_uri - - -class ScoDocManager(object): - """Gestion de la liste des départements - En ScoDoc8, c'est très simple: on intègre tous les départements pour - lesquels un fichier de config est présent. - """ - - def __init__(self): - _ = self.get_dept_descriptions() - - def get_dept_descriptions(self): - filenames = glob.glob(Config.SCODOC_VAR_DIR + "/config/depts/*.cfg") - descr_list = [ScoDeptDescription(f) for f in filenames] - self._dept_descriptions = {d.dept_id: d for d in descr_list} - return self._dept_descriptions - - def get_dept_db_uri(self, dept_id): - "DB URI for this dept id" - return self._dept_descriptions[dept_id].db_uri - - def get_dept_ids(self): - "get (sorted) dept ids" - return sorted(self.get_dept_descriptions().keys()) - - def get_db_uri(self): - """ - Returns DB URI for the "current" departement. - Replaces ScoDoc7 GetDBConnexionString() - """ - return self.get_dept_db_uri(g.scodoc_dept) - - -sco_mgr = ScoDocManager() - - -class FakeUsers(object): - """Temporary for ScoDoc8 devs""" - - def __init__(self): - logging.getLogger(__name__).info("Warning: creating a FakeUser instance !") - - def user_info(self, user_name="test8", REQUEST=None): - return { - "user_name": user_name, - "nom": user_name, - "prenom": "", - "email": "", - "dept": "", - "nomprenom": user_name, - "prenomnom": user_name, - "prenom_fmt": "", - "nom_fmt": user_name, - "nomcomplet": user_name, - "nomplogin": user_name, - "passwd_temp": 0, - "status": "", - "date_expiration": None, - } - - def get_user_list(self, dept=None, with_inactives=False): - return [self.user_info()] diff --git a/tests/unit/sco_fake_gen.py b/tests/unit/sco_fake_gen.py index 130bae44..9cf9276e 100644 --- a/tests/unit/sco_fake_gen.py +++ b/tests/unit/sco_fake_gen.py @@ -15,7 +15,6 @@ import string import typing -import scodoc_manager from config import Config from app.auth.models import User from app.models import NotesFormModalite