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
cd /opt/scodoc
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", ...).
@ -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)

View File

@ -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")
)

View File

@ -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")

View File

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

View File

@ -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

View File

@ -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 = []

View File

@ -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

View File

@ -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,

View File

@ -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

View File

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

View File

@ -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,
)

View File

@ -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)

View File

@ -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

View File

@ -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)

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 scodoc_manager
from config import Config
from app.auth.models import User
from app.models import NotesFormModalite