Liste des départements, page d'accueil

This commit is contained in:
Emmanuel Viennet 2021-08-13 09:31:49 +02:00
parent 486f20d7f7
commit 0b0259997f
18 changed files with 62 additions and 170 deletions

View File

@ -172,7 +172,7 @@ de votre installation ScoDoc 7 pour passer à ScoDoc 8 (*ne pas utiliser en prod
su scodoc # si besoin su scodoc # si besoin
cd /opt/scodoc cd /opt/scodoc
source venv/bin/activate source venv/bin/activate
flask sco-create-dept DEPT flask create-dept DEPT
`DEPT` est le nom du département (un acronyme en majuscule, comme "RT", "GEA", ...). `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 su scodoc # si besoin
cd /opt/scodoc cd /opt/scodoc
source venv/bin/activate source venv/bin/activate
flask sco-delete-dept DEPT flask delete-dept DEPT
## Lancement serveur (développement, sur VM Linux) ## Lancement serveur (développement, sur VM Linux)

View File

@ -194,7 +194,7 @@ class User(UserMixin, db.Model):
return user return user
# Permissions management: # 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`. """Check if user has permission `perm` in given `dept`.
Similar to Zope ScoDoc7 `has_permission`` Similar to Zope ScoDoc7 `has_permission``
@ -382,7 +382,7 @@ class UserRole(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id")) user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
role_id = db.Column(db.Integer, db.ForeignKey("role.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 = db.relationship(
User, backref=db.backref("user_roles", cascade="all, delete-orphan") User, backref=db.backref("user_roles", cascade="all, delete-orphan")
) )

View File

@ -34,7 +34,7 @@ def login():
if form.validate_on_submit(): if form.validate_on_submit():
user = User.query.filter_by(user_name=form.user_name.data).first() user = User.query.filter_by(user_name=form.user_name.data).first()
if user is None or not user.check_password(form.password.data): 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")) return redirect(url_for("auth.login"))
login_user(user, remember=form.remember_me.data) login_user(user, remember=form.remember_me.data)
next_page = request.args.get("next") next_page = request.args.get("next")

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "8.0.1" SCOVERSION = "8.1"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"

View File

@ -37,7 +37,6 @@ import datetime
import calendar import calendar
import cgi import cgi
from scodoc_manager import sco_mgr
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb

View File

@ -31,8 +31,8 @@ import flask
from flask import url_for, g from flask import url_for, g
from flask_login import current_user from flask_login import current_user
from scodoc_manager import sco_mgr
import app import app
from app.models import Departement
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
@ -270,12 +270,12 @@ def search_etud_in_accessible_depts(expnom=None, code_nip=None):
""" """
result = [] result = []
accessible_depts = [] accessible_depts = []
depts = sco_mgr.get_dept_ids() depts = Departement.query.filter_by(visible=True).all()
for dept in depts: 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: if expnom or code_nip:
accessible_depts.append(dept) accessible_depts.append(dept.acronym)
app.set_sco_dept(dept) app.set_sco_dept(dept.acronym)
etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip) etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip)
else: else:
etuds = [] etuds = []

View File

@ -30,7 +30,8 @@
import time import time
from operator import itemgetter 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_codes_parcours
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_formations from app.scodoc import sco_formations
@ -474,16 +475,23 @@ def sem_est_courant(context, sem):
return (debut <= now) and (now <= fin) return (debut <= now) and (now <= fin)
def scodoc_get_all_unlocked_sems(context): def scodoc_get_all_unlocked_sems():
"""Liste de tous les semestres non verrouillés de tous les départements""" """Liste de tous les semestres non verrouillés de _tous_ les départements
depts = sco_mgr.get_dept_ids() (utilisé pour rapports d'activités)
"""
cur_dept = g.scodoc_dept
depts = Departement.query.filter_by(visible=True).all()
semdepts = [] semdepts = []
try:
for dept in depts: for dept in depts:
app.set_sco_dept(dept.acronym)
semdepts += [ semdepts += [
(sem, dept.Scolarite.Notes) (sem, dept)
for sem in do_formsemestre_list(dept.Scolarite.Notes) for sem in do_formsemestre_list(dept.Scolarite.Notes)
if sem["etat"] if sem["etat"]
] ]
finally:
app.set_sco_dept(cur_dept)
return semdepts return semdepts

View File

@ -33,6 +33,7 @@ from operator import itemgetter
from flask import url_for, g from flask import url_for, g
import app
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_formsemestre 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): 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.""" """Table avec _tous_ les étudiants des semestres non verrouillés
semdepts = sco_formsemestre.scodoc_get_all_unlocked_sems(context) de _tous_ les départements.
"""
cur_dept = g.scodoc_dept
semdepts = sco_formsemestre.scodoc_get_all_unlocked_sems()
etuds = [] etuds = []
for (sem, deptcontext) in semdepts: try:
etuds += sco_report.tsp_etud_list(deptcontext, sem["formsemestre_id"])[0] 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( tab, etuds_by_lycee = _table_etuds_lycees(
context, context,

View File

@ -54,8 +54,6 @@ from PIL import Image as PILImage
from flask import g, url_for, request from flask import g, url_for, request
from scodoc_manager import sco_mgr
from config import Config from config import Config
from app.scodoc.notes_log import log from app.scodoc.notes_log import log

View File

@ -11,11 +11,11 @@
{% endif %} {% endif %}
<ul class="main"> <ul class="main">
{% for dept in dept_ids %} {% for dept in depts %}
<li> <li>
<a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept) else 'link_unauthorized'}}" <a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept.acronym) else 'link_unauthorized'}}"
href="{{url_for('scolar.index_html', scodoc_dept=dept)}}">Département href="{{url_for('scolar.index_html', scodoc_dept=dept.acronym)}}">Département
{{dept}}</a> {{dept.acronym}}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@ -110,7 +110,7 @@ def sco_publish(route, function, permission, methods=["GET"]):
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """
return bp.route(route, methods=methods)( return bp.route(route, methods=methods)(
permission_required(permission)(scodoc7func(context)(scodoc(function))) scodoc(permission_required(permission)(scodoc7func(context)(function)))
) )

View File

@ -43,7 +43,6 @@ from flask import current_app
from flask_login import current_user from flask_login import current_user
from config import Config from config import Config
import scodoc_manager
from app.auth.models import User 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. protected by permission and called following ScoDoc 7 Zope standards.
""" """
return bp.route(route, methods=methods)( return bp.route(route, methods=methods)(
permission_required(permission)(scodoc7func(context)(function)) scodoc(permission_required(permission)(scodoc7func(context)(function)))
) )

View File

@ -35,23 +35,23 @@ from flask import render_template
from flask import request from flask import request
from flask_login.utils import login_required from flask_login.utils import login_required
from scodoc_manager import sco_mgr from app.models import Departement
from app.views import scodoc_bp as bp
from app.scodoc import VERSION from app.scodoc import VERSION
from app.scodoc import sco_find_etud from app.scodoc import sco_find_etud
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.views import scodoc_bp as bp
@bp.route("/ScoDoc") @bp.route("/ScoDoc")
@bp.route("/ScoDoc/index") @bp.route("/ScoDoc/index")
def index(): # XXX TODO A REECRIRE def index():
dept_ids = sco_mgr.get_dept_ids() "Page d'accueil: liste des départements"
depts = Departement.query.filter_by(visible=True).all()
return render_template( return render_template(
"scodoc.html", "scodoc.html",
title=VERSION.SCONAME, title=VERSION.SCONAME,
current_app=flask.current_app, current_app=flask.current_app,
dept_ids=dept_ids, depts=depts,
Permission=Permission, Permission=Permission,
) )

View File

@ -46,7 +46,6 @@ from flask import current_app
from flask_login import current_user from flask_login import current_user
from config import Config from config import Config
import scodoc_manager
from app.decorators import ( from app.decorators import (
scodoc, scodoc,
scodoc7func, scodoc7func,
@ -116,12 +115,12 @@ from app.scodoc import sco_etud
context = ScoDoc7Context("scolar") 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, """Declare a route for a python function,
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """
return bp.route(route, methods=methods)( 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("/")
@bp.route("/kimo") @bp.route("/kimo")
@scodoc @scodoc
@scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)
def kimo(context, REQUEST=None, showcodes=0, showsemtable=0): 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}" return f"{time.time()} := {g.scodoc_dept}"
# @bp.route("/") @bp.route("/")
@bp.route("/index_html2") @bp.route("/index_html")
@scodoc
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func(context) @scodoc7func(context)

View File

@ -42,11 +42,12 @@ from flask import g
from flask_login import current_user from flask_login import current_user
from app import db from app import db
from app.auth.models import Permission from app.auth.models import Permission
from app.auth.models import User from app.auth.models import User
from app.auth.models import Role from app.auth.models import Role
from app.auth.models import UserRole from app.auth.models import UserRole
from app.models import Departement
from app.decorators import ( from app.decorators import (
scodoc, scodoc,
scodoc7func, 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.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.views import users_bp as bp from app.views import users_bp as bp
from scodoc_manager import sco_mgr
from six.moves import range
context = ScoDoc7Context("users") # sco8 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 # sinon, les départements dans lesquels l'utilisateur a le droit
if is_super_admin: if is_super_admin:
log("create_user_form called by %s (super admin)" % (current_user.user_name,)) 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: else:
# Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la # Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la
# permission ScoUsersAdmin # permission ScoUsersAdmin

View File

@ -145,7 +145,7 @@ def user_password(username, password=None): # user-password
@app.cli.command() @app.cli.command()
@click.argument("dept") @click.argument("dept")
def sco_delete_dept(dept): # sco-delete-dept def delete_dept(dept): # delete-dept
"""Delete existing departement""" """Delete existing departement"""
click.confirm( click.confirm(
f"""Attention: Cela va effacer toutes les données du département {dept} 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() @app.cli.command()
@click.argument("dept") @click.argument("dept")
def sco_create_dept(dept): # sco-create-dept def create_dept(dept): # create-dept
"Create new departement" "Create new departement"
d = models.Departement(acronym=dept) d = models.Departement(acronym=dept)
db.session.add(d) db.session.add(d)

View File

@ -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://<user>@localhost:5432/<dbname>"
<user> 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()]

View File

@ -15,7 +15,6 @@ import string
import typing import typing
import scodoc_manager
from config import Config from config import Config
from app.auth.models import User from app.auth.models import User
from app.models import NotesFormModalite from app.models import NotesFormModalite