forked from ScoDoc/ScoDoc
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5cad38d6c8 | ||
|
401bbf103d | ||
b89277a9a8 | |||
11618196b3 | |||
|
2c7d55713a | ||
|
01820b5a91 | ||
|
600016d1e0 | ||
|
87f136d6b9 | ||
|
699b482c30 | ||
|
34e34b188c | ||
|
65221f247c |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -131,7 +131,6 @@ venv/
|
|||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
envsco8/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
|
|
@ -108,7 +108,7 @@ ADMISSION_MODIFIABLE_FIELDS = (
|
|||
def sco_import_format(with_codesemestre=True):
|
||||
"returns tuples (Attribut, Type, Table, AllowNulls, Description)"
|
||||
r = []
|
||||
for l in open(scu.SCO_SRC_DIR + "/" + FORMAT_FILE):
|
||||
for l in open(scu.SCO_SRCDIR + "/" + FORMAT_FILE):
|
||||
l = l.strip()
|
||||
if l and l[0] != "#":
|
||||
fs = l.split(";")
|
65
README.md
65
README.md
|
@ -1,5 +1,5 @@
|
|||
|
||||
# ScoDoc - Gestion de la scolarité
|
||||
# SCODOC - gestion de la scolarité
|
||||
|
||||
(c) Emmanuel Viennet 1999 - 2021 (voir LICENCE.txt)
|
||||
|
||||
|
@ -8,68 +8,7 @@ Installation: voir instructions à jour sur <https://scodoc.org>
|
|||
|
||||
Documentation utilisateur: <https://scodoc.org>
|
||||
|
||||
## Branche ScoDoc 8 expérimentale
|
||||
|
||||
N'utiliser que pour les développements et tests, dans le cadre de la migration de Zope vers Flask.
|
||||
|
||||
Basée sur **python 2.7**.
|
||||
|
||||
## Setup (sur Debian 10 / python2.7)
|
||||
|
||||
virtualenv envsco8
|
||||
|
||||
source envsco8/bin/activate
|
||||
|
||||
installation:
|
||||
|
||||
pip install flask
|
||||
# et pas mal d'autres paquets
|
||||
|
||||
donc utiliser:
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
pour régénerer ce fichier:
|
||||
|
||||
pip freeze > requirements.txt
|
||||
|
||||
### Bidouilles temporaires
|
||||
|
||||
Installer le bon vieux `pyExcelerator` dans l'environnement:
|
||||
|
||||
(cd /tmp; tar xfz /opt/scodoc/Products/ScoDoc/config/softs/pyExcelerator-0.6.3a.patched.tgz )
|
||||
(cd /tmp/pyExcelerator-0.6.3a.patched/; python setup.py install)
|
||||
|
||||
## Lancement serveur (développement, sur VM Linux)
|
||||
|
||||
export FLASK_APP=scodoc.py
|
||||
export FLASK_ENV=development
|
||||
flask run --host=0.0.0.0
|
||||
|
||||
## Tests
|
||||
|
||||
python -m unittest tests.test_users
|
||||
|
||||
# Work in Progress
|
||||
|
||||
## Migration ZScolar
|
||||
|
||||
### Méthodes qui ne devraient plus être publiées:
|
||||
security.declareProtected(ScoView, "get_preferences")
|
||||
|
||||
def get_preferences(context, formsemestre_id=None):
|
||||
"Get preferences for this instance (a dict-like instance)"
|
||||
return sco_preferences.sem_preferences(context, formsemestre_id)
|
||||
|
||||
security.declareProtected(ScoView, "get_preference")
|
||||
|
||||
def get_preference(context, name, formsemestre_id=None):
|
||||
"""Returns value of named preference.
|
||||
All preferences have a sensible default value (see sco_preferences.py),
|
||||
this function always returns a usable value for all defined preferences names.
|
||||
"""
|
||||
return sco_preferences.get_base_preferences(context).get(formsemestre_id, name)
|
||||
|
||||
Ce logiciel est un produit pour Zope 2.13 écrit en Python (2.4, passé à 2.7 pour ScoDoc7).
|
||||
|
||||
|
||||
|
||||
|
|
238
TODO
Normal file
238
TODO
Normal file
|
@ -0,0 +1,238 @@
|
|||
|
||||
NOTES EN VRAC / Brouillon / Trucs obsoletes
|
||||
|
||||
|
||||
#do_moduleimpl_list\(\{"([a-z_]*)"\s*:\s*(.*)\}\)
|
||||
#do_moduleimpl_list( $1 = $2 )
|
||||
|
||||
#do_moduleimpl_list\([\s\n]*args[\s\n]*=[\s\n]*\{"([a-z_]*)"[\s\n]*:[\s\n]*(.*)[\s\n]*\}[\s\n]*\)
|
||||
|
||||
Upgrade JavaScript
|
||||
- jquery-ui-1.12.1 introduit un problème d'affichage de la barre de menu.
|
||||
Il faudrait la revoir entièrement pour upgrader.
|
||||
On reste donc à jquery-ui-1.10.4.custom
|
||||
Or cette version est incompatible avec jQuery 3 (messages d'erreur dans la console)
|
||||
On reste donc avec jQuery 1.12.14
|
||||
|
||||
|
||||
Suivi des requêtes utilisateurs:
|
||||
table sql: id, ip, authuser, request
|
||||
|
||||
|
||||
* Optim:
|
||||
porcodeb4, avant memorisation des moy_ue:
|
||||
S1 SEM14133 cold start: min 9s, max 12s, avg > 11s
|
||||
inval (add note): 1.33s (pas de recalcul des autres)
|
||||
inval (add abs) : min8s, max 12s (recalcule tout :-()
|
||||
LP SEM14946 cold start: 0.7s - 0.86s
|
||||
|
||||
|
||||
|
||||
----------------- LISTE OBSOLETE (très ancienne, à trier) -----------------------
|
||||
BUGS
|
||||
----
|
||||
|
||||
- formsemestre_inscription_with_modules
|
||||
si inscription 'un etud deja inscrit, IntegrityError
|
||||
|
||||
FEATURES REQUESTS
|
||||
-----------------
|
||||
|
||||
* Bulletins:
|
||||
. logos IUT et Univ sur bull PDF
|
||||
. nom departement: nom abbrégé (CJ) ou complet (Carrière Juridiques)
|
||||
. bulletin: deplacer la barre indicateur (cf OLDGEA S2: gêne)
|
||||
. bulletin: click nom titre -> ficheEtud
|
||||
|
||||
. formsemestre_pagebulletin_dialog: marges en mm: accepter "2,5" et "2.5"
|
||||
et valider correctement le form !
|
||||
|
||||
* Jury
|
||||
. recapcomplet: revenir avec qq lignes au dessus de l'étudiant en cours
|
||||
|
||||
|
||||
* Divers
|
||||
. formsemestre_editwithmodules: confirmer suppression modules
|
||||
(et pour l'instant impossible si evaluations dans le module)
|
||||
|
||||
* Modules et UE optionnelles:
|
||||
. UE capitalisées: donc dispense possible dans semestre redoublé.
|
||||
traitable en n'inscrivant pas l'etudiant au modules
|
||||
de cette UE: faire interface utilisateur
|
||||
|
||||
. page pour inscription d'un etudiant a un module
|
||||
. page pour visualiser les modules auquel un etudiant est inscrit,
|
||||
et le desinscrire si besoin.
|
||||
|
||||
. ficheEtud indiquer si inscrit au module sport
|
||||
|
||||
* Absences
|
||||
. EtatAbsences : verifier dates (en JS)
|
||||
. Listes absences pdf et listes groupes pdf + emargements (cf mail Nathalie)
|
||||
. absences par demi-journées sur EtatAbsencesDate (? à vérifier)
|
||||
. formChoixSemestreGroupe: utilisé par Absences/index_html
|
||||
a améliorer
|
||||
|
||||
|
||||
* Notes et évaluations:
|
||||
. Exception "Not an OLE file": generer page erreur plus explicite
|
||||
. Dates evaluation: utiliser JS pour calendrier
|
||||
. Saisie des notes: si une note invalide, l'indiquer dans le listing (JS ?)
|
||||
. et/ou: notes invalides: afficher les noms des etudiants concernes
|
||||
dans le message d'erreur.
|
||||
. upload excel: message erreur peu explicite:
|
||||
* Feuille "Saisie notes", 17 lignes
|
||||
* Erreur: la feuille contient 1 notes invalides
|
||||
* Notes invalides pour les id: ['10500494']
|
||||
(pas de notes modifiées)
|
||||
Notes chargées. <<< CONTRADICTOIRE !!
|
||||
|
||||
. recap complet semestre:
|
||||
Options:
|
||||
- choix groupes
|
||||
- critère de tri (moy ou alphab)
|
||||
- nb de chiffres a afficher
|
||||
|
||||
+ definir des "catégories" d'évaluations (eg "théorie","pratique")
|
||||
afin de n'afficher que des moyennes "de catégorie" dans
|
||||
le bulletin.
|
||||
|
||||
. liste des absents à une eval et croisement avec BD absences
|
||||
|
||||
. notes_evaluation_listenotes
|
||||
- afficher groupes, moyenne, #inscrits, #absents, #manquantes dans l'en-tete.
|
||||
- lien vers modif notes (selon role)
|
||||
|
||||
. Export excel des notes d'evaluation: indiquer date, et autres infos en haut.
|
||||
. Génération PDF listes notes
|
||||
. Page recap notes moyennes par groupes (choisir type de groupe?)
|
||||
|
||||
. (GEA) edition tableau notes avec tous les evals d'un module
|
||||
(comme notes_evaluation_listenotes mais avec tt les evals)
|
||||
|
||||
|
||||
* Non prioritaire:
|
||||
. optimiser scolar_news_summary
|
||||
. recapitulatif des "nouvelles"
|
||||
- dernieres notes
|
||||
- changement de statuts (demissions,inscriptions)
|
||||
- annotations
|
||||
- entreprises
|
||||
|
||||
. notes_table: pouvoir changer decision sans invalider tout le cache
|
||||
. navigation: utiliser Session pour montrer historique pages vues ?
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
A faire:
|
||||
- fiche etud: code dec jury sur ligne 1
|
||||
si ancien, indiquer autorisation inscription sous le parcours
|
||||
|
||||
- saisie notes: undo
|
||||
- saisie notes: validation
|
||||
- ticket #18:
|
||||
UE capitalisées: donc dispense possible dans semestre redoublé. Traitable en n'inscrivant pas l'etudiant aux modules de cette UE: faire interface utilisateur.
|
||||
|
||||
Prévoir d'entrer une UE capitalisée avec sa note, date d'obtention et un commentaire. Coupler avec la désincription aux modules (si l'étudiant a été inscrit avec ses condisciples).
|
||||
|
||||
|
||||
- Ticket #4: Afin d'éviter les doublons, vérifier qu'il n'existe pas d'homonyme proche lors de la création manuelle d'un étudiant. (confirmé en ScoDoc 6, vérifier aussi les imports Excel)
|
||||
|
||||
- Ticket #74: Il est possible d'inscrire un étudiant sans prénom par un import excel !!!
|
||||
|
||||
- Ticket #64: saisir les absences pour la promo entiere (et pas par groupe). Des fois, je fais signer une feuille de presence en amphi a partir de la liste de tous les etudiants. Ensuite pour reporter les absents par groupe, c'est galere.
|
||||
|
||||
- Ticket #62: Lors des exports Excel, le format des cellules n'est pas reconnu comme numérique sous Windows (pas de problèmes avec Macintosh et Linux).
|
||||
|
||||
A confirmer et corriger.
|
||||
|
||||
- Ticket #75: On peut modifier une décision de jury (et les autorisations de passage associées), mais pas la supprimer purement et simplement.
|
||||
Ajoute ce choix dans les "décisions manuelles".
|
||||
|
||||
- Ticket #37: Page recap notes moyennes par groupes
|
||||
Construire une page avec les moyennes dans chaque UE ou module par groupe d'étudiants.
|
||||
Et aussi pourquoi pas ventiler par type de bac, sexe, parcours (nombre de semestre de parcours) ?
|
||||
redemandé par CJ: à faire avant mai 2008 !
|
||||
|
||||
- Ticket #75: Synchro Apogée: choisir les etudiants
|
||||
Sur la page de syncho Apogée (formsemestre_synchro_etuds), on peut choisir (cocher) les étudiants Apogée à importer. mais on ne peut pas le faire s'ils sont déjà dans ScoDoc: il faudrait ajouter des checkboxes dans toutes les listes.
|
||||
|
||||
- Ticket #9: Format des valeurs de marges des bulletins.
|
||||
formsemestre_pagebulletin_dialog: marges en mm: accepter "2,5" et "2.5" et valider correctement le form !
|
||||
|
||||
- Ticket #17: Suppression modules dans semestres
|
||||
formsemestre_editwithmodules: confirmer suppression modules
|
||||
|
||||
- Ticket #29: changer le stoquage des photos, garder une version HD.
|
||||
|
||||
- bencher NotesTable sans calcul de moyennes. Etudier un cache des moyennes de modules.
|
||||
- listes d'utilisateurs (modules): remplacer menus par champs texte + completions javascript
|
||||
- documenter archives sur Wiki
|
||||
- verifier paquet Debian pour font pdf (reportab: helvetica ... plante si font indisponible)
|
||||
- chercher comment obtenir une page d'erreur correcte pour les pages POST
|
||||
(eg: si le font n'existe pas, archive semestre echoue sans page d'erreur)
|
||||
? je ne crois pas que le POST soit en cause. HTTP status=500
|
||||
ne se produit pas avec Safari
|
||||
- essayer avec IE / Win98
|
||||
- faire apparaitre les diplômés sur le graphe des parcours
|
||||
- démission: formulaire: vérifier que la date est bien dans le semestre
|
||||
|
||||
+ graphe parcours: aligner en colonnes selon les dates (de fin), placer les diplomes
|
||||
dans la même colone que le semestre terminal.
|
||||
|
||||
- modif gestion utilisateurs (donner droits en fct du dept. d'appartenance, bug #57)
|
||||
- modif form def. utilisateur (dept appartenance)
|
||||
- utilisateurs: source externe
|
||||
- archivage des semestres
|
||||
|
||||
|
||||
o-------------------------------------o
|
||||
|
||||
* Nouvelle gestion utilisateurs:
|
||||
objectif: dissocier l'authentification de la notion "d'enseignant"
|
||||
On a une source externe "d'utilisateurs" (annuaire LDAP ou base SQL)
|
||||
qui permet seulement de:
|
||||
- authentifier un utilisateur (login, passwd)
|
||||
- lister un utilisateur: login => firstname, lastname, email
|
||||
- lister les utilisateurs
|
||||
|
||||
et une base interne ScoDoc "d'acteurs" (enseignants, administratifs).
|
||||
Chaque acteur est défini par:
|
||||
- actor_id, firstname, lastname
|
||||
date_creation, date_expiration,
|
||||
roles, departement,
|
||||
email (+flag indiquant s'il faut utiliser ce mail ou celui de
|
||||
l'utilisateur ?)
|
||||
state (on, off) (pour desactiver avant expiration ?)
|
||||
user_id (login) => lien avec base utilisateur
|
||||
|
||||
On offrira une source d'utilisateurs SQL (base partagée par tous les dept.
|
||||
d'une instance ScoDoc), mais dans la plupart des cas les gens utiliseront
|
||||
un annuaire LDAP.
|
||||
|
||||
La base d'acteurs remplace ScoUsers. Les objets ScoDoc (semestres,
|
||||
modules etc) font référence à des acteurs (eg responsable_id est un actor_id).
|
||||
|
||||
Le lien entre les deux ?
|
||||
Loger un utilisateur => authentification utilisateur + association d'un acteur
|
||||
Cela doit se faire au niveau d'un UserFolder Zope, pour avoir les
|
||||
bons rôles et le contrôle d'accès adéquat.
|
||||
(Il faut donc coder notre propre UserFolder).
|
||||
On ne peut associer qu'un acteur à l'état 'on' et non expiré.
|
||||
|
||||
Opérations ScoDoc:
|
||||
- paramétrage: choisir et paramétrer source utilisateurs
|
||||
- ajouter utilisateur: choisir un utilisateur dans la liste
|
||||
et lui associer un nouvel acteur (choix des rôles, des dates)
|
||||
+ éventuellement: synchro d'un ensemble d'utilisateurs, basé sur
|
||||
une requête (eg LDAP) précise (quelle interface utilisateur proposer ?)
|
||||
|
||||
- régulièrement (cron) aviser quelqu'un (le chef) de l'expiration des acteurs.
|
||||
- changer etat d'un acteur (on/off)
|
||||
|
||||
|
||||
o-------------------------------------o
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "8.01a"
|
||||
SCOVERSION = "7.24"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
SCONEWS = """
|
||||
<h4>Année 2021</h4>
|
||||
<ul>
|
||||
<li>Version mobile (en test)</li>
|
||||
<li>Évaluations de type "deuxième session"</li>
|
||||
<li>Gestion du genre neutre (pas d'affichage de la civilité)</li>
|
||||
<li>Diverses corrections (PV de jurys, ...)</li>
|
|
@ -720,7 +720,7 @@ class ZAbsences(
|
|||
+ self.sco_footer(REQUEST)
|
||||
)
|
||||
|
||||
base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % (
|
||||
base_url = "SignaleAbsenceGrHebdo?datelundi=%s&%s&destination=%s" % (
|
||||
datelundi,
|
||||
groups_infos.groups_query_args,
|
||||
urllib.quote(destination),
|
||||
|
@ -904,16 +904,15 @@ class ZAbsences(
|
|||
etuds = [e for e in etuds if e["etudid"] in mod_inscrits]
|
||||
if not moduleimpl_id:
|
||||
moduleimpl_id = None
|
||||
base_url_noweeks = (
|
||||
"SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s"
|
||||
% (
|
||||
datedebut,
|
||||
datefin,
|
||||
groups_infos.groups_query_args,
|
||||
urllib.quote(destination),
|
||||
)
|
||||
base_url_noweeks = "SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s" % (
|
||||
datedebut,
|
||||
datefin,
|
||||
groups_infos.groups_query_args,
|
||||
urllib.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
|
||||
|
||||
if etuds:
|
||||
nt = self.Notes._getNotesCache().get_NotesTable(self.Notes, formsemestre_id)
|
||||
|
@ -953,9 +952,9 @@ class ZAbsences(
|
|||
dates = dates[-nbweeks:]
|
||||
msg = "Montrer toutes les semaines"
|
||||
nwl = 0
|
||||
url_link_semaines = base_url_noweeks + "&nbweeks=%s" % nwl
|
||||
url_link_semaines = base_url_noweeks + "&nbweeks=%s" % nwl
|
||||
if moduleimpl_id:
|
||||
url_link_semaines += "&moduleimpl_id=" + moduleimpl_id
|
||||
url_link_semaines += "&moduleimpl_id=" + moduleimpl_id
|
||||
#
|
||||
dates = [x.ISO() for x in dates]
|
||||
dayname = sco_abs.day_names(self)[jourdebut.weekday]
|
||||
|
@ -1028,7 +1027,7 @@ class ZAbsences(
|
|||
"""<p>
|
||||
Module concerné par ces absences (%(optionel_txt)s):
|
||||
<select id="moduleimpl_id" name="moduleimpl_id"
|
||||
onchange="document.location='%(url)s&moduleimpl_id='+document.getElementById('moduleimpl_id').value">
|
||||
onchange="document.location='%(url)s&moduleimpl_id='+document.getElementById('moduleimpl_id').value">
|
||||
<option value="" %(sel)s>non spécifié</option>
|
||||
%(menu_module)s
|
||||
</select>
|
||||
|
@ -1328,7 +1327,7 @@ class ZAbsences(
|
|||
for a in absnonjust:
|
||||
a["justlink"] = "<em>justifier</em>"
|
||||
a["_justlink_target"] = (
|
||||
"doJustifAbsence?etudid=%s&datedebut=%s&datefin=%s&demijournee=%s"
|
||||
"doJustifAbsence?etudid=%s&datedebut=%s&datefin=%s&demijournee=%s"
|
||||
% (etudid, a["datedmy"], a["datedmy"], a["ampm"])
|
||||
)
|
||||
#
|
||||
|
@ -1464,7 +1463,7 @@ class ZAbsences(
|
|||
)
|
||||
+ "<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"
|
||||
% (groups_infos.base_url, formsemestre_id, debut, fin),
|
||||
filename="etat_abs_"
|
||||
+ scu.make_filename(
|
||||
|
@ -1701,7 +1700,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||
"ProcessBilletAbsenceForm?billet_id=%s" % b["billet_id"]
|
||||
)
|
||||
if etud:
|
||||
b["_etat_str_target"] += "&etudid=%s" % etud["etudid"]
|
||||
b["_etat_str_target"] += "&etudid=%s" % etud["etudid"]
|
||||
b["_billet_id_target"] = b["_etat_str_target"]
|
||||
else:
|
||||
b["etat_str"] = "ok"
|
|
@ -55,17 +55,7 @@ from email.MIMEBase import MIMEBase # pylint: disable=no-name-in-module,import-
|
|||
from email.Header import Header # pylint: disable=no-name-in-module,import-error
|
||||
from email import Encoders # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
from sco_zope import (
|
||||
ObjectManager,
|
||||
PropertyManager,
|
||||
RoleManager,
|
||||
Item,
|
||||
Persistent,
|
||||
Implicit,
|
||||
ClassSecurityInfo,
|
||||
DTMLFile,
|
||||
Globals,
|
||||
)
|
||||
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
try:
|
||||
import Products.ZPsycopgDA.DA as ZopeDA
|
||||
|
@ -514,11 +504,6 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||
% REQUEST.BASE0
|
||||
)
|
||||
|
||||
# Lien expérimental temporaire:
|
||||
H.append(
|
||||
'<p><a href="/ScoDoc/static/mobile">Version mobile (expérimentale, à vos risques et périls)</a></p>'
|
||||
)
|
||||
|
||||
H.append(
|
||||
"""
|
||||
<div id="scodoc_attribution">
|
||||
|
@ -768,6 +753,7 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||
% params
|
||||
)
|
||||
# display error traceback (? may open a security risk via xss attack ?)
|
||||
# log('exc B')
|
||||
params["txt_html"] = self._report_request(REQUEST, fmt="html")
|
||||
H.append(
|
||||
"""<h4 class="scodoc">Zope Traceback (à envoyer par mail à <a href="mailto:%(sco_dev_mail)s">%(sco_dev_mail)s</a>)</h4><div style="background-color: rgb(153,153,204); border: 1px;">
|
||||
|
@ -841,6 +827,8 @@ REFERER: %(REFERER)s
|
|||
Form: %(form)s
|
||||
Origin: %(HTTP_X_FORWARDED_FOR)s
|
||||
Agent: %(HTTP_USER_AGENT)s
|
||||
|
||||
subversion: %(svn_version)s
|
||||
"""
|
||||
% params
|
||||
)
|
|
@ -261,7 +261,7 @@ class ZScoUsers(
|
|||
|
||||
security.declareProtected(ScoUsersAdmin, "user_info")
|
||||
|
||||
def user_info(self, user_name=None, user=None, format=None, REQUEST=None):
|
||||
def user_info(self, user_name=None, user=None):
|
||||
"""Donne infos sur l'utilisateur (qui peut ne pas etre dans notre base).
|
||||
Si user_name est specifie, interroge la BD. Sinon, user doit etre un dict.
|
||||
"""
|
||||
|
@ -322,7 +322,7 @@ class ZScoUsers(
|
|||
# nomnoacc est le nom en minuscules sans accents
|
||||
info["nomnoacc"] = scu.suppress_accents(scu.strlower(info["nom"]))
|
||||
|
||||
return scu.sendResult(REQUEST, info, name="user", format=format)
|
||||
return info
|
||||
|
||||
def _can_handle_passwd(self, authuser, user_name, allow_admindepts=False):
|
||||
"""true if authuser can see or change passwd of user_name.
|
||||
|
@ -523,7 +523,7 @@ class ZScoUsers(
|
|||
if authuser.has_permission(ScoUsersAdmin, self):
|
||||
H.append(
|
||||
"""
|
||||
<li><a class="stdlink" href="create_user_form?user_name=%(user_name)s&edit=1">modifier/déactiver ce compte</a></li>
|
||||
<li><a class="stdlink" href="create_user_form?user_name=%(user_name)s&edit=1">modifier/déactiver ce compte</a></li>
|
||||
<li><a class="stdlink" href="delete_user_form?user_name=%(user_name)s">supprimer cet utilisateur</a> <em>(à n'utiliser qu'en cas d'erreur !)</em></li>
|
||||
"""
|
||||
% info[0]
|
|
@ -279,7 +279,7 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||
<!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>
|
||||
<title>Programme DUT TEST</title>
|
||||
<title>Programme DUT R&T</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<meta name="LANG" content="fr" />
|
||||
|
@ -416,6 +416,11 @@ REQUEST.URL0=%s<br/>
|
|||
# GESTION DE LA BD
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
security.declareProtected(ScoSuperAdmin, "GetDBConnexionString")
|
||||
|
||||
def GetDBConnexionString(self):
|
||||
# should not be published (but used from contained classes via acquisition)
|
||||
return self._db_cnx_string
|
||||
|
||||
security.declareProtected(ScoSuperAdmin, "GetDBConnexion")
|
||||
GetDBConnexion = ndb.GetDBConnexion
|
||||
|
@ -462,9 +467,9 @@ REQUEST.URL0=%s<br/>
|
|||
H = [
|
||||
"""<h2>Système de gestion scolarité</h2>
|
||||
<p>© Emmanuel Viennet 1997-2021</p>
|
||||
<p>Version %s</p>
|
||||
<p>Version %s (subversion %s)</p>
|
||||
"""
|
||||
% (scu.get_scodoc_version())
|
||||
% (SCOVERSION, scu.get_svn_version(file_path))
|
||||
]
|
||||
H.append(
|
||||
'<p>Logiciel libre écrit en <a href="http://www.python.org">Python</a>.</p><p>Utilise <a href="http://www.reportlab.org/">ReportLab</a> pour générer les documents PDF, et <a href="http://sourceforge.net/projects/pyexcelerator">pyExcelerator</a> pour le traitement des documents Excel.</p>'
|
||||
|
@ -674,7 +679,7 @@ REQUEST.URL0=%s<br/>
|
|||
date = date.next()
|
||||
FA.append("</select>")
|
||||
FA.append(
|
||||
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
|
||||
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
|
||||
% sem
|
||||
)
|
||||
FA.append("</form></td>")
|
||||
|
@ -710,8 +715,8 @@ REQUEST.URL0=%s<br/>
|
|||
"""<td>
|
||||
<a href="%(url)s/groups_view?group_ids=%(group_id)s">%(label)s</a>
|
||||
</td><td>
|
||||
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
|
||||
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
|
||||
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
|
||||
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
|
||||
</td>"""
|
||||
% group
|
||||
)
|
||||
|
@ -775,9 +780,7 @@ REQUEST.URL0=%s<br/>
|
|||
# -------------------------- INFOS SUR ETUDIANTS --------------------------
|
||||
security.declareProtected(ScoView, "getEtudInfo")
|
||||
|
||||
def getEtudInfo(
|
||||
self, etudid=False, code_nip=False, filled=False, REQUEST=None, format=None
|
||||
):
|
||||
def getEtudInfo(self, etudid=False, code_nip=False, filled=False, REQUEST=None, format=None):
|
||||
"""infos sur un etudiant pour utilisation en Zope DTML
|
||||
On peut specifier etudid
|
||||
ou bien cherche dans REQUEST.form: etudid, code_nip, code_ine
|
||||
|
@ -1171,7 +1174,7 @@ REQUEST.URL0=%s<br/>
|
|||
scolars.etud_annotations_delete(cnx, annotation_id)
|
||||
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"ficheEtud?etudid=%s&head_message=Annotation%%20supprimée" % (etudid)
|
||||
"ficheEtud?etudid=%s&head_message=Annotation%%20supprimée" % (etudid)
|
||||
)
|
||||
|
||||
security.declareProtected(ScoEtudChangeAdr, "formChangeCoordonnees")
|
||||
|
@ -2773,7 +2776,7 @@ def _simple_error_page(context, msg, DeptId=None):
|
|||
H = [context.standard_html_header(context), "<h2>Erreur !</h2>", "<p>", msg, "</p>"]
|
||||
if DeptId:
|
||||
H.append(
|
||||
'<p><a href="delete_dept?DeptId=%s&force=1">Supprimer le dossier %s</a>(très recommandé !)</p>'
|
||||
'<p><a href="delete_dept?DeptId=%s&force=1">Supprimer le dossier %s</a>(très recommandé !)</p>'
|
||||
% (DeptId, DeptId)
|
||||
)
|
||||
H.append(context.standard_html_footer(context))
|
|
@ -25,6 +25,33 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
"""ScoDoc core package
|
||||
"""
|
||||
# from app.scodoc import sco_core
|
||||
from ZScolar import ZScolar, manage_addZScolarForm, manage_addZScolar
|
||||
|
||||
from ZScoDoc import ZScoDoc, manage_addZScoDoc
|
||||
|
||||
# from sco_zope import *
|
||||
# from notes_log import log
|
||||
# log.set_log_directory( INSTANCE_HOME + '/log' )
|
||||
|
||||
|
||||
__version__ = "1.0.0"
|
||||
|
||||
|
||||
def initialize(context):
|
||||
"""initialize the Scolar products"""
|
||||
# called at each startup (context is a ProductContext instance, basically useless)
|
||||
|
||||
# --- ZScolars
|
||||
context.registerClass(
|
||||
ZScolar,
|
||||
constructors=(
|
||||
manage_addZScolarForm, # this is called when someone adds the product
|
||||
manage_addZScolar,
|
||||
),
|
||||
icon="static/icons/sco_icon.png",
|
||||
)
|
||||
|
||||
# --- ZScoDoc
|
||||
context.registerClass(
|
||||
ZScoDoc, constructors=(manage_addZScoDoc,), icon="static/icons/sco_icon.png"
|
||||
)
|
105
app/__init__.py
105
app/__init__.py
|
@ -1,105 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
import os
|
||||
import logging
|
||||
from logging.handlers import SMTPHandler, RotatingFileHandler
|
||||
|
||||
from flask import request
|
||||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_login import LoginManager
|
||||
from flask_mail import Mail
|
||||
from flask_bootstrap import Bootstrap
|
||||
from flask_moment import Moment
|
||||
|
||||
from config import Config
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(Config)
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
migrate = Migrate(app, db)
|
||||
login = LoginManager()
|
||||
login.login_view = "auth.login"
|
||||
login.login_message = "Please log in to access this page."
|
||||
mail = Mail()
|
||||
bootstrap = Bootstrap(app)
|
||||
moment = Moment()
|
||||
|
||||
|
||||
def create_app(config_class=Config):
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(config_class)
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
login.init_app(app)
|
||||
mail.init_app(app)
|
||||
bootstrap.init_app(app)
|
||||
moment.init_app(app)
|
||||
|
||||
from app.auth import bp as auth_bp
|
||||
|
||||
app.register_blueprint(auth_bp, url_prefix="/auth")
|
||||
|
||||
from app.views import essais_bp
|
||||
|
||||
app.register_blueprint(essais_bp, url_prefix="/Essais")
|
||||
|
||||
from app.views import scolar_bp
|
||||
from app.views import notes_bp
|
||||
from app.views import absences_bp
|
||||
|
||||
# https://scodoc.fr/ScoDoc/RT/Scolarite/...
|
||||
app.register_blueprint(scolar_bp, url_prefix="/ScoDoc/<scodoc_dept>/Scolarite")
|
||||
# https://scodoc.fr/ScoDoc/RT/Scolarite/Notes/...
|
||||
app.register_blueprint(notes_bp, url_prefix="/ScoDoc/<scodoc_dept>/Scolarite/Notes")
|
||||
# https://scodoc.fr/ScoDoc/RT/Scolarite/Absences/...
|
||||
app.register_blueprint(
|
||||
absences_bp, url_prefix="/ScoDoc/<scodoc_dept>/Scolarite/Absences"
|
||||
)
|
||||
|
||||
from app.main import bp as main_bp
|
||||
|
||||
app.register_blueprint(main_bp)
|
||||
|
||||
if not app.debug and not app.testing:
|
||||
if app.config["MAIL_SERVER"]:
|
||||
auth = None
|
||||
if app.config["MAIL_USERNAME"] or app.config["MAIL_PASSWORD"]:
|
||||
auth = (app.config["MAIL_USERNAME"], app.config["MAIL_PASSWORD"])
|
||||
secure = None
|
||||
if app.config["MAIL_USE_TLS"]:
|
||||
secure = ()
|
||||
mail_handler = SMTPHandler(
|
||||
mailhost=(app.config["MAIL_SERVER"], app.config["MAIL_PORT"]),
|
||||
fromaddr="no-reply@" + app.config["MAIL_SERVER"],
|
||||
toaddrs=[app.config["ADMINS"]],
|
||||
subject="ScoDoc8 Failure",
|
||||
credentials=auth,
|
||||
secure=secure,
|
||||
)
|
||||
mail_handler.setLevel(logging.ERROR)
|
||||
app.logger.addHandler(mail_handler)
|
||||
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
file_handler = RotatingFileHandler(
|
||||
"logs/scodoc.log", maxBytes=10240, backupCount=10
|
||||
)
|
||||
file_handler.setFormatter(
|
||||
logging.Formatter(
|
||||
"%(asctime)s %(levelname)s: %(message)s " "[in %(pathname)s:%(lineno)d]"
|
||||
)
|
||||
)
|
||||
file_handler.setLevel(logging.INFO)
|
||||
app.logger.addHandler(file_handler)
|
||||
|
||||
app.logger.setLevel(logging.INFO)
|
||||
app.logger.info("ScoDoc8 startup")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
# from app import models
|
|
@ -1,6 +0,0 @@
|
|||
# ScoDoc User Authentication Blueprint
|
||||
|
||||
Code borrowed and adapted from
|
||||
https://courses.miguelgrinberg.com/p/flask-mega-tutorial
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
"""auth.__init__
|
||||
"""
|
||||
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint("auth", __name__)
|
||||
|
||||
from app.auth import routes
|
|
@ -1,15 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
from flask import render_template, current_app
|
||||
from flask_babel import _
|
||||
from app.email import send_email
|
||||
|
||||
|
||||
def send_password_reset_email(user):
|
||||
token = user.get_reset_password_token()
|
||||
send_email(
|
||||
"[ScoDoc] Reset Your Password",
|
||||
sender=current_app.config["ADMINS"][0],
|
||||
recipients=[user.email],
|
||||
text_body=render_template("email/reset_password.txt", user=user, token=token),
|
||||
html_body=render_template("email/reset_password.html", user=user, token=token),
|
||||
)
|
|
@ -1,55 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
|
||||
"""Formulaires authentification
|
||||
|
||||
TODO: à revoir complètement pour reprendre ZScoUsers et les pages d'authentification
|
||||
"""
|
||||
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
||||
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
||||
from app.auth.models import User
|
||||
|
||||
|
||||
_ = lambda x: x # sans babel
|
||||
_l = _
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
username = StringField(_l("Username"), validators=[DataRequired()])
|
||||
password = PasswordField(_l("Password"), validators=[DataRequired()])
|
||||
remember_me = BooleanField(_l("Remember Me"))
|
||||
submit = SubmitField(_l("Sign In"))
|
||||
|
||||
|
||||
class UserCreationForm(FlaskForm):
|
||||
username = StringField(_l("Username"), validators=[DataRequired()])
|
||||
email = StringField(_l("Email"), validators=[DataRequired(), Email()])
|
||||
password = PasswordField(_l("Password"), validators=[DataRequired()])
|
||||
password2 = PasswordField(
|
||||
_l("Repeat Password"), validators=[DataRequired(), EqualTo("password")]
|
||||
)
|
||||
submit = SubmitField(_l("Register"))
|
||||
|
||||
def validate_username(self, username):
|
||||
user = User.query.filter_by(username=username.data).first()
|
||||
if user is not None:
|
||||
raise ValidationError(_("Please use a different username."))
|
||||
|
||||
def validate_email(self, email):
|
||||
user = User.query.filter_by(email=email.data).first()
|
||||
if user is not None:
|
||||
raise ValidationError(_("Please use a different email address."))
|
||||
|
||||
|
||||
class ResetPasswordRequestForm(FlaskForm):
|
||||
email = StringField(_l("Email"), validators=[DataRequired(), Email()])
|
||||
submit = SubmitField(_l("Request Password Reset"))
|
||||
|
||||
|
||||
class ResetPasswordForm(FlaskForm):
|
||||
password = PasswordField(_l("Password"), validators=[DataRequired()])
|
||||
password2 = PasswordField(
|
||||
_l("Repeat Password"), validators=[DataRequired(), EqualTo("password")]
|
||||
)
|
||||
submit = SubmitField(_l("Request Password Reset"))
|
|
@ -1,262 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
|
||||
"""Users and Roles models for ScoDoc
|
||||
"""
|
||||
|
||||
import base64
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import md5
|
||||
import json
|
||||
import os
|
||||
from time import time
|
||||
|
||||
from flask import current_app, url_for
|
||||
from flask_login import UserMixin, AnonymousUserMixin
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
|
||||
import jwt
|
||||
|
||||
from app import db, login
|
||||
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS
|
||||
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
"""ScoDoc users, handled by Flask / SQLAlchemy"""
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(64), index=True, unique=True)
|
||||
email = db.Column(db.String(120), index=True, unique=True)
|
||||
password_hash = db.Column(db.String(128))
|
||||
about_me = db.Column(db.String(140))
|
||||
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
token = db.Column(db.String(32), index=True, unique=True)
|
||||
token_expiration = db.Column(db.DateTime)
|
||||
roles = db.relationship("Role", secondary="user_role", viewonly=True)
|
||||
Permission = Permission
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.roles = []
|
||||
super(User, self).__init__(**kwargs)
|
||||
if (
|
||||
not self.roles
|
||||
and self.email
|
||||
and self.email == current_app.config["SCODOC_ADMIN_MAIL"]
|
||||
):
|
||||
# super-admin
|
||||
admin_role = Role.query.filter_by(name="Admin").first()
|
||||
assert admin_role
|
||||
self.add_role(admin_role, None)
|
||||
db.session.commit()
|
||||
current_app.logger.info("creating user with roles={}".format(self.roles))
|
||||
|
||||
def __repr__(self):
|
||||
return "<User {}>".format(self.username)
|
||||
|
||||
def __str__(self):
|
||||
return self.username
|
||||
|
||||
def set_password(self, password):
|
||||
"Set password"
|
||||
if password:
|
||||
self.password_hash = generate_password_hash(password)
|
||||
else:
|
||||
self.password_hash = None
|
||||
|
||||
def check_password(self, password):
|
||||
"""Check given password vs current one.
|
||||
Returns `True` if the password matched, `False` otherwise.
|
||||
"""
|
||||
if not self.password_hash: # user without password can't login
|
||||
return False
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
def get_reset_password_token(self, expires_in=600):
|
||||
return jwt.encode(
|
||||
{"reset_password": self.id, "exp": time() + expires_in},
|
||||
current_app.config["SECRET_KEY"],
|
||||
algorithm="HS256",
|
||||
).decode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def verify_reset_password_token(token):
|
||||
try:
|
||||
id = jwt.decode(
|
||||
token, current_app.config["SECRET_KEY"], algorithms=["HS256"]
|
||||
)["reset_password"]
|
||||
except:
|
||||
return
|
||||
return User.query.get(id)
|
||||
|
||||
def to_dict(self, include_email=False):
|
||||
data = {
|
||||
"id": self.id,
|
||||
"username": self.username,
|
||||
"last_seen": self.last_seen.isoformat() + "Z",
|
||||
"about_me": self.about_me,
|
||||
}
|
||||
if include_email:
|
||||
data["email"] = self.email
|
||||
return data
|
||||
|
||||
def from_dict(self, data, new_user=False):
|
||||
for field in ["username", "email", "about_me"]:
|
||||
if field in data:
|
||||
setattr(self, field, data[field])
|
||||
if new_user and "password" in data:
|
||||
self.set_password(data["password"])
|
||||
|
||||
def get_token(self, expires_in=3600):
|
||||
now = datetime.utcnow()
|
||||
if self.token and self.token_expiration > now + timedelta(seconds=60):
|
||||
return self.token
|
||||
self.token = base64.b64encode(os.urandom(24)).decode("utf-8")
|
||||
self.token_expiration = now + timedelta(seconds=expires_in)
|
||||
db.session.add(self)
|
||||
return self.token
|
||||
|
||||
def revoke_token(self):
|
||||
self.token_expiration = datetime.utcnow() - timedelta(seconds=1)
|
||||
|
||||
@staticmethod
|
||||
def check_token(token):
|
||||
user = User.query.filter_by(token=token).first()
|
||||
if user is None or user.token_expiration < datetime.utcnow():
|
||||
return None
|
||||
return user
|
||||
|
||||
# Permissions management:
|
||||
def has_permission(self, perm, dept):
|
||||
"""Check if user has permission `perm` in given `dept`.
|
||||
Emulate Zope `has_permission``
|
||||
|
||||
Args:
|
||||
perm: integer, one of the value defined in Permission class.
|
||||
context:
|
||||
"""
|
||||
# les role liés à ce département, et les roles avec dept=None (super-admin)
|
||||
roles_in_dept = (
|
||||
UserRole.query.filter_by(user_id=self.id)
|
||||
.filter((UserRole.dept == dept) | (UserRole.dept == None))
|
||||
.all()
|
||||
)
|
||||
for user_role in roles_in_dept:
|
||||
if user_role.role.has_permission(perm):
|
||||
return True
|
||||
return False
|
||||
|
||||
# Role management
|
||||
def add_role(self, role, dept):
|
||||
"""Add a role to this user.
|
||||
:param role: Role to add.
|
||||
"""
|
||||
self.user_roles.append(UserRole(user=self, role=role, dept=dept))
|
||||
|
||||
def add_roles(self, roles, dept):
|
||||
"""Add roles to this user.
|
||||
:param roles: Roles to add.
|
||||
"""
|
||||
for role in roles:
|
||||
self.add_role(role, dept)
|
||||
|
||||
def set_roles(self, roles, dept):
|
||||
self.user_roles = [UserRole(user=self, role=r, dept=dept) for r in roles]
|
||||
|
||||
def get_roles(self):
|
||||
for role in self.roles:
|
||||
yield role
|
||||
|
||||
def is_administrator(self):
|
||||
return self.has_permission(Permission.ScoSuperAdmin, None)
|
||||
|
||||
|
||||
class AnonymousUser(AnonymousUserMixin):
|
||||
def has_permission(self, perm, dept=None):
|
||||
return False
|
||||
|
||||
def is_administrator(self):
|
||||
return False
|
||||
|
||||
|
||||
login.anonymous_user = AnonymousUser
|
||||
|
||||
|
||||
class Role(db.Model):
|
||||
"""Roles for ScoDoc"""
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(64), unique=True)
|
||||
default = db.Column(db.Boolean, default=False, index=True)
|
||||
permissions = db.Column(db.BigInteger) # 64 bits
|
||||
users = db.relationship("User", secondary="user_role", viewonly=True)
|
||||
# __table_args__ = (db.UniqueConstraint("name", "dept", name="_rolename_dept_uc"),)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Role, self).__init__(**kwargs)
|
||||
if self.permissions is None:
|
||||
self.permissions = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "<Role {} perm={:0{w}b}>".format(
|
||||
self.name,
|
||||
self.permissions & ((1 << Permission.NBITS) - 1),
|
||||
w=Permission.NBITS,
|
||||
)
|
||||
|
||||
def add_permission(self, perm):
|
||||
self.permissions |= perm
|
||||
|
||||
def remove_permission(self, perm):
|
||||
self.permissions = self.permissions & ~perm
|
||||
|
||||
def reset_permissions(self):
|
||||
self.permissions = 0
|
||||
|
||||
def has_permission(self, perm):
|
||||
return self.permissions & perm == perm
|
||||
|
||||
@staticmethod
|
||||
def insert_roles():
|
||||
"""Create default roles"""
|
||||
default_role = "Observateur"
|
||||
for r, permissions in SCO_ROLES_DEFAULTS.items():
|
||||
role = Role.query.filter_by(name=r).first()
|
||||
if role is None:
|
||||
role = Role(name=r)
|
||||
role.reset_permissions()
|
||||
for perm in permissions:
|
||||
role.add_permission(perm)
|
||||
role.default = role.name == default_role
|
||||
db.session.add(role)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def get_named_role(name):
|
||||
"""Returns existing role with given name, or None."""
|
||||
return Role.query.filter_by(name=name).first()
|
||||
|
||||
|
||||
class UserRole(db.Model):
|
||||
"""Associate user to role, in a dept.
|
||||
If dept is None, the role applies to all departments (eg super admin).
|
||||
"""
|
||||
|
||||
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))
|
||||
user = db.relationship(
|
||||
User, backref=db.backref("user_roles", cascade="all, delete-orphan")
|
||||
)
|
||||
role = db.relationship(
|
||||
Role, backref=db.backref("user_roles", cascade="all, delete-orphan")
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "<UserRole u={} r={} dept={}>".format(self.user, self.role, self.dept)
|
||||
|
||||
|
||||
@login.user_loader
|
||||
def load_user(id):
|
||||
return User.query.get(int(id))
|
|
@ -1,100 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
"""
|
||||
auth.routes.py
|
||||
"""
|
||||
|
||||
from flask import render_template, redirect, url_for, current_app, flash, request
|
||||
from werkzeug.urls import url_parse
|
||||
from flask_login import login_user, logout_user, current_user
|
||||
|
||||
from app import db
|
||||
from app.auth import bp
|
||||
from app.auth.forms import (
|
||||
LoginForm,
|
||||
UserCreationForm,
|
||||
ResetPasswordRequestForm,
|
||||
ResetPasswordForm,
|
||||
)
|
||||
from app.auth.models import User
|
||||
from app.auth.email import send_password_reset_email
|
||||
from app.decorators import scodoc7func, admin_required
|
||||
|
||||
_ = lambda x: x # sans babel
|
||||
_l = _
|
||||
|
||||
|
||||
@bp.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for("main.index"))
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(username=form.username.data).first()
|
||||
if user is None or not user.check_password(form.password.data):
|
||||
flash(_("Invalid username or password"))
|
||||
return redirect(url_for("auth.login"))
|
||||
login_user(user, remember=form.remember_me.data)
|
||||
next_page = request.args.get("next")
|
||||
if not next_page or url_parse(next_page).netloc != "":
|
||||
next_page = url_for("main.index")
|
||||
return redirect(next_page)
|
||||
return render_template("auth/login.html", title=_("Sign In"), form=form)
|
||||
|
||||
|
||||
@bp.route("/logout")
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for("main.index"))
|
||||
|
||||
|
||||
@bp.route("/create_user", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def create_user():
|
||||
"Form creating new user"
|
||||
form = UserCreationForm()
|
||||
if form.validate_on_submit():
|
||||
user = User(username=form.username.data, email=form.email.data)
|
||||
user.set_password(form.password.data)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
flash("User {} created".format(user.username))
|
||||
return redirect(url_for("main.index"))
|
||||
return render_template(
|
||||
"auth/register.html", title=u"Création utilisateur", form=form
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/reset_password_request", methods=["GET", "POST"])
|
||||
def reset_password_request():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for("main.index"))
|
||||
form = ResetPasswordRequestForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(email=form.email.data).first()
|
||||
if user:
|
||||
send_password_reset_email(user)
|
||||
else:
|
||||
current_app.logger.info(
|
||||
"reset_password_request: for unkown user '{}'".format(form.email.data)
|
||||
)
|
||||
flash(_("Check your email for the instructions to reset your password"))
|
||||
return redirect(url_for("auth.login"))
|
||||
return render_template(
|
||||
"auth/reset_password_request.html", title=_("Reset Password"), form=form
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/reset_password/<token>", methods=["GET", "POST"])
|
||||
def reset_password(token):
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for("main.index"))
|
||||
user = User.verify_reset_password_token(token)
|
||||
if not user:
|
||||
return redirect(url_for("main.index"))
|
||||
form = ResetPasswordForm()
|
||||
if form.validate_on_submit():
|
||||
user.set_password(form.password.data)
|
||||
db.session.commit()
|
||||
flash(_("Your password has been reset."))
|
||||
return redirect(url_for("auth.login"))
|
||||
return render_template("auth/reset_password.html", form=form)
|
|
@ -1,7 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
import os
|
||||
import click
|
||||
|
||||
|
||||
def register(app):
|
||||
pass
|
|
@ -1,206 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
"""Decorators for permissions, roles and ScoDoc7 Zope compatibility
|
||||
"""
|
||||
import functools
|
||||
from functools import wraps
|
||||
import inspect
|
||||
|
||||
import flask
|
||||
from flask import g
|
||||
from flask import abort, current_app
|
||||
from flask import request
|
||||
from flask_login import current_user
|
||||
from flask_login import login_required
|
||||
from flask import current_app
|
||||
from werkzeug.exceptions import BadRequest
|
||||
from app.auth.models import Permission
|
||||
|
||||
|
||||
class ZUser(object):
|
||||
"Emulating Zope User"
|
||||
|
||||
def __init__(self):
|
||||
"create, based on `flask_login.current_user`"
|
||||
self.username = current_user.username
|
||||
|
||||
def __str__(self):
|
||||
return self.username
|
||||
|
||||
def has_permission(self, perm, context):
|
||||
"""check if this user as the permission `perm`
|
||||
in departement given by `g.scodoc_dept`.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ZRequest(object):
|
||||
"Emulating Zope 2 REQUEST"
|
||||
|
||||
def __init__(self):
|
||||
self.URL = request.base_url
|
||||
self.URL0 = self.URL
|
||||
self.BASE0 = request.url_root
|
||||
self.QUERY_STRING = request.query_string
|
||||
self.REQUEST_METHOD = request.method
|
||||
self.AUTHENTICATED_USER = current_user
|
||||
if request.method == "POST":
|
||||
self.form = request.form
|
||||
if request.files:
|
||||
# Add files in form: must copy to get a mutable version
|
||||
# request.form is a werkzeug.datastructures.ImmutableMultiDict
|
||||
self.form = self.form.copy()
|
||||
self.form.update(request.files)
|
||||
elif request.method == "GET":
|
||||
self.form = request.args
|
||||
self.RESPONSE = ZResponse()
|
||||
|
||||
def __str__(self):
|
||||
return """REQUEST
|
||||
URL={r.URL}
|
||||
QUERY_STRING={r.QUERY_STRING}
|
||||
REQUEST_METHOD={r.REQUEST_METHOD}
|
||||
AUTHENTICATED_USER={r.AUTHENTICATED_USER}
|
||||
form={r.form}
|
||||
""".format(
|
||||
r=self
|
||||
)
|
||||
|
||||
|
||||
class ZResponse(object):
|
||||
"Emulating Zope 2 RESPONSE"
|
||||
|
||||
def __init__(self):
|
||||
self.headers = {}
|
||||
|
||||
def redirect(self, url):
|
||||
return flask.redirect(url) # http 302
|
||||
|
||||
def setHeader(self, header, value):
|
||||
self.headers[header.tolower()] = value
|
||||
|
||||
|
||||
def permission_required(permission):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if "scodoc_dept" in kwargs:
|
||||
g.scodoc_dept = kwargs["scodoc_dept"]
|
||||
del kwargs["scodoc_dept"]
|
||||
current_app.logger.info(
|
||||
"permission_required: %s in %s" % (permission, g.scodoc_dept)
|
||||
)
|
||||
if not current_user.has_permission(permission, g.scodoc_dept):
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def admin_required(f):
|
||||
return permission_required(Permission.ScoSuperAdmin)(f)
|
||||
|
||||
|
||||
def scodoc7func(context):
|
||||
"""Décorateur pour intégrer les fonctions Zope 2 de ScoDoc 7.
|
||||
Si on a un kwarg `scodoc_dept`(venant de la route), le stocke dans `g.scodoc_dept`.
|
||||
Ajoute l'argument REQUEST s'il est dans la signature de la fonction.
|
||||
Les paramètres de la query string deviennent des (keywords) paramètres de la fonction.
|
||||
"""
|
||||
|
||||
def s7_decorator(func):
|
||||
@wraps(func)
|
||||
def scodoc7func_decorator(*args, **kwargs):
|
||||
"""Decorator allowing legacy Zope published methods to be called via Flask
|
||||
routes without modification.
|
||||
|
||||
There are two cases: the function can be called
|
||||
1. via a Flask route ("top level call")
|
||||
2. or be called directly from Python.
|
||||
|
||||
If called via a route, this decorator setups a REQUEST object (emulating Zope2 REQUEST)
|
||||
and `g.scodoc_dept` if present in the argument (for routes like `/<scodoc_dept>/Scolarite/sco_exemple`).
|
||||
"""
|
||||
assert not args
|
||||
# Détermine si on est appelé via une route ("toplevel")
|
||||
# ou par un appel de fonction python normal.
|
||||
top_level = not hasattr(g, "zrequest")
|
||||
if top_level:
|
||||
g.zrequest = None
|
||||
#
|
||||
if "scodoc_dept" in kwargs:
|
||||
g.scodoc_dept = kwargs["scodoc_dept"]
|
||||
del kwargs["scodoc_dept"]
|
||||
elif not hasattr(g, "scodoc_dept"): # if toplevel call
|
||||
g.scodoc_dept = None
|
||||
# --- Emulate Zope's REQUEST
|
||||
REQUEST = ZRequest()
|
||||
g.zrequest = REQUEST
|
||||
req_args = REQUEST.form # args from query string (get) or form (post)
|
||||
# --- Add positional arguments
|
||||
pos_arg_values = []
|
||||
# PY3 à remplacer par inspect.getfullargspec en py3:
|
||||
argspec = inspect.getargspec(func)
|
||||
current_app.logger.info("argspec=%s" % str(argspec))
|
||||
nb_default_args = len(argspec.defaults) if argspec.defaults else 0
|
||||
if nb_default_args:
|
||||
arg_names = argspec.args[:-nb_default_args]
|
||||
else:
|
||||
arg_names = argspec.args
|
||||
for arg_name in arg_names:
|
||||
if arg_name == "REQUEST": # special case
|
||||
pos_arg_values.append(REQUEST)
|
||||
elif arg_name == "context":
|
||||
pos_arg_values.append(context)
|
||||
else:
|
||||
pos_arg_values.append(req_args[arg_name])
|
||||
current_app.logger.info("pos_arg_values=%s" % pos_arg_values)
|
||||
# Add keyword arguments
|
||||
if nb_default_args:
|
||||
for arg_name in argspec.args[-nb_default_args:]:
|
||||
if arg_name == "REQUEST": # special case
|
||||
kwargs[arg_name] = REQUEST
|
||||
elif arg_name in req_args:
|
||||
# set argument kw optionnel
|
||||
kwargs[arg_name] = req_args[arg_name]
|
||||
current_app.logger.info(
|
||||
"scodoc7func_decorator: top_level=%s, pos_arg_values=%s, kwargs=%s"
|
||||
% (top_level, pos_arg_values, kwargs)
|
||||
)
|
||||
value = func(*pos_arg_values, **kwargs)
|
||||
|
||||
if not top_level:
|
||||
return value
|
||||
else:
|
||||
# Build response, adding collected http headers:
|
||||
headers = []
|
||||
kw = {"response": value, "status": 200}
|
||||
if g.zrequest:
|
||||
headers = g.zrequest.RESPONSE.headers
|
||||
if not headers:
|
||||
# no customized header, speedup:
|
||||
return value
|
||||
if "content-type" in headers:
|
||||
kw["mimetype"] = headers["content-type"]
|
||||
r = flask.Response(**kw)
|
||||
for h in headers:
|
||||
r.headers[h] = headers[h]
|
||||
return r
|
||||
|
||||
return scodoc7func_decorator
|
||||
|
||||
return s7_decorator
|
||||
|
||||
|
||||
# Le "context" de ScoDoc7
|
||||
class ScoDoc7Context(object):
|
||||
"""Context object for legacy Zope methods.
|
||||
Mainly used to call published methods, as context.function(...)
|
||||
"""
|
||||
|
||||
def __init__(self, globals_dict):
|
||||
self.__dict__ = globals_dict
|
||||
|
||||
def __repr__(self):
|
||||
return "ScoDoc7Context()"
|
19
app/email.py
19
app/email.py
|
@ -1,19 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
from threading import Thread
|
||||
from flask import current_app
|
||||
from flask_mail import Message
|
||||
from app import mail
|
||||
|
||||
|
||||
def send_async_email(app, msg):
|
||||
with app.app_context():
|
||||
mail.send(msg)
|
||||
|
||||
|
||||
def send_email(subject, sender, recipients, text_body, html_body):
|
||||
msg = Message(subject, sender=sender, recipients=recipients)
|
||||
msg.body = text_body
|
||||
msg.html = html_body
|
||||
Thread(
|
||||
target=send_async_email, args=(current_app._get_current_object(), msg)
|
||||
).start()
|
|
@ -1,8 +0,0 @@
|
|||
# main Blueprint
|
||||
|
||||
Quelques essais pour la migration.
|
||||
|
||||
TODO: Ne sera pas conservé.
|
||||
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint("main", __name__)
|
||||
|
||||
from app.main import routes
|
|
@ -1,145 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
import pprint
|
||||
from pprint import pprint as pp
|
||||
import functools
|
||||
import thread # essai
|
||||
from zipfile import ZipFile
|
||||
from StringIO import StringIO
|
||||
|
||||
import flask
|
||||
from flask import request, render_template, redirect
|
||||
from flask_login import login_required
|
||||
|
||||
from app.main import bp
|
||||
|
||||
from app.decorators import scodoc7func, admin_required
|
||||
|
||||
context = None
|
||||
|
||||
|
||||
@bp.route("/")
|
||||
@bp.route("/index")
|
||||
def index():
|
||||
return render_template("main/index.html", title=u"Essai Flask")
|
||||
|
||||
|
||||
@bp.route("/test_vue")
|
||||
@login_required
|
||||
def test_vue():
|
||||
return """Vous avez vu. <a href="/">Retour à l'accueil</a>"""
|
||||
|
||||
|
||||
def get_request_infos():
|
||||
return [
|
||||
"<p>request.base_url=%s</p>" % request.base_url,
|
||||
"<p>request.url_root=%s</p>" % request.url_root,
|
||||
"<p>request.query_string=%s</p>" % request.query_string,
|
||||
]
|
||||
|
||||
|
||||
D = {"count": 0}
|
||||
|
||||
# @app.route("/")
|
||||
# @app.route("/index")
|
||||
# def index():
|
||||
# sleep(8)
|
||||
# D["count"] = D.get("count", 0) + 1
|
||||
# return "Hello, World! %s count=%s" % (thread.get_ident(), D["count"])
|
||||
|
||||
|
||||
@bp.route("/zopefunction", methods=["POST", "GET"])
|
||||
@login_required
|
||||
@scodoc7func(context)
|
||||
def a_zope_function(y, x="defaut", REQUEST=None):
|
||||
"""Une fonction typique de ScoDoc7"""
|
||||
H = get_request_infos() + [
|
||||
"<p><b>x=<tt>%s</tt></b></p>" % x,
|
||||
"<p><b>y=<tt>%s</tt></b></p>" % y,
|
||||
"<p><b>URL=<tt>%s</tt></b></p>" % REQUEST.URL,
|
||||
"<p><b>QUERY_STRING=<tt>%s</tt></b></p>" % REQUEST.QUERY_STRING,
|
||||
"<p><b>AUTHENTICATED_USER=<tt>%s</tt></b></p>" % REQUEST.AUTHENTICATED_USER,
|
||||
]
|
||||
H.append("<p><b>form=<tt>%s</tt></b></p>" % REQUEST.form)
|
||||
H.append("<p><b>form[x]=<tt>%s</tt></b></p>" % REQUEST.form.get("x", "non fourni"))
|
||||
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
@bp.route("/zopeform_get")
|
||||
@scodoc7func(context)
|
||||
def a_zope_form_get(REQUEST=None):
|
||||
H = [
|
||||
"""<h2>Formulaire GET</h2>
|
||||
<form action="%s" method="get">
|
||||
x : <input type="text" name="x"/><br/>
|
||||
y : <input type="text" name="y"/><br/>
|
||||
fichier : <input type="file" name="fichier"/><br/>
|
||||
<input type="submit" value="Envoyer"/>
|
||||
</form>
|
||||
"""
|
||||
% flask.url_for("main.a_zope_function")
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
@bp.route("/zopeform_post")
|
||||
@scodoc7func(context)
|
||||
def a_zope_form_post(REQUEST=None):
|
||||
H = [
|
||||
"""<h2>Formulaire POST</h2>
|
||||
<form action="%s" method="post" enctype="multipart/form-data">
|
||||
x : <input type="text" name="x"/><br/>
|
||||
y : <input type="text" name="y"/><br/>
|
||||
fichier : <input type="file" name="fichier"/><br/>
|
||||
<input type="submit" value="Envoyer"/>
|
||||
</form>
|
||||
"""
|
||||
% flask.url_for("main.a_zope_function")
|
||||
]
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
@bp.route("/ScoDoc/<dept_id>/Scolarite/Notes/formsemestre_status")
|
||||
@scodoc7func(context)
|
||||
def formsemestre_status(dept_id=None, formsemestre_id=None, REQUEST=None):
|
||||
"""Essai méthode de département
|
||||
Le contrôle d'accès doit vérifier les bons rôles : ici Ens<dept_id>
|
||||
"""
|
||||
return u"""dept_id=%s , formsemestre_id=%s <a href="/">Retour à l'accueil</a>""" % (
|
||||
dept_id,
|
||||
formsemestre_id,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/hello/world")
|
||||
def hello():
|
||||
H = get_request_infos() + [
|
||||
"<p>Hello, World! %s count=%s</p>" % (thread.get_ident(), D["count"]),
|
||||
]
|
||||
# print(pprint.pformat(dir(request)))
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
@bp.route("/getzip")
|
||||
def getzip():
|
||||
"""Essai renvoi d'un ZIP en Flask"""
|
||||
# La version Zope:
|
||||
# REQUEST.RESPONSE.setHeader("content-type", "application/zip")
|
||||
# REQUEST.RESPONSE.setHeader("content-length", size)
|
||||
# REQUEST.RESPONSE.setHeader(
|
||||
# "content-disposition", 'attachement; filename="monzip.zip"'
|
||||
# )
|
||||
zipdata = StringIO()
|
||||
zipfile = ZipFile(zipdata, "w")
|
||||
zipfile.writestr("fichier1", "un contenu")
|
||||
zipfile.writestr("fichier2", "deux contenus")
|
||||
zipfile.close()
|
||||
data = zipdata.getvalue()
|
||||
size = len(data)
|
||||
# open("/tmp/toto.zip", "w").write(data)
|
||||
# Flask response:
|
||||
r = flask.Response(response=data, status=200, mimetype="application/zip")
|
||||
r.headers["Content-Type"] = "application/zip"
|
||||
r.headers["content-length"] = size
|
||||
r.headers["content-disposition"] = 'attachement; filename="monzip.zip"'
|
||||
return r
|
|
@ -1,7 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
|
||||
"""ScoDoc8 models
|
||||
"""
|
||||
|
||||
# None, at this point
|
||||
# see auth.models for user/role related models
|
|
@ -1,109 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Configuration de ScoDoc (version 2020)
|
||||
NE PAS MODIFIER localement ce fichier !
|
||||
mais éditer /opt/scodoc/var/scodoc/config/scodoc_local.py
|
||||
"""
|
||||
|
||||
from attrdict import AttrDict
|
||||
import bonus_sport
|
||||
|
||||
CONFIG = AttrDict()
|
||||
|
||||
# set to 1 if you want to require INE:
|
||||
CONFIG.always_require_ine = 0
|
||||
|
||||
# The base URL, use only if you are behind a proxy
|
||||
# eg "https://scodoc.example.net/ScoDoc"
|
||||
CONFIG.ABSOLUTE_URL = ""
|
||||
|
||||
# -----------------------------------------------------
|
||||
# -------------- Documents PDF
|
||||
# -----------------------------------------------------
|
||||
|
||||
# Taille du l'image logo: largeur/hauteur (ne pas oublier le . !!!)
|
||||
# W/H XXX provisoire: utilisera PIL pour connaitre la taille de l'image
|
||||
CONFIG.LOGO_FOOTER_ASPECT = 326 / 96.0
|
||||
# Taille dans le document en millimetres
|
||||
CONFIG.LOGO_FOOTER_HEIGHT = 10
|
||||
# Proportions logo (donné ici pour IUTV)
|
||||
CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
|
||||
# Taille verticale dans le document en millimetres
|
||||
CONFIG.LOGO_HEADER_HEIGHT = 28
|
||||
|
||||
|
||||
# Pied de page PDF : un format Python, %(xxx)s est remplacé par la variable xxx.
|
||||
# Les variables définies sont:
|
||||
# day : Day of the month as a decimal number [01,31]
|
||||
# month : Month as a decimal number [01,12].
|
||||
# year : Year without century as a decimal number [00,99].
|
||||
# Year : Year with century as a decimal number.
|
||||
# hour : Hour (24-hour clock) as a decimal number [00,23].
|
||||
# minute: Minute as a decimal number [00,59].
|
||||
#
|
||||
# server_url: URL du serveur ScoDoc
|
||||
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir VERSION.py)
|
||||
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||
|
||||
#
|
||||
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
||||
#
|
||||
|
||||
CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
||||
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
||||
|
||||
# ------------- Capitalisation des UEs -------------
|
||||
# Deux écoles:
|
||||
# - règle "DUT": capitalisation des UE obtenues avec moyenne UE >= 10 ET de toutes les UE
|
||||
# des semestres validés (ADM, ADC, AJ). (conforme à l'arrêté d'août 2005)
|
||||
#
|
||||
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
||||
|
||||
# Si vrai, capitalise toutes les UE des semestres validés (règle "DUT").
|
||||
# CONFIG.CAPITALIZE_ALL_UES = True
|
||||
|
||||
# -----------------------------------------------------
|
||||
# -------------- Personnalisation des pages
|
||||
# -----------------------------------------------------
|
||||
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
||||
# le <body> des pages ScoDoc
|
||||
CONFIG.CUSTOM_HTML_HEADER = ""
|
||||
|
||||
# Fichier html a inclure en fin des pages (juste avant le </body>)
|
||||
CONFIG.CUSTOM_HTML_FOOTER = ""
|
||||
|
||||
# Fichier .html à inclure dans la pages connexion/déconnexion (accueil)
|
||||
# si on veut que ce soit différent (par défaut la même chose)
|
||||
CONFIG.CUSTOM_HTML_HEADER_CNX = CONFIG.CUSTOM_HTML_HEADER
|
||||
CONFIG.CUSTOM_HTML_FOOTER_CNX = CONFIG.CUSTOM_HTML_FOOTER
|
||||
|
||||
# -----------------------------------------------------
|
||||
# -------------- Noms de Lycées
|
||||
# -----------------------------------------------------
|
||||
|
||||
# Fichier de correspondance codelycee -> noms
|
||||
# (chemin relatif au repertoire d'install des sources)
|
||||
CONFIG.ETABL_FILENAME = "config/etablissements.csv"
|
||||
|
||||
# ----------------------------------------------------
|
||||
# -------------- Divers:
|
||||
# ----------------------------------------------------
|
||||
# True for UCAC (étudiants camerounais sans prénoms)
|
||||
CONFIG.ALLOW_NULL_PRENOM = False
|
||||
|
||||
# Taille max des fichiers archive etudiants (en octets)
|
||||
# CONFIG.ETUD_MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||
|
||||
# Si pas de photo et portail, publie l'url (était vrai jusqu'en oct 2016)
|
||||
CONFIG.PUBLISH_PORTAL_PHOTO_URL = False
|
||||
|
||||
# Si > 0: longueur minimale requise des nouveaux mots de passe
|
||||
# (le test cracklib.FascistCheck s'appliquera dans tous les cas)
|
||||
CONFIG.MIN_PASSWORD_LENGTH = 0
|
||||
|
||||
# Ce dictionnaire est fusionné à celui de sco_codes_parcours
|
||||
# pour définir les codes jury et explications associées
|
||||
CONFIG.CODES_EXPL = {
|
||||
# AJ : 'Ajourné (échec)',
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Chargement de la configuration locale
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from notes_log import log
|
||||
import sco_config
|
||||
|
||||
# scodoc_local defines a CONFIG object
|
||||
# here we check if there is a local config file
|
||||
|
||||
|
||||
def load_local_configuration(scodoc_cfg_dir):
|
||||
"""Load local configuration file (if exists)
|
||||
and merge it with CONFIG.
|
||||
"""
|
||||
# this path should be synced with upgrade.sh
|
||||
LOCAL_CONFIG_FILENAME = os.path.join(scodoc_cfg_dir, "scodoc_local.py")
|
||||
LOCAL_CONFIG = None
|
||||
if os.path.exists(LOCAL_CONFIG_FILENAME):
|
||||
if not scodoc_cfg_dir in sys.path:
|
||||
sys.path.insert(1, scodoc_cfg_dir)
|
||||
try:
|
||||
from scodoc_local import CONFIG as LOCAL_CONFIG
|
||||
|
||||
log("imported %s" % LOCAL_CONFIG_FILENAME)
|
||||
except ImportError:
|
||||
log("Error: can't import %s" % LOCAL_CONFIG_FILENAME)
|
||||
del sys.path[1]
|
||||
if LOCAL_CONFIG is None:
|
||||
return
|
||||
# Now merges local config in our CONFIG
|
||||
for x in [x for x in dir(LOCAL_CONFIG) if x[0] != "_"]:
|
||||
v = getattr(LOCAL_CONFIG, x)
|
||||
if not v in sco_config.CONFIG:
|
||||
log("Warning: local config setting unused parameter %s (skipped)" % x)
|
||||
else:
|
||||
if v != sco_config.CONFIG[x]:
|
||||
log("Setting parameter %s from %s" % (x, LOCAL_CONFIG_FILENAME))
|
||||
sco_config.CONFIG[x] = v
|
|
@ -1,19 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""essai: ceci serait un module scodoc/sco_xxx.py
|
||||
"""
|
||||
|
||||
import types
|
||||
|
||||
import sco_utils as scu
|
||||
|
||||
|
||||
def sco_get_version(context, REQUEST=None):
|
||||
"""Une fonction typique de ScoDoc7"""
|
||||
return """<html><body><p>%s</p></body></html>""" % scu.SCOVERSION
|
||||
|
||||
|
||||
def test_refactor(context, x=1):
|
||||
x = context.toto()
|
||||
y = ("context=" + context.module_is_locked("alpha")) + "23"
|
|
@ -1,58 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Definition of ScoDoc 8 permissions
|
||||
used by auth
|
||||
"""
|
||||
# Définition des permissions: ne pas changer les numéros ou l'ordre des lignes !
|
||||
_SCO_PERMISSIONS = (
|
||||
# permission bit, symbol, description
|
||||
# ScoSuperAdmin est utilisé pour:
|
||||
# - ZScoDoc: add/delete departments
|
||||
# - tous rôles lors creation utilisateurs
|
||||
(1 << 1, "ScoSuperAdmin", "Super Administrateur"),
|
||||
(1 << 2, "ScoView", "Voir"),
|
||||
(1 << 3, "ScoEnsView", "Voir les parties pour les enseignants"),
|
||||
(1 << 4, "ScoObservateur", "Observer (accès lecture restreint aux bulletins)"),
|
||||
(1 << 5, "ScoUsersAdmin", "Gérer les utilisateurs"),
|
||||
(1 << 6, "ScoUsersView", "Voir les utilisateurs"),
|
||||
(1 << 7, "ScoChangePreferences", "Modifier les préférences"),
|
||||
(1 << 8, "ScoChangeFormation", "Changer les formations"),
|
||||
(1 << 9, "ScoEditFormationTags", "Tagguer les formations"),
|
||||
(1 << 10, "ScoEditAllNotes", "Modifier toutes les notes"),
|
||||
(1 << 11, "ScoEditAllEvals", "Modifier toutes les evaluations"),
|
||||
(1 << 12, "ScoImplement", "Mettre en place une formation (créer un semestre)"),
|
||||
(1 << 13, "ScoAbsChange", "Saisir des absences"),
|
||||
(1 << 14, "ScoAbsAddBillet", "Saisir des billets d'absences"),
|
||||
# changer adresse/photo ou pour envoyer bulletins par mail ou pour debouche
|
||||
(1 << 15, "ScoEtudChangeAdr", "Changer les addresses d'étudiants"),
|
||||
(1 << 16, "ScoEtudChangeGroups", "Modifier les groupes"),
|
||||
# aussi pour demissions, diplomes:
|
||||
(1 << 17, "ScoEtudInscrit", "Inscrire des étudiants"),
|
||||
# aussi pour archives:
|
||||
(1 << 18, "ScoEtudAddAnnotations", "Éditer les annotations"),
|
||||
(1 << 19, "ScoEntrepriseView", "Voir la section 'entreprises'"),
|
||||
(1 << 20, "ScoEntrepriseChange", "Modifier les entreprises"),
|
||||
(1 << 21, "ScoEditPVJury", "Éditer les PV de jury"),
|
||||
# ajouter maquettes Apogee (=> chef dept et secr):
|
||||
(1 << 22, "ScoEditApo", "Ajouter des maquettes Apogées"),
|
||||
)
|
||||
|
||||
|
||||
class Permission:
|
||||
"Permissions for ScoDoc"
|
||||
NBITS = 1 # maximum bits used (for formatting)
|
||||
ALL_PERMISSIONS = [-1]
|
||||
description = {} # { symbol : blah blah }
|
||||
|
||||
@staticmethod
|
||||
def init_permissions():
|
||||
for (perm, symbol, description) in _SCO_PERMISSIONS:
|
||||
setattr(Permission, symbol, perm)
|
||||
# Crée aussi les attributs dans le module (ScoDoc7 compat)
|
||||
globals()[symbol] = perm
|
||||
Permission.description[symbol] = description
|
||||
Permission.NBITS = len(_SCO_PERMISSIONS)
|
||||
|
||||
|
||||
Permission.init_permissions()
|
|
@ -1,58 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Definition of ScoDoc default roles
|
||||
"""
|
||||
|
||||
from sco_permissions import Permission as p
|
||||
|
||||
SCO_ROLES_DEFAULTS = {
|
||||
"Observateur": (p.ScoObservateur,),
|
||||
"Ens": (
|
||||
p.ScoObservateur,
|
||||
p.ScoView,
|
||||
p.ScoEnsView,
|
||||
p.ScoUsersView,
|
||||
p.ScoEtudAddAnnotations,
|
||||
p.ScoAbsChange,
|
||||
p.ScoAbsAddBillet,
|
||||
p.ScoEntrepriseView,
|
||||
),
|
||||
"Secr": (
|
||||
p.ScoObservateur,
|
||||
p.ScoView,
|
||||
p.ScoUsersView,
|
||||
p.ScoEtudAddAnnotations,
|
||||
p.ScoAbsChange,
|
||||
p.ScoAbsAddBillet,
|
||||
p.ScoEntrepriseView,
|
||||
p.ScoEntrepriseChange,
|
||||
p.ScoEtudChangeAdr,
|
||||
),
|
||||
# Admin est le chef du département, pas le "super admin"
|
||||
# on dit donc lister toutes ses permissions:
|
||||
"Admin": (
|
||||
p.ScoObservateur,
|
||||
p.ScoView,
|
||||
p.ScoEnsView,
|
||||
p.ScoUsersView,
|
||||
p.ScoEtudAddAnnotations,
|
||||
p.ScoAbsChange,
|
||||
p.ScoAbsAddBillet,
|
||||
p.ScoEntrepriseView,
|
||||
p.ScoEntrepriseChange,
|
||||
p.ScoEtudChangeAdr,
|
||||
p.ScoChangeFormation,
|
||||
p.ScoEditFormationTags,
|
||||
p.ScoEditAllNotes,
|
||||
p.ScoEditAllEvals,
|
||||
p.ScoImplement,
|
||||
p.ScoEtudChangeGroups,
|
||||
p.ScoEtudInscrit,
|
||||
p.ScoUsersAdmin,
|
||||
p.ScoChangePreferences,
|
||||
),
|
||||
# Super Admin est un root: création/suppression de départements
|
||||
# _tous_ les droits
|
||||
"SuperAdmin": p.ALL_PERMISSIONS,
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
<h1>Sign In</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
Forgot Your Password?
|
||||
<a href="{{ url_for('auth.reset_password_request') }}">Click to Reset It</a>
|
||||
</p>
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
<h1>Création utilisateur</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
<h1>Reset Your Password</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
<h1>Reset Password</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,60 +0,0 @@
|
|||
{% extends 'bootstrap/base.html' %}
|
||||
|
||||
{% block title %}
|
||||
{% if title %}{{ title }} - ScoDoc{% else %}Welcome to ScoDoc{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block navbar %}
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
|
||||
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{ url_for('main.index') }}">ScoDoc</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="{{ url_for('main.index') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('main.hello') }}">Hello</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if current_user.is_anonymous %}
|
||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||
{% else %}
|
||||
<li>{{current_user.username}}</li>
|
||||
<li><a href="{{ url_for('auth.logout') }}">Logout</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-info" role="alert">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{# application content needs to be provided in the app_content block #}
|
||||
{% block app_content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
{{ moment.include_moment() }}
|
||||
{{ moment.lang(g.locale) }}
|
||||
<script>
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
<p>Bonjour {{ user.username }},</p>
|
||||
<p>
|
||||
Pour réinitialiser votre mot de passe ScoDoc,
|
||||
<a href="{{ url_for('auth.reset_password', token=token, _external=True) }}">
|
||||
cliquez sur ce lien
|
||||
</a>.
|
||||
</p>
|
||||
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web::</p>
|
||||
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
|
||||
|
||||
<p>Si vous n'avez pas demandé à réinitialiser votre mot de passe sur
|
||||
ScoDoc, vous pouvez simplement ignorer ce message.
|
||||
</p>
|
||||
|
||||
|
||||
<p>A bientôt !</p>
|
|
@ -1,12 +0,0 @@
|
|||
Bonjour {{ user.username }},
|
||||
|
||||
Pour réinitialiser votre mot de passe ScoDoc, suivre le lien:
|
||||
|
||||
{{ url_for('auth.reset_password', token=token, _external=True) }}
|
||||
|
||||
|
||||
Si vous n'avez pas demandé à réinitialiser votre mot de passe sur
|
||||
ScoDoc, vous pouvez simplement ignorer ce message.
|
||||
|
||||
A bientôt !
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% import 'bootstrap/wtf.html' as wtf %}
|
||||
|
||||
{% block app_content %}
|
||||
<h1>Protoype ScoDoc 8: accueil</h1>
|
||||
<div class="row">
|
||||
<h2>Avec login requis</h2>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('main.test_vue') }}"><tt>test_vue</tt>, login requis</a></li>
|
||||
<li><a href="{{ url_for('main.a_zope_function', y=22) }}">a_zope_function</a> : affichage objets "Zope"</li>
|
||||
<li><a href="{{ url_for('main.a_zope_function', x=11, y=22) }}">a_zope_function?x=22</a> : avec parametre
|
||||
<tt>x=11, y=22</tt>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Sans login</h2>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('main.a_zope_form_get') }}"><tt>a_zope_form_get</tt></a> : formulaire GET ala ScoDoc non
|
||||
protégé renvoyant vers une page protégée</li>
|
||||
<li><a href="{{ url_for('main.a_zope_form_post') }}"><tt>a_zope_form_post</tt></a> : formulaire POST ala ScoDoc
|
||||
non protégé renvoyant vers une page protégée</li>
|
||||
|
||||
|
||||
<li><a href="{{ url_for('main.formsemestre_status', dept_id='RT') }}"><tt>formsemestre_status</tt></a> : a-t-on
|
||||
le rôle EnsRT ?
|
||||
</li>
|
||||
<li><a href="ScoDoc/RT/Scolarite/Notes/essai"><tt>Notes/essai</tt> : test "notes", url
|
||||
manuelle</a></li>
|
||||
<li><a href="{{ url_for('notes.essai2' , scodoc_dept='RT') }}"><tt>Notes/essai2</tt></a> : permission
|
||||
ScoImplement dans RT
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
"""ScoDoc Flask views
|
||||
"""
|
||||
from flask import Blueprint
|
||||
|
||||
scolar_bp = Blueprint("scolar", __name__)
|
||||
notes_bp = Blueprint("notes", __name__)
|
||||
absences_bp = Blueprint("absences", __name__)
|
||||
essais_bp = Blueprint("essais", __name__)
|
||||
|
||||
from app.views import notes, scolar, absences
|
File diff suppressed because it is too large
Load Diff
|
@ -1,65 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
"""
|
||||
Module Essais: divers essais pour la migration vers Flask
|
||||
|
||||
Emmanuel Viennet, 2021
|
||||
"""
|
||||
|
||||
from flask import g
|
||||
from flask import current_app
|
||||
|
||||
from app.decorators import (
|
||||
scodoc7func,
|
||||
ScoDoc7Context,
|
||||
permission_required,
|
||||
admin_required,
|
||||
login_required,
|
||||
)
|
||||
from app.auth.models import Permission
|
||||
|
||||
from app.views import notes_bp as bp
|
||||
|
||||
# import sco_core deviendra:
|
||||
from app.scodoc import sco_core
|
||||
|
||||
context = ScoDoc7Context(globals())
|
||||
|
||||
|
||||
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple")
|
||||
@scodoc7func(context)
|
||||
def sco_exemple(etudid="NON"):
|
||||
"""Un exemple de fonction ScoDoc 7"""
|
||||
return """<html>
|
||||
<body><h1>ScoDoc 7 rules !</h1>
|
||||
<p>etudid=%(etudid)s</p>
|
||||
<p>g.scodoc_dept=%(scodoc_dept)s</p>
|
||||
</body>
|
||||
</html>
|
||||
""" % {
|
||||
"etudid": etudid,
|
||||
"scodoc_dept": g.scodoc_dept,
|
||||
}
|
||||
|
||||
|
||||
# En ScoDoc 7, on a souvent des vues qui en appellent d'autres
|
||||
# avec context.sco_exemple( etudid="E12" )
|
||||
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple2")
|
||||
@login_required
|
||||
@scodoc7func(context)
|
||||
def sco_exemple2():
|
||||
return "Exemple 2" + context.sco_exemple(etudid="deux")
|
||||
|
||||
|
||||
# Test avec un seul argument REQUEST positionnel
|
||||
@bp.route("/<scodoc_dept>/Scolarite/sco_get_version")
|
||||
@scodoc7func(context)
|
||||
def sco_get_version(REQUEST):
|
||||
return sco_core.sco_get_version(REQUEST)
|
||||
|
||||
|
||||
# Fonction ressemblant à une méthode Zope protégée
|
||||
@bp.route("/<scodoc_dept>/Scolarite/sco_test_view")
|
||||
@scodoc7func(context)
|
||||
@permission_required(Permission.ScoView)
|
||||
def sco_test_view(REQUEST=None):
|
||||
return """Vous avez vu sco_test_view !"""
|
3544
app/views/notes.py
3544
app/views/notes.py
File diff suppressed because it is too large
Load Diff
2063
app/views/scolar.py
2063
app/views/scolar.py
File diff suppressed because it is too large
Load Diff
|
@ -45,16 +45,9 @@ def bonus_iutv(notes_sport, coefs, infos=None):
|
|||
return bonus
|
||||
|
||||
|
||||
def bonus_direct(notes_sport, coefs, infos=None):
|
||||
"""Un bonus direct et sans chichis: les points sont directement ajoutés à la moyenne générale.
|
||||
Les coefficients sont ignorés: tous les points de bonus sont sommés.
|
||||
(rappel: la note est ramenée sur 20 avant application).
|
||||
"""
|
||||
return sum(notes_sport)
|
||||
|
||||
|
||||
def bonus_iut_stdenis(notes_sport, coefs, infos=None):
|
||||
"""Semblable à bonus_iutv mais sans coefficients et total limité à 0.5 points."""
|
||||
"""Semblable à bonus_iutv mais sans coefficients et total limité à 0.5 points.
|
||||
"""
|
||||
points = sum([x - 10 for x in notes_sport if x > 10]) # points au dessus de 10
|
||||
bonus = points * 0.05 # ou / 20
|
||||
return min(bonus, 0.5) # bonus limité à 1/2 point
|
||||
|
@ -69,7 +62,7 @@ def bonus_colmar(notes_sport, coefs, infos=None):
|
|||
sur 20 obtenus dans chacune des matières optionnelles sont cumulés
|
||||
dans la limite de 10 points. 5% de ces points cumulés s'ajoutent à
|
||||
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||
|
||||
|
||||
"""
|
||||
# les coefs sont ignorés
|
||||
points = sum([x - 10 for x in notes_sport if x > 10])
|
||||
|
@ -80,7 +73,7 @@ def bonus_colmar(notes_sport, coefs, infos=None):
|
|||
|
||||
def bonus_iutva(notes_sport, coefs, infos=None):
|
||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Ville d'Avray
|
||||
|
||||
|
||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||
de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.
|
||||
Si la note est >= 10 et < 12, bonus de 0.1 point
|
||||
|
@ -100,13 +93,42 @@ def bonus_iutva(notes_sport, coefs, infos=None):
|
|||
return 0
|
||||
|
||||
|
||||
# XXX Inutilisé (mai 2020) ? à confirmer avant suppression XXX
|
||||
# def bonus_iut1grenoble_v0(notes_sport, coefs, infos=None):
|
||||
# """Calcul bonus sport IUT Grenoble sur la moyenne générale
|
||||
#
|
||||
# La note de sport de nos étudiants va de 0 à 5 points.
|
||||
# Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
|
||||
# Par exemple : note de sport 2/5 : chaque UE sera augmentée de 2%, ainsi que la moyenne générale.
|
||||
#
|
||||
# Calcul ici du bonus sur moyenne générale et moyennes d'UE non capitalisées.
|
||||
# """
|
||||
# # les coefs sont ignorés
|
||||
# # notes de 0 à 5
|
||||
# points = sum([x for x in notes_sport])
|
||||
# factor = (points / 4.0) / 100.0
|
||||
# bonus = infos["moy"] * factor
|
||||
# # Modifie les moyennes de toutes les UE:
|
||||
# for ue_id in infos["moy_ues"]:
|
||||
# ue_status = infos["moy_ues"][ue_id]
|
||||
# if ue_status["sum_coefs"] > 0:
|
||||
# # modifie moyenne UE ds semestre courant
|
||||
# ue_status["cur_moy_ue"] = ue_status["cur_moy_ue"] * (1.0 + factor)
|
||||
# if not ue_status["is_capitalized"]:
|
||||
# # si non capitalisee, modifie moyenne prise en compte
|
||||
# ue_status["moy"] = ue_status["cur_moy_ue"]
|
||||
#
|
||||
# # open('/tmp/log','a').write( pprint.pformat(ue_status) + '\n\n' )
|
||||
# return bonus
|
||||
|
||||
|
||||
def bonus_iut1grenoble_2017(notes_sport, coefs, infos=None):
|
||||
"""Calcul bonus sport IUT Grenoble sur la moyenne générale (version 2017)
|
||||
|
||||
La note de sport de nos étudiants va de 0 à 5 points.
|
||||
|
||||
La note de sport de nos étudiants va de 0 à 5 points.
|
||||
Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
|
||||
Par exemple : note de sport 2/5 : la moyenne générale sera augmentée de 2%.
|
||||
|
||||
|
||||
Calcul ici du bonus sur moyenne générale
|
||||
"""
|
||||
# les coefs sont ignorés
|
||||
|
@ -140,14 +162,14 @@ def bonus_lille(notes_sport, coefs, infos=None):
|
|||
def bonus_iutlh(notes_sport, coefs, infos=None):
|
||||
"""Calcul bonus sport IUT du Havre sur moyenne générale et UE
|
||||
|
||||
La note de sport de nos étudiants va de 0 à 20 points.
|
||||
m2=m1*(1+0.005*((10-N1)+(10-N2))
|
||||
m2 : Nouvelle moyenne de l'unité d'enseignement si note de sport et/ou de langue supérieure à 10
|
||||
m1 : moyenne de l'unité d'enseignement avant bonification
|
||||
N1 : note de sport si supérieure à 10
|
||||
N2 : note de seconde langue si supérieure à 10
|
||||
Par exemple : sport 15/20 et langue 12/20 : chaque UE sera multipliée par 1+0.005*7, ainsi que la moyenne générale.
|
||||
Calcul ici de la moyenne générale et moyennes d'UE non capitalisées.
|
||||
La note de sport de nos étudiants va de 0 à 20 points.
|
||||
m2=m1*(1+0.005*((10-N1)+(10-N2))
|
||||
m2 : Nouvelle moyenne de l'unité d'enseignement si note de sport et/ou de langue supérieure à 10
|
||||
m1 : moyenne de l'unité d'enseignement avant bonification
|
||||
N1 : note de sport si supérieure à 10
|
||||
N2 : note de seconde langue si supérieure à 10
|
||||
Par exemple : sport 15/20 et langue 12/20 : chaque UE sera multipliée par 1+0.005*7, ainsi que la moyenne générale.
|
||||
Calcul ici de la moyenne générale et moyennes d'UE non capitalisées.
|
||||
"""
|
||||
# les coefs sont ignorés
|
||||
points = sum([x - 10 for x in notes_sport if x > 10])
|
||||
|
@ -183,8 +205,8 @@ def bonus_tours(notes_sport, coefs, infos=None):
|
|||
def bonus_iutr(notes_sport, coefs, infos=None):
|
||||
"""Calcul du bonus , regle de l'IUT de Roanne (contribuée par Raphael C., nov 2012)
|
||||
|
||||
Le bonus est compris entre 0 et 0.35 point.
|
||||
cette procédure modifie la moyenne de chaque UE capitalisable.
|
||||
Le bonus est compris entre 0 et 0.35 point.
|
||||
cette procédure modifie la moyenne de chaque UE capitalisable.
|
||||
|
||||
"""
|
||||
# modifie les moyennes de toutes les UE:
|
||||
|
@ -238,7 +260,7 @@ def bonus_saint_etienne(notes_sport, coefs, infos=None):
|
|||
"""IUT de Saint-Etienne (jan 2014)
|
||||
Nous avons différents types de bonification
|
||||
bonfication Sport / Associations
|
||||
coopératives de département / Bureau Des Étudiants
|
||||
coopératives de département / Bureau Des Étudiants
|
||||
/ engagement citoyen / Langues optionnelles
|
||||
Nous ajoutons sur le bulletin une bonification qui varie entre 0,1 et 0,3 ou 0,35 pour chaque item
|
||||
la bonification totale ne doit pas excéder les 0,6 point.
|
||||
|
@ -256,9 +278,9 @@ def bonus_saint_etienne(notes_sport, coefs, infos=None):
|
|||
|
||||
|
||||
def bonus_iutTarbes(notes_sport, coefs, infos=None):
|
||||
"""Calcul bonus modules optionnels
|
||||
"""Calcul bonus modules optionnels
|
||||
(sport, Langues, action sociale, Théâtre), règle IUT Tarbes
|
||||
Les coefficients ne sont pas pris en compte,
|
||||
Les coefficients ne sont pas pris en compte,
|
||||
seule la meilleure note est prise en compte
|
||||
le 1/30ème des points au-dessus de 10 sur 20 est retenu et s'ajoute à
|
||||
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||
|
@ -386,7 +408,7 @@ def bonus_iutbethune(notes_sport, coefs, infos=None):
|
|||
def bonus_demo(notes_sport, coefs, infos=None):
|
||||
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
||||
et aider les développeurs.
|
||||
Les informations sont placées dans le fichier /tmp/scodoc_bonus.log
|
||||
Les informations sont placées dans le fichier /tmp/scodoc_bonus.log
|
||||
qui est ECRASE à chaque appel.
|
||||
*** Ne pas utiliser en production !!! ***
|
||||
"""
|
43
config.py
43
config.py
|
@ -1,43 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.dirname(__file__))
|
||||
load_dotenv(os.path.join(BASEDIR, ".env"))
|
||||
|
||||
|
||||
class ConfigClass(object):
|
||||
"""General configuration. Mostly loaded from environment via .env"""
|
||||
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY") or "un-grand-secret-introuvable"
|
||||
SQLALCHEMY_DATABASE_URI = (
|
||||
os.environ.get("USERS_DATABASE_URI")
|
||||
or "postgresql://scodoc@localhost:5432/SCO8USERS"
|
||||
)
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
LOG_TO_STDOUT = os.environ.get("LOG_TO_STDOUT")
|
||||
MAIL_SERVER = os.environ.get("MAIL_SERVER")
|
||||
MAIL_PORT = int(os.environ.get("MAIL_PORT") or 25)
|
||||
MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS") is not None
|
||||
MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
|
||||
MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD")
|
||||
LANGUAGES = ["fr", "en"] # unused for now
|
||||
SCODOC_ADMIN_MAIL = os.environ.get("SCODOC_ADMIN_MAIL")
|
||||
SCODOC_ADMIN_LOGIN = os.environ.get("SCODOC_ADMIN_LOGIN") or "admin"
|
||||
ADMINS = [SCODOC_ADMIN_MAIL]
|
||||
SCODOC_ERR_MAIL = os.environ.get("SCODOC_ERR_MAIL")
|
||||
BOOTSTRAP_SERVE_LOCAL = os.environ.get("BOOTSTRAP_SERVE_LOCAL")
|
||||
# for ScoDoc 7 compat (à changer)
|
||||
INSTANCE_HOME = os.environ.get("INSTANCE_HOME", "/opt/scodoc")
|
||||
|
||||
# For legacy ScoDoc7 installs: postgresql user
|
||||
SCODOC7_SQL_USER = os.environ.get("SCODOC7_SQL_USER", "www-data")
|
||||
DEFAULT_SQL_PORT = os.environ.get("DEFAULT_SQL_PORT", "5432")
|
||||
|
||||
def __init__(self):
|
||||
"""Used to build some config variable at startup time"""
|
||||
self.SCODOC_VAR_DIR = os.path.join(self.INSTANCE_HOME, "var", "scodoc")
|
||||
|
||||
|
||||
Config = ConfigClass()
|
|
@ -34,11 +34,9 @@ export POSTGRES_USER=www-data
|
|||
if [ "${debian_version}" = "10" ]
|
||||
then
|
||||
PSQL=/usr/lib/postgresql/11/bin/psql
|
||||
export POSTGRES_SERVICE="postgresql@11-main.service"
|
||||
elif [ "${debian_version}" = "9" ]
|
||||
then
|
||||
PSQL=/usr/lib/postgresql/9.6/bin/psql
|
||||
export POSTGRES_SERVICE="postgresql"
|
||||
elif [ "${debian_version}" = "8" ]
|
||||
then
|
||||
PSQL=/usr/lib/postgresql/9.4/bin/psql
|
||||
|
@ -54,7 +52,7 @@ elif [ "${debian_version}" = "5" ]
|
|||
else
|
||||
PSQL=/usr/lib/postgresql/8.1/bin/psql
|
||||
fi
|
||||
export PSQL
|
||||
|
||||
|
||||
# tcp port for SQL server (under Debian 4, 5432 or 5433 for 8.1 if 7.4 also installed !)
|
||||
# Important note: if changed, you should probably also change it in
|
||||
|
|
|
@ -5,16 +5,10 @@
|
|||
source config.sh
|
||||
source utils.sh
|
||||
|
||||
check_uid_root "$0"
|
||||
check_uid_root $0
|
||||
|
||||
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
||||
|
||||
# La variable POSTGRES_SERVICE doit être positionnée dans config.sh
|
||||
# suivant la version de Debian et de postgresql
|
||||
[ -z "${POSTGRES_SERVICE}" ] && die "incompatible Debian version"
|
||||
|
||||
cat "$SCODOC_DIR/config/etc/scodoc.service" | sed 's/{{postgresql}}/'"${POSTGRES_SERVICE}"'/g' > /etc/systemd/system/scodoc.service
|
||||
|
||||
cp $SCODOC_DIR/config/etc/scodoc.service /etc/systemd/system
|
||||
systemctl enable scodoc.service
|
||||
|
||||
echo "A partir de maintenant, utiliser"
|
||||
|
|
|
@ -11,6 +11,6 @@ source utils.sh
|
|||
echo 'Creating postgresql database'
|
||||
|
||||
# ---
|
||||
echo 'Creating postgresql database ' "$db_name"
|
||||
createdb -E UTF-8 -p "$POSTGRES_PORT" -O "$POSTGRES_USER" "$db_name"
|
||||
echo 'Creating postgresql database ' $db_name
|
||||
createdb -E UTF-8 -p $POSTGRES_PORT -O $POSTGRES_USER $db_name
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
source config.sh
|
||||
source utils.sh
|
||||
|
||||
check_uid_root "$0"
|
||||
check_uid_root $0
|
||||
|
||||
# --- Ensure postgres user www-data exists
|
||||
init_postgres_user
|
||||
|
@ -21,8 +21,8 @@ db_name=SCOUSERS
|
|||
|
||||
echo 'Creating postgresql database ' $db_name
|
||||
|
||||
su -c "createdb -E UTF-8 -O $POSTGRES_USER -p $POSTGRES_PORT $db_name" "$POSTGRES_SUPERUSER"
|
||||
su -c "createdb -E UTF-8 -O $POSTGRES_USER -p $POSTGRES_PORT $db_name" $POSTGRES_SUPERUSER
|
||||
|
||||
echo 'Initializing tables in database ' "$db_name"
|
||||
echo su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" "$POSTGRES_USER"
|
||||
su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" "$POSTGRES_USER"
|
||||
echo 'Initializing tables in database ' $db_name
|
||||
echo su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" $POSTGRES_USER
|
||||
su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" $POSTGRES_USER
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# Avec option:
|
||||
# -a : sauve aussi les bases de données
|
||||
#
|
||||
DEST_ADDRESS=emmanuel.viennet@gmail.com
|
||||
DEST_ADDRESS=emmanuel.viennet@univ-paris13.fr
|
||||
|
||||
INSTANCE_DIR=/opt/scodoc
|
||||
|
||||
|
@ -36,7 +36,7 @@ while getopts ":d:aunh" opt; do
|
|||
SEND_BY_MAIL=0
|
||||
;;
|
||||
d)
|
||||
DEPTS_TO_SAVE=$( join_by ' ' "$DEPTS_TO_SAVE" "$OPTARG" )
|
||||
DEPTS_TO_SAVE=$( join_by ' ' $DEPTS_TO_SAVE $OPTARG )
|
||||
;;
|
||||
h)
|
||||
echo "Diagnostic installation ScoDoc"
|
||||
|
@ -71,7 +71,7 @@ then
|
|||
apt-get install sharutils
|
||||
fi
|
||||
|
||||
mkdir "$TMP"
|
||||
mkdir $TMP
|
||||
|
||||
# Files to copy:
|
||||
FILES="/etc/hosts /etc/debian_version /etc/apt /etc/apache2"
|
||||
|
@ -91,33 +91,33 @@ echo "left in ${TMP}"
|
|||
# -------------------------------------
|
||||
|
||||
copy_log() {
|
||||
if [ -e "$1" ]
|
||||
if [ -e $1 ]
|
||||
then
|
||||
cp "$1" "$TMP"/scodoc_logs/
|
||||
cp $1 $TMP/scodoc_logs/
|
||||
fi
|
||||
}
|
||||
mkdir "$TMP"/scodoc_logs/
|
||||
copy_log /opt/scodoc/log/event.log
|
||||
copy_log /opt/scodoc/log/event.log.1
|
||||
copy_log /opt/scodoc/log/notes.log
|
||||
copy_log /opt/scodoc/log/notes.log.1
|
||||
mkdir $TMP/scodoc_logs/
|
||||
copy_log /opt/scodoc/instance/log/event.log
|
||||
copy_log /opt/scodoc/instance/log/event.log.1
|
||||
copy_log /opt/scodoc/instance/log/notes.log
|
||||
copy_log /opt/scodoc/instance/log/notes.log.1
|
||||
|
||||
|
||||
# -------------------------------------
|
||||
# Linux System Configuration
|
||||
# -------------------------------------
|
||||
|
||||
iptables -L > "$TMP"/iptables.out
|
||||
ip a > "$TMP"/ifconfig.out
|
||||
ps auxww > "$TMP"/ps.out
|
||||
df -h > "$TMP"/df.out
|
||||
dpkg -l > "$TMP"/dpkg.lst
|
||||
iptables -L > $TMP/iptables.out
|
||||
ip a > $TMP/ifconfig.out
|
||||
ps auxww > $TMP/ps.out
|
||||
df -h > $TMP/df.out
|
||||
dpkg -l > $TMP/dpkg.lst
|
||||
|
||||
(cd /opt/scodoc/Products/ScoDoc; svn status > "$TMP"/svn.status)
|
||||
(cd /opt/scodoc/Products/ScoDoc; svn diff > "$TMP"/svn.diff)
|
||||
(cd /opt/scodoc/instance/Products/ScoDoc; svn status > $TMP/svn.status)
|
||||
(cd /opt/scodoc/instance/Products/ScoDoc; svn diff > $TMP/svn.diff)
|
||||
|
||||
(cd /opt/scodoc/Products/ScoDoc; svnversion > "$TMP"/svn.version)
|
||||
ls -laR /opt/scodoc/Products/ScoDoc > "$TMP"/ls-laR
|
||||
(cd /opt/scodoc/instance/Products/ScoDoc; svnversion > $TMP/svn.version)
|
||||
ls -laR /opt/scodoc/instance/Products/ScoDoc > $TMP/ls-laR
|
||||
|
||||
|
||||
# -------------------------------------
|
||||
|
@ -126,7 +126,7 @@ ls -laR /opt/scodoc/Products/ScoDoc > "$TMP"/ls-laR
|
|||
(su postgres -c "psql -l") > "${TMP}/psql-l.out"
|
||||
for dept in "${INSTANCE_DIR}"/var/scodoc/config/depts/*.cfg
|
||||
do
|
||||
cnx=$(cat "$dept")
|
||||
cnx=$(cat $dept)
|
||||
(su postgres -c "echo '\dt' | psql -d $cnx") > "${TMP}/psql-$(basename ${dept%%.*}).out"
|
||||
done
|
||||
|
||||
|
@ -137,14 +137,14 @@ done
|
|||
# copy files:
|
||||
for f in $FILES
|
||||
do
|
||||
cp -R "$f" "$TMP"
|
||||
cp -R $f $TMP
|
||||
done
|
||||
|
||||
|
||||
# -------------------------------------
|
||||
# Optionally save dept(s) database(s)
|
||||
# -------------------------------------
|
||||
DEPTS_TO_SAVE=$(echo "${DEPTS_TO_SAVE}" | tr ' ' '\n' | sort | uniq)
|
||||
DEPTS_TO_SAVE=$(echo ${DEPTS_TO_SAVE} | tr ' ' '\n' | sort | uniq)
|
||||
|
||||
# Dump database of a dept (eg "RT")
|
||||
function dump_dept_db {
|
||||
|
@ -176,10 +176,10 @@ fi
|
|||
# Archive all stuff to /tmp
|
||||
# -------------------------------------
|
||||
|
||||
tar cfz "$TMP".tgz "$TMP"
|
||||
tar cfz $TMP.tgz $TMP
|
||||
|
||||
echo
|
||||
echo "Fichier de diagnostic: "$TMP".tgz"
|
||||
echo "Fichier de diagnostic: $TMP.tgz"
|
||||
echo
|
||||
|
||||
# If no mail, stop here
|
||||
|
@ -197,9 +197,9 @@ fi
|
|||
|
||||
#requires: basename,date,md5sum,sed,sendmail,uuencode
|
||||
function fappend {
|
||||
echo "$2">>"$1";
|
||||
echo "$2">>$1;
|
||||
}
|
||||
YYYYMMDD=$(date +%Y%m%d)
|
||||
YYYYMMDD=`date +%Y%m%d`
|
||||
|
||||
# CHANGE THESE
|
||||
TOEMAIL=$DEST_ADDRESS
|
||||
|
@ -212,45 +212,45 @@ MIMETYPE="application/gnutar" #if not sure, use http://www.webmaster-toolkit.com
|
|||
|
||||
# DON'T CHANGE ANYTHING BELOW
|
||||
TMP="/tmp/tmpfil_123"$RANDOM;
|
||||
BOUNDARY=$(date +%s|md5sum)
|
||||
BOUNDARY=`date +%s|md5sum`
|
||||
BOUNDARY=${BOUNDARY:0:32}
|
||||
FILENAME=$(basename "$ATTACHMENT")
|
||||
FILENAME=`basename $ATTACHMENT`
|
||||
|
||||
rm -rf "$TMP"
|
||||
uuencode --base64 "$FILENAME" < "$ATTACHMENT" >"$TMP"
|
||||
sed -i -e '1,1d' -e '$d' "$TMP"; #removes first & last lines from "$TMP"
|
||||
DATA=$(cat "$TMP")
|
||||
rm -rf $TMP;
|
||||
cat $ATTACHMENT|uuencode --base64 $FILENAME>$TMP;
|
||||
sed -i -e '1,1d' -e '$d' $TMP;#removes first & last lines from $TMP
|
||||
DATA=`cat $TMP`
|
||||
|
||||
rm -rf "$TMP";
|
||||
fappend "$TMP" "From: $FREMAIL";
|
||||
fappend "$TMP" "To: $TOEMAIL";
|
||||
fappend "$TMP" "Reply-To: $FREMAIL";
|
||||
fappend "$TMP" "Subject: $SUBJECT";
|
||||
fappend "$TMP" "Content-Type: multipart/mixed; boundary=\""$BOUNDARY"\"";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "This is a MIME formatted message. If you see this text it means that your";
|
||||
fappend "$TMP" "email software does not support MIME formatted messages.";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "--$BOUNDARY";
|
||||
fappend "$TMP" "Content-Type: text/plain; charset=ISO-8859-1; format=flowed";
|
||||
fappend "$TMP" "Content-Transfer-Encoding: 7bit";
|
||||
fappend "$TMP" "Content-Disposition: inline";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "$MSGBODY";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "--$BOUNDARY";
|
||||
fappend "$TMP" "Content-Type: $MIMETYPE; name=\"$FILENAME\"";
|
||||
fappend "$TMP" "Content-Transfer-Encoding: base64";
|
||||
fappend "$TMP" "Content-Disposition: attachment; filename=\"$FILENAME\";";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "$DATA";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "--$BOUNDARY--";
|
||||
fappend "$TMP" "";
|
||||
fappend "$TMP" "";
|
||||
#cat "$TMP">out.txt
|
||||
cat "$TMP"|sendmail -t -f none@example.com;
|
||||
rm "$TMP";
|
||||
rm -rf $TMP;
|
||||
fappend $TMP "From: $FREMAIL";
|
||||
fappend $TMP "To: $TOEMAIL";
|
||||
fappend $TMP "Reply-To: $FREMAIL";
|
||||
fappend $TMP "Subject: $SUBJECT";
|
||||
fappend $TMP "Content-Type: multipart/mixed; boundary=\""$BOUNDARY"\"";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "This is a MIME formatted message. If you see this text it means that your";
|
||||
fappend $TMP "email software does not support MIME formatted messages.";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "--$BOUNDARY";
|
||||
fappend $TMP "Content-Type: text/plain; charset=ISO-8859-1; format=flowed";
|
||||
fappend $TMP "Content-Transfer-Encoding: 7bit";
|
||||
fappend $TMP "Content-Disposition: inline";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "$MSGBODY";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "--$BOUNDARY";
|
||||
fappend $TMP "Content-Type: $MIMETYPE; name=\"$FILENAME\"";
|
||||
fappend $TMP "Content-Transfer-Encoding: base64";
|
||||
fappend $TMP "Content-Disposition: attachment; filename=\"$FILENAME\";";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "$DATA";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "--$BOUNDARY--";
|
||||
fappend $TMP "";
|
||||
fappend $TMP "";
|
||||
#cat $TMP>out.txt
|
||||
cat $TMP|sendmail -t -f none@example.com;
|
||||
rm $TMP;
|
||||
|
||||
|
|
|
@ -15,15 +15,15 @@ then
|
|||
fi
|
||||
|
||||
|
||||
echo "Changing to directory " "$SCODOC_DIR"/config
|
||||
cd "$SCODOC_DIR"/config || { echo "directory does not exist"; exit 1; }
|
||||
echo "Changing to directory " $SCODOC_DIR/config
|
||||
cd $SCODOC_DIR/config
|
||||
|
||||
echo "Stopping ScoDoc..."
|
||||
scodocctl stop
|
||||
|
||||
# DROITS
|
||||
echo -n "Verification des droits: proprietaire www-data ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo 'changing owner to www-data'
|
||||
|
@ -31,7 +31,7 @@ then
|
|||
fi
|
||||
|
||||
echo -n 'Suppression des backups des sources (*~) ? (y/n) [y] '
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
/bin/rm -f ../*~ ../*/*~
|
||||
|
@ -40,7 +40,7 @@ fi
|
|||
|
||||
# SVN
|
||||
echo -n "svn update ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo 'Updating from SVN...'
|
||||
|
@ -50,7 +50,7 @@ fi
|
|||
|
||||
# DEPARTEMENTS (maintenant inutile car dans /var)
|
||||
echo -n "Supprimer les (anciennes) configs de departements ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo "moving " depts/*.cfg "to /tmp"
|
||||
|
@ -59,7 +59,7 @@ fi
|
|||
|
||||
# .../var/
|
||||
echo -n "Supprimer et recréer .../var (archives, photos, configs, ...) ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo "moving ../../../var/scodoc to /tmp"
|
||||
|
@ -73,7 +73,7 @@ fi
|
|||
|
||||
# LOGS ZOPE
|
||||
echo -n "Effacer les logs de Zope et ScoDoc ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
(cd ../../../log/; ./purge)
|
||||
|
@ -81,7 +81,7 @@ fi
|
|||
|
||||
# IMAGE Data.fs
|
||||
echo -n "Recopier le Data.fs original ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo "moving Data.fs to /tmp"
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
# ScoDoc7 service
|
||||
# Zope based
|
||||
# Depends on {{postgresql}} (replaced by installation script by
|
||||
# postgresql@11-main.service on Debian 10
|
||||
# postgresql on Debian <= 9
|
||||
# => is restarted when {{postgresql}} restarts
|
||||
# Depends on postgresql
|
||||
# => is restarted when postgresql restarts
|
||||
#
|
||||
[Unit]
|
||||
Description=ScoDoc 7 service
|
||||
After=network.target {{postgresql}}
|
||||
Requires={{postgresql}}
|
||||
PartOf={{postgresql}}
|
||||
After=network.target postgresql@11-main.service
|
||||
Requires=postgresql@11-main.service
|
||||
PartOf=postgresql@11-main.service
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
|
@ -23,4 +21,4 @@ ExecStop=/opt/scodoc/bin/zopectl stop
|
|||
ExecReload=/opt/scodoc/bin/zopectl restart
|
||||
|
||||
[Install]
|
||||
WantedBy={{postgresql}}
|
||||
WantedBy=postgresql@11-main.service
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Get version information
|
||||
# Use VERSION.py, last commit, diff, and last upstream commit date
|
||||
|
||||
|
||||
source config.sh
|
||||
source utils.sh
|
||||
|
||||
# Source code version:
|
||||
x=$(grep SCOVERSION ../VERSION.py) || terminate "can't access VERSION.py" 1
|
||||
x=${x#*\"}
|
||||
src_version=${x%\"*}
|
||||
|
||||
# last commit
|
||||
git_last_commit_hash=$(git log -1 --format=%h)
|
||||
git_last_commit_date=$(git log -1 --format=%ci)
|
||||
|
||||
git_up_commit_hash=$(git log -1 --format=%h origin/ScoDoc8)
|
||||
git_up_commit_date=$(git log -1 --format=%ci origin/ScoDoc8)
|
||||
|
||||
# Check if git has local changes
|
||||
nchanges=$(git status --porcelain | grep -c -v '^??')
|
||||
if [ "$nchanges" -gt 0 ]
|
||||
then
|
||||
has_local_changes="yes"
|
||||
else
|
||||
has_local_changes="no"
|
||||
fi
|
||||
|
||||
# Synthetic one-line version:
|
||||
sco_version="$src_version ($git_up_commit_hash) $git_up_commit_date"
|
||||
if [ "$has_local_changes" = "yes" ]
|
||||
then
|
||||
sco_version="$sco_version (modified)"
|
||||
fi
|
||||
|
||||
#
|
||||
if [ "$1" = "-s" ]
|
||||
then
|
||||
echo "$sco_version"
|
||||
else
|
||||
echo src_version: "$src_version"
|
||||
echo git_last_commit_hash: "$git_last_commit_hash"
|
||||
echo git_last_commit_date: "$git_last_commit_date"
|
||||
echo git_up_commit_hash: "$git_up_commit_hash"
|
||||
echo git_up_commit_date: "$git_up_commit_date"
|
||||
echo has_local_diffs: "$has_local_changes"
|
||||
echo sco_version: "$sco_version"
|
||||
fi
|
|
@ -8,16 +8,15 @@
|
|||
source config.sh
|
||||
source utils.sh
|
||||
|
||||
if [ "$(id -nu)" != "$POSTGRES_USER" ]
|
||||
if [ $(id -nu) != $POSTGRES_USER ]
|
||||
then
|
||||
echo "$0: script must be runned as user $POSTGRES_USER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
echo 'Initializing tables in database ' "$db_name"
|
||||
$PSQL -U "$POSTGRES_USER" -p "$POSTGRES_PORT" "$db_name" -f "$SCODOC_DIR"/misc/createtables.sql
|
||||
echo 'Initializing tables in database ' $db_name
|
||||
$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name -f $SCODOC_DIR/misc/createtables.sql
|
||||
|
||||
|
||||
# Set DeptName in preferences:
|
||||
echo "insert into sco_prefs (name, value) values ('DeptName', '"${DEPT}\'\) | $PSQL -U "$POSTGRES_USER" -p "$POSTGRES_PORT" "$db_name"
|
||||
echo "insert into sco_prefs (name, value) values ('DeptName', '"${DEPT}\'\) | $PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
#
|
||||
# ScoDoc: install third-party software necessary for our installation
|
||||
# starting for a minimal Debian (Buster, 10.0) install.
|
||||
# starting for a minimal Debian (Stretch, 9.0) install.
|
||||
#
|
||||
# E. Viennet, Jun 2008, Apr 2009, Sept 2011, Sept 2013, Nov 2013, Mar 2017, Jul 2017,
|
||||
# Jun 2019, Oct 2019, Dec 2020
|
||||
# E. Viennet, Jun 2008, Apr 2009, Sept 2011, Sept 2013, Nov 2013, Mar 2017, Jul 2017, Jun 2019, Oct 2019
|
||||
#
|
||||
|
||||
source config.sh
|
||||
|
@ -13,14 +12,16 @@ source utils.sh
|
|||
|
||||
check_uid_root $0
|
||||
|
||||
PYTHON=/opt/zope213/bin/python
|
||||
|
||||
# ------------ Safety checks
|
||||
if [ "${debian_version}" != "10" ]
|
||||
if [ ${debian_version} != "10" ]
|
||||
then
|
||||
echo "Version du systeme Linux Debian incompatible"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(arch)" != "x86_64" ]
|
||||
if [ $(arch) != "x86_64" ]
|
||||
then
|
||||
echo "Version du systeme Linux Debian incompatible (pas X86 64 bits)"
|
||||
exit 1
|
||||
|
@ -28,16 +29,14 @@ fi
|
|||
|
||||
# ------------ Permissions & directories
|
||||
# source dir should be writable by scodoc to write bytecode files
|
||||
chgrp www-data "$SCODOC_DIR" "$SCODOC_DIR"/ZopeProducts/*
|
||||
chmod g+w "$SCODOC_DIR" "$SCODOC_DIR"/ZopeProducts/*
|
||||
chgrp www-data $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
||||
chmod g+w $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
||||
|
||||
if [ -d "${SCODOC_VAR_DIR}"/photos ]; then
|
||||
chgrp -R www-data "${SCODOC_VAR_DIR}"/photos
|
||||
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
||||
fi
|
||||
chgrp -R www-data "${SCODOC_VAR_DIR}"/photos
|
||||
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
||||
|
||||
if [ ! -e "${SCODOC_VERSION_DIR}" ]; then
|
||||
mkdir -p "${SCODOC_VERSION_DIR}"
|
||||
mkdir "${SCODOC_VERSION_DIR}"
|
||||
chown www-data.www-data "${SCODOC_VERSION_DIR}"
|
||||
fi
|
||||
|
||||
|
@ -54,8 +53,8 @@ fi
|
|||
|
||||
for locname in en_US.UTF-8 en_US.ISO-8859-15 en_US.ISO-8859-1
|
||||
do
|
||||
outname=$(echo ${locname//-/} | tr 'A-Z' 'a-z')
|
||||
if [ "$(locale -a | grep -E -i ^${outname}$ | wc -l)" -lt 1 ]
|
||||
outname=$(echo ${locname//-/} | tr '[A-Z]' '[a-z]')
|
||||
if [ $(locale -a | egrep -i ^${outname}$ | wc -l) -lt 1 ]
|
||||
then
|
||||
echo adding $locname
|
||||
echo "$locname ${locname##*.}" >> /etc/locale.gen
|
||||
|
@ -87,7 +86,7 @@ apt-get -y install postgresql
|
|||
apt-get -y install graphviz
|
||||
|
||||
# ------------ INSTALL DES EXTENSIONS PYTHON (2.7)
|
||||
# XXX to fix: pip in our env
|
||||
|
||||
apt-get -y install python-docutils
|
||||
apt-get -y install python-jaxml
|
||||
apt-get -y install python-psycopg2
|
||||
|
@ -100,15 +99,15 @@ apt-get -y install python-requests
|
|||
|
||||
# ------------
|
||||
SVNVERSION=$(cd ..; svnversion)
|
||||
SVERSION=$(curl --silent http://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=install\&svn="$SVNVERSION")
|
||||
echo "$SVERSION" > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
||||
SVERSION=$(curl --silent http://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=install\&svn=$SVNVERSION)
|
||||
echo $SVERSION > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
||||
|
||||
|
||||
# ------------ POSTFIX
|
||||
echo
|
||||
echo "ScoDoc a besoin de pouvoir envoyer des messages par mail."
|
||||
echo -n "Voulez vous configurer la messagerie (tres recommande) ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
apt-get -y install postfix
|
||||
|
@ -118,7 +117,7 @@ fi
|
|||
echo
|
||||
echo "Le firewall aide a proteger votre serveur d'intrusions indesirables."
|
||||
echo -n "Voulez vous configurer un firewall minimal (ufw) ? (y/n) [n] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" = 'Y' ]
|
||||
then
|
||||
echo 'Installation du firewall IP ufw (voir documentation Debian)'
|
||||
|
@ -143,16 +142,16 @@ a2enmod rewrite
|
|||
echo
|
||||
echo "La configuration du serveur web va modifier votre installation Apache pour supporter ScoDoc."
|
||||
echo -n "Voulez vous configurer le serveur web Apache maintenant (tres conseille) ? (y/n) [y] "
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
echo "Configuration d'Apache"
|
||||
server_name=""
|
||||
while [ -z "$server_name" ]
|
||||
while [ -z $server_name ]
|
||||
do
|
||||
echo "Le nom de votre serveur doit normalement etre connu dans le DNS."
|
||||
echo -n "Nom complet de votre serveur (exemple: notes.univ.fr): "
|
||||
read -r server_name
|
||||
read server_name
|
||||
done
|
||||
# --- CERTIFICATS AUTO-SIGNES
|
||||
echo
|
||||
|
@ -160,7 +159,7 @@ then
|
|||
echo "auto-signes, qui ne seront pas reconnus comme de confiance"
|
||||
echo "par les navigateurs, mais offrent une certaine securite."
|
||||
echo -n 'Voulez vous generer des certificats ssl auto-signes ? (y/n) [y] '
|
||||
read -r ans
|
||||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
# attention: utilise dans scodoc-site-ssl.orig
|
||||
|
@ -176,7 +175,7 @@ then
|
|||
fi
|
||||
# ---
|
||||
echo 'generation de /etc/apache2/sites-available/scodoc-site-ssl'
|
||||
cat "$SCODOC_DIR"/config/etc/scodoc-site-ssl-apache2.4.orig | sed -e "s:YOUR\.FULL\.HOST\.NAME:$server_name:g" > /etc/apache2/sites-available/scodoc-site-ssl.conf
|
||||
cat $SCODOC_DIR/config/etc/scodoc-site-ssl-apache2.4.orig | sed -e "s:YOUR\.FULL\.HOST\.NAME:$server_name:g" > /etc/apache2/sites-available/scodoc-site-ssl.conf
|
||||
echo 'activation du site...'
|
||||
a2ensite scodoc-site-ssl
|
||||
|
||||
|
@ -186,7 +185,7 @@ then
|
|||
then
|
||||
mv $fn $fn.bak
|
||||
fi
|
||||
cp "$SCODOC_DIR"/config/etc/scodoc-site.orig $fn
|
||||
cp $SCODOC_DIR/config/etc/scodoc-site.orig $fn
|
||||
|
||||
if [ -z "$(grep Listen /etc/apache2/ports.conf | grep 443)" ]
|
||||
then
|
||||
|
@ -219,7 +218,9 @@ read ans
|
|||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
# ScoDoc 7.19+ uses systemd
|
||||
$SCODOC_DIR/config/configure_systemd.sh
|
||||
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
||||
cp $SCODOC_DIR/config/etc/scodoc.service /etc/systemd/system
|
||||
systemctl enable scodoc.service
|
||||
fi
|
||||
|
||||
|
||||
|
@ -229,8 +230,8 @@ echo -n "Mises a jour hebdomadaires (tres recommande) ? (y/n) [y] "
|
|||
read ans
|
||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||
then
|
||||
cp "$SCODOC_DIR"/config/etc/scodoc-updater.service /etc/systemd/system
|
||||
cp "$SCODOC_DIR"/config/etc/scodoc-updater.timer /etc/systemd/system
|
||||
cp $SCODOC_DIR/config/etc/scodoc-updater.service /etc/systemd/system
|
||||
cp $SCODOC_DIR/config/etc/scodoc-updater.timer /etc/systemd/system
|
||||
systemctl enable scodoc-updater.timer
|
||||
systemctl start scodoc-updater.timer
|
||||
fi
|
||||
|
|
|
@ -8,7 +8,7 @@ PG_DUMPFILE=$1
|
|||
# Check locale of installation. If invalid, reinitialize all system
|
||||
|
||||
is_latin1=$(psql -l | grep postgres | grep iso88591 | wc -l)
|
||||
if [ "$is_latin1" -gt 1 ]
|
||||
if [ $is_latin1 -gt 1 ]
|
||||
then
|
||||
echo "Recreating postgres cluster using UTF-8"
|
||||
|
||||
|
@ -20,8 +20,8 @@ fi
|
|||
|
||||
# Drop all current ScoDoc databases, if any:
|
||||
for f in $(psql -l --no-align --field-separator . | grep SCO | cut -f 1 -d.); do
|
||||
echo dropping "$f"
|
||||
dropdb "$f"
|
||||
echo dropping $f
|
||||
dropdb $f
|
||||
done
|
||||
echo "Restoring postgres data..."
|
||||
psql -f "$PG_DUMPFILE" postgres
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#
|
||||
source utils.sh
|
||||
|
||||
check_uid_root "$0"
|
||||
|
||||
# Destination directory
|
||||
if [ ! $# -eq 1 ]
|
||||
then
|
||||
|
@ -36,12 +34,9 @@ fi
|
|||
INSTANCE_DIR=/opt/scodoc
|
||||
SCODOC_DIR="$INSTANCE_DIR/Products/ScoDoc"
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
source utils.sh
|
||||
check_uid_root "$0"
|
||||
|
||||
>>>>>>> e2a2b0f0836fc6de922c35b77b236379783e7590
|
||||
echo "Stopping ScoDoc..."
|
||||
scodocctl stop
|
||||
|
||||
|
@ -51,16 +46,12 @@ chown postgres "$DEST"
|
|||
su -c "pg_dumpall > \"$DEST\"/scodoc.dump.txt" postgres
|
||||
if [ ! "$?" -eq 0 ]
|
||||
then
|
||||
<<<<<<< HEAD
|
||||
printf "Error dumping postgresql database\nPlease check that SQL server is running\nAborting.\n"
|
||||
=======
|
||||
printf "Error dumping postgresql database\nPlease check that SQL server is running\nAborting."
|
||||
>>>>>>> e2a2b0f0836fc6de922c35b77b236379783e7590
|
||||
exit 1
|
||||
fi
|
||||
chown root "$DEST"
|
||||
|
||||
# Zope DB, ScoDoc archives, configuration, photos, etc.
|
||||
# Zope DB and ScoDoc archives:
|
||||
echo "Copying var/ ..."
|
||||
cp -rp "$INSTANCE_DIR/var" "$DEST"
|
||||
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Configuration globale de ScoDoc (version juin 2009)
|
||||
# Ce fichier est copié dans /opt/scodoc/var/scodoc/config
|
||||
# par les scripts d'installation/mise à jour.
|
||||
|
||||
# La plupart des réglages sont stoqués en base de donnée et accessibles via le web
|
||||
# (pages de paramètres ou préférences).
|
||||
# Les valeurs indiquées ici sont les valeurs initiales que prendront
|
||||
# les paramètres lors de la création d'un nouveau département,
|
||||
# elles ne sont plus utilisées ensuite.
|
||||
|
||||
# Nota: il y a aussi des réglages dans sco_utils.py, mais ils nécessitent
|
||||
# souvent de comprendre le code qui les utilise pour ne pas faire d'erreur: attention.
|
||||
|
||||
|
||||
class CFG:
|
||||
pass
|
||||
|
||||
|
||||
CONFIG = CFG()
|
||||
|
||||
# set to 1 if you want to require INE:
|
||||
# CONFIG.always_require_ine = 0
|
||||
|
||||
# The base URL, use only if you are behind a proxy
|
||||
# eg "https://scodoc.example.net/ScoDoc"
|
||||
# CONFIG.ABSOLUTE_URL = ""
|
||||
|
||||
# -----------------------------------------------------
|
||||
# -------------- Documents PDF
|
||||
# -----------------------------------------------------
|
||||
|
||||
# Taille du l'image logo: largeur/hauteur (ne pas oublier le . !!!)
|
||||
# W/H XXX provisoire: utilisera PIL pour connaitre la taille de l'image
|
||||
# CONFIG.LOGO_FOOTER_ASPECT = 326 / 96.0
|
||||
# Taille dans le document en millimetres
|
||||
# CONFIG.LOGO_FOOTER_HEIGHT = 10
|
||||
# Proportions logo (donné ici pour IUTV)
|
||||
# CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
|
||||
# Taille verticale dans le document en millimetres
|
||||
# CONFIG.LOGO_HEADER_HEIGHT = 28
|
||||
|
||||
# Pied de page PDF : un format Python, %(xxx)s est remplacé par la variable xxx.
|
||||
# Les variables définies sont:
|
||||
# day : Day of the month as a decimal number [01,31]
|
||||
# month : Month as a decimal number [01,12].
|
||||
# year : Year without century as a decimal number [00,99].
|
||||
# Year : Year with century as a decimal number.
|
||||
# hour : Hour (24-hour clock) as a decimal number [00,23].
|
||||
# minute: Minute as a decimal number [00,59].
|
||||
#
|
||||
# server_url: URL du serveur ScoDoc
|
||||
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir VERSION.py)
|
||||
|
||||
# CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||
|
||||
|
||||
#
|
||||
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
||||
#
|
||||
|
||||
# CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
||||
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
||||
|
||||
#
|
||||
# ------------- Capitalisation des UEs -------------
|
||||
# Deux écoles:
|
||||
# - règle "DUT": capitalisation des UE obtenues avec moyenne UE >= 10 ET de toutes les UE
|
||||
# des semestres validés (ADM, ADC, AJ). (conforme à l'arrêté d'août 2005)
|
||||
#
|
||||
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
||||
|
||||
# Si vrai, capitalise toutes les UE des semestres validés (règle "DUT").
|
||||
# CONFIG.CAPITALIZE_ALL_UES = True
|
||||
|
||||
|
||||
#
|
||||
# -----------------------------------------------------
|
||||
#
|
||||
# -------------- Personnalisation des pages
|
||||
#
|
||||
# -----------------------------------------------------
|
||||
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
||||
# le <body> des pages ScoDoc
|
||||
# CONFIG.CUSTOM_HTML_HEADER = ""
|
||||
|
||||
# Fichier html a inclure en fin des pages (juste avant le </body>)
|
||||
# CONFIG.CUSTOM_HTML_FOOTER = ""
|
||||
|
||||
# Fichier .html à inclure dans la pages connexion/déconnexion (accueil)
|
||||
# si on veut que ce soit différent (par défaut la même chose)
|
||||
# CONFIG.CUSTOM_HTML_HEADER_CNX = CONFIG.CUSTOM_HTML_HEADER
|
||||
# CONFIG.CUSTOM_HTML_FOOTER_CNX = CONFIG.CUSTOM_HTML_FOOTER
|
||||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# -------------- Noms de Lycées
|
||||
# -----------------------------------------------------
|
||||
# Fichier de correspondance codelycee -> noms
|
||||
# (chemin relatif au repertoire d'install des sources)
|
||||
# CONFIG.ETABL_FILENAME = "config/etablissements.csv"
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# -------------- Divers:
|
||||
# ----------------------------------------------------
|
||||
# True for UCAC (étudiants camerounais sans prénoms)
|
||||
# CONFIG.ALLOW_NULL_PRENOM = False
|
||||
|
||||
# Taille max des fichiers archive etudiants (en octets)
|
||||
# CONFIG.ETUD_MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||
|
||||
# Si pas de photo et portail, publie l'url (était vrai jusqu'en oct 2016)
|
||||
# CONFIG.PUBLISH_PORTAL_PHOTO_URL = False
|
||||
|
||||
# Si > 0: longueur minimale requise des nouveaux mots de passe
|
||||
# (le test cracklib.FascistCheck s'appliquera dans tous les cas)
|
||||
# CONFIG.MIN_PASSWORD_LENGTH = 0
|
||||
|
||||
|
||||
# Ce dictionnaire est fusionné à celui de sco_codes_parcours
|
||||
# pour définir les codes jury et explications associées
|
||||
# CONFIG.CODES_EXPL = {
|
||||
# # AJ : 'Ajourné (échec)',
|
||||
# }
|
|
@ -4,7 +4,7 @@
|
|||
# ScoDoc: reglage du mot de passe admin Zope
|
||||
# (in Zope terminology, an emergency user)
|
||||
#
|
||||
# Doit <EFBFBD>tre lanc<6E> par l'utilisateur unix root dans le repertoire .../config
|
||||
# Doit être lancé par l'utilisateur unix root dans le repertoire .../config
|
||||
# ^^^^^^^^^^^^^^^^^^^^^
|
||||
# E. Viennet, Juin 2008, Jul 2019
|
||||
#
|
||||
|
@ -22,14 +22,14 @@ fi
|
|||
echo "Creation d'un utilisateur d'urgence pour ScoDoc"
|
||||
echo "(utile en cas de perte de votre mot de passe admin)"
|
||||
|
||||
if [ "${debian_version}" != "10" ]
|
||||
if [ ${debian_version} != "10" ]
|
||||
then
|
||||
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2-2.13.21-py2.7.egg/Zope2/utilities
|
||||
else
|
||||
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2/utilities
|
||||
fi
|
||||
|
||||
python $mdir/zpasswd.py "$SCODOC_DIR"/../../access
|
||||
python $mdir/zpasswd.py $SCODOC_DIR/../../access
|
||||
|
||||
echo
|
||||
echo "redemarrer scodoc pour prendre en compte le mot de passe"
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Upgrade ScoDoc installation using GIT
|
||||
# GIT must be properly configured and have read access to ScoDoc repository
|
||||
# Upgrade ScoDoc installation using SVN
|
||||
# SVN must be properly configured and have read access to ScoDoc repository
|
||||
# This script STOP and RESTART ScoDoc and should be runned as root
|
||||
#
|
||||
# Upgrade also the Linux system using apt.
|
||||
#
|
||||
# Script for ScoDoc 8 (10)
|
||||
# Script for ScoDoc 7 (Debian 7, 8, 9, 10)
|
||||
#
|
||||
# E. Viennet, sep 2013, mar 2017, jun 2019, aug 2020, dec 2020
|
||||
# E. Viennet, sep 2013, mar 2017, jun 2019, aug 2020
|
||||
|
||||
cd /opt/scodoc/Products/ScoDoc/config || { echo "Invalid directory"; exit 1; }
|
||||
cd /opt/scodoc/Products/ScoDoc/config
|
||||
source config.sh
|
||||
source utils.sh
|
||||
|
||||
|
@ -32,8 +32,8 @@ fi
|
|||
scodocctl stop
|
||||
|
||||
echo
|
||||
echo "Using git to update $SCODOC_DIR..."
|
||||
(cd "$SCODOC_DIR"; git checkout ScoDoc8; git pull origin master)
|
||||
echo "Using SVN to update $SCODOC_DIR..."
|
||||
(cd "$SCODOC_DIR"; svn update)
|
||||
|
||||
SVNVERSION=$(cd ..; svnversion)
|
||||
|
||||
|
@ -119,19 +119,6 @@ if [ $? -ne 0 ]
|
|||
then
|
||||
/opt/zope213/bin/pip install requests
|
||||
fi
|
||||
/opt/zope213/bin/python -c "import attrdict" >& /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
/opt/zope213/bin/pip install attrdict
|
||||
fi
|
||||
|
||||
# Check that local configuration file is installed
|
||||
LOCAL_CONFIG_FILENAME="/opt/scodoc/var/scodoc/config/scodoc_local.py"
|
||||
if [ ! -e "$LOCAL_CONFIG_FILENAME" ]
|
||||
then
|
||||
cp "$SCODOC_DIR"/config/scodoc_config_tmpl.py "$LOCAL_CONFIG_FILENAME"
|
||||
chmod 600 "$LOCAL_CONFIG_FILENAME"
|
||||
fi
|
||||
|
||||
# upgrade old dateutil (check version manually to speedup)
|
||||
v=$(/opt/zope213/bin/python -c "import dateutil; print dateutil.__version__")
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Misc utilities for ScoDoc install shell scripts
|
||||
|
||||
to_lower() {
|
||||
echo "$1" | tr "[:upper:]" "[:lower:]"
|
||||
echo $1 | tr "[:upper:]" "[:lower:]"
|
||||
}
|
||||
|
||||
to_upper() {
|
||||
echo "$1" | tr "[:lower:]" "[:upper:]"
|
||||
echo $1 | tr "[:lower:]" "[:upper:]"
|
||||
}
|
||||
|
||||
norm_ans() {
|
||||
x=$(to_upper "$1" | tr O Y)
|
||||
echo "${x:0:1}"
|
||||
x=$(to_upper $1 | tr O Y)
|
||||
echo ${x:0:1}
|
||||
}
|
||||
|
||||
check_uid_root() {
|
||||
|
@ -23,11 +23,10 @@ check_uid_root() {
|
|||
}
|
||||
|
||||
terminate() {
|
||||
status=${2:-1} # default: exit 1
|
||||
echo
|
||||
echo "Erreur: $1"
|
||||
echo
|
||||
exit $status
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Start/stop scodoc, using sysv or systemd
|
||||
|
@ -45,7 +44,7 @@ scodocctl() {
|
|||
systemctl $1 scodoc
|
||||
else
|
||||
echo "(using legacy SystemV)"
|
||||
/etc/init.d/scodoc "$1"
|
||||
/etc/init.d/scodoc $1
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -55,7 +54,7 @@ init_postgres_user() { # run as root
|
|||
then
|
||||
# add database user
|
||||
echo "Creating postgresql user $POSTGRES_USER"
|
||||
su -c "createuser -p $POSTGRES_PORT --no-superuser --no-createdb --no-adduser --no-createrole ${POSTGRES_USER}" "$POSTGRES_SUPERUSER"
|
||||
su -c "createuser -p $POSTGRES_PORT --no-superuser --no-createdb --no-adduser --no-createrole ${POSTGRES_USER}" $POSTGRES_SUPERUSER
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -70,8 +69,8 @@ gen_passwd() {
|
|||
password=""
|
||||
while [ "$n" -le "$PASSWORD_LENGTH" ]
|
||||
do
|
||||
password="$password${ALLOWABLE_ASCII:$((RANDOM%${#ALLOWABLE_ASCII})):1}"
|
||||
n=$((n+1))
|
||||
password="$password${ALLOWABLE_ASCII:$(($RANDOM%${#ALLOWABLE_ASCII})):1}"
|
||||
n=$((n+1))
|
||||
done
|
||||
echo "$password"
|
||||
echo $password
|
||||
}
|
||||
|
|
|
@ -67,11 +67,7 @@ def go(app, n=0, verbose=True):
|
|||
def go_dept(app, dept, verbose=True):
|
||||
objs = app.ScoDoc.objectValues("Folder")
|
||||
for o in objs:
|
||||
try:
|
||||
context = o.Scolarite
|
||||
except AttributeError:
|
||||
# ignore other folders, like old "icons"
|
||||
continue
|
||||
context = o.Scolarite
|
||||
if context.DeptId() == dept:
|
||||
if verbose:
|
||||
print("context in dept ", context.DeptId())
|
49
dtml/docLogin.dtml
Normal file
49
dtml/docLogin.dtml
Normal file
|
@ -0,0 +1,49 @@
|
|||
<dtml-var standard_html_header>
|
||||
<center>
|
||||
<dtml-if authFailedCode>
|
||||
<dtml-call "REQUEST.set('loginTitle', getAuthFailedMessage(authFailedCode))">
|
||||
<dtml-else>
|
||||
<dtml-call "REQUEST.set('loginTitle', 'Identifiez vous sur ScoDoc')">
|
||||
</dtml-if>
|
||||
<dtml-var "DialogHeader(_.None,_,DialogTitle=loginTitle)">
|
||||
<P>
|
||||
<dtml-if destination>
|
||||
<FORM ACTION="&dtml-destination;" METHOD="POST">
|
||||
<dtml-else>
|
||||
<FORM ACTION="&dtml-URL;" METHOD="POST">
|
||||
</dtml-if>
|
||||
|
||||
<dtml-var "query_string_to_form_inputs(QUERY_STRING)"> <dtml-comment> Added by Emmanuel for ScoDoc</dtml-comment>
|
||||
|
||||
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TD ALIGN="LEFT" VALIGN="TOP">
|
||||
<STRONG><dtml-babel src="'en'">Nom</dtml-babel></STRONG>
|
||||
</TD>
|
||||
<TD ALIGN="LEFT" VALIGN="TOP">
|
||||
<INPUT TYPE="TEXT" NAME="__ac_name" SIZE="20">
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD ALIGN="LEFT" VALIGN="TOP">
|
||||
<STRONG><dtml-babel src="'en'">Mot de passe</dtml-babel></STRONG>
|
||||
</TD>
|
||||
<TD ALIGN="LEFT" VALIGN="TOP">
|
||||
<INPUT TYPE="PASSWORD" NAME="__ac_password" SIZE="20">
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="LEFT" VALIGN="TOP">
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<center>
|
||||
<INPUT TYPE="SUBMIT" NAME="submit" VALUE=" <dtml-babel src="'en'">Ok</dtml-babel> ">
|
||||
</center>
|
||||
</FORM>
|
||||
<br>
|
||||
<dtml-var DialogFooter>
|
||||
</center>
|
||||
<dtml-var standard_html_footer>
|
16
dtml/docLogout.dtml
Normal file
16
dtml/docLogout.dtml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<dtml-var standard_html_header>
|
||||
<P>
|
||||
<CENTER>
|
||||
<p>Vous êtes déconnecté de ScoDoc.
|
||||
</p>
|
||||
|
||||
<p><a href="<dtml-var "BASE0">">revenir à l'accueil</a></p>
|
||||
|
||||
<br/>
|
||||
<p><em style="color: red;">(Attention: si vous êtes administrateur, vous ne pouvez vous déconnecter complètement qu'en relançant votre navigateur)
|
||||
</em></p>
|
||||
</CENTER>
|
||||
|
||||
|
||||
|
||||
<dtml-var standard_html_footer>
|
49
dtml/manage_addZNotesForm.dtml
Normal file
49
dtml/manage_addZNotesForm.dtml
Normal file
|
@ -0,0 +1,49 @@
|
|||
<dtml-var manage_page_header>
|
||||
|
||||
<dtml-var "manage_form_title(this(), _,
|
||||
form_title='Add Notes',
|
||||
help_product='ZNotes',
|
||||
help_topic='ZNotes-add.stx'
|
||||
)">
|
||||
|
||||
<div class="form-help">
|
||||
<p>
|
||||
Notes Objects are very usefull thus not documented yet...
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form name="form" action="manage_addZNotes"><br>
|
||||
|
||||
<table cellspacing="0" cellpadding="2" border="0">
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Id
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="id" size="40" value="" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Title
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="title" size="40" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<div class="form-element">
|
||||
<input class="form-element"
|
||||
type="submit"
|
||||
name="submit"
|
||||
value=" Add "
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<dtml-var manage_page_header>
|
62
dtml/manage_addZScolarForm.dtml
Normal file
62
dtml/manage_addZScolarForm.dtml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<dtml-var manage_page_header>
|
||||
|
||||
<dtml-var "manage_form_title(this(), _,
|
||||
form_title='Add ZScolar',
|
||||
help_product='ZScolar',
|
||||
help_topic='ZScolar-add.stx'
|
||||
)">
|
||||
|
||||
<div class="form-help">
|
||||
<p>
|
||||
ZScolar: gestion scolarite d'un departement
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form name="form" action="manage_addZScolar"><br>
|
||||
|
||||
<table cellspacing="0" cellpadding="2" border="0">
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Id
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="id" size="40" value="" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Title
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="title" size="40" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
DB connexion string
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="db_cnx_string" size="80" value="user=zopeuser dbname=SCOGTR password=XXXX host=localhost" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<div class="form-element">
|
||||
<input class="form-element"
|
||||
type="submit"
|
||||
name="submit"
|
||||
value=" Add "
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<dtml-var manage_page_header>
|
21
dtml/manage_editZNotesForm.dtml
Normal file
21
dtml/manage_editZNotesForm.dtml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<dtml-var manage_page_header>
|
||||
<dtml-var manage_tabs>
|
||||
|
||||
<dtml-var "manage_form_title(this(), _,
|
||||
form_title='Edit ZNotes',
|
||||
help_product='ZNotes',
|
||||
help_topic='ZNotes-edit.stx'
|
||||
)">
|
||||
|
||||
|
||||
<form name="form" action="manage_editAction" method="post"><br/>
|
||||
id: <dtml-var id><br/>
|
||||
title: <input type="text" name="title:string" size="30" value="<dtml-var title>"><br/>
|
||||
<div class="form-element">
|
||||
<input class="form-element" type="submit" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<dtml-var manage_page_footer>
|
||||
|
21
dtml/manage_editZScolarForm.dtml
Normal file
21
dtml/manage_editZScolarForm.dtml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<dtml-var manage_page_header>
|
||||
<dtml-var manage_tabs>
|
||||
|
||||
<dtml-var "manage_form_title(this(), _,
|
||||
form_title='Edit ZScolar',
|
||||
help_product='ZScolar',
|
||||
help_topic='ZScolar-edit.stx'
|
||||
)">
|
||||
|
||||
|
||||
<form name="form" action="manage_editAction" method="post"><br/>
|
||||
id: <dtml-var id><br/>
|
||||
title: <input type="text" name="title:string" size="30" value="<dtml-var title>"><br/>
|
||||
<div class="form-element">
|
||||
<input class="form-element" type="submit" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<dtml-var manage_page_footer>
|
||||
|
|
@ -445,14 +445,14 @@ class GenTable:
|
|||
if self.base_url:
|
||||
if self.xls_link:
|
||||
H.append(
|
||||
' <a href="%s&format=xls">%s</a>'
|
||||
' <a href="%s&format=xls">%s</a>'
|
||||
% (self.base_url, scu.ICON_XLS)
|
||||
)
|
||||
if self.xls_link and self.pdf_link:
|
||||
H.append(" ")
|
||||
if self.pdf_link:
|
||||
H.append(
|
||||
' <a href="%s&format=pdf">%s</a>'
|
||||
' <a href="%s&format=pdf">%s</a>'
|
||||
% (self.base_url, scu.ICON_PDF)
|
||||
)
|
||||
H.append("</p>")
|
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Check usage of (published) ScoDoc methods
|
||||
|
||||
Quick method: just grep method name in all constant strings from the source code base.
|
||||
|
||||
Usage:
|
||||
check_zope_usage.py publishedmethods.csv string-constants.txt
|
||||
|
||||
publishedmethods.csv : fichier texte, module et un nom de méthode / ligne
|
||||
ZScoUsers get_userlist
|
||||
comme extrait par zopelistmethods.py
|
||||
|
||||
string-constants.txt : les constantes chaines, extraites par extract_code_strings.py
|
||||
"scolars.py" "</li><li>"
|
||||
|
||||
E. Viennet 2021-01-09
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import glob
|
||||
|
||||
methods_filename = sys.argv[1]
|
||||
constants_filename = sys.argv[2]
|
||||
|
||||
with open(methods_filename) as f:
|
||||
# module, method_name, signature
|
||||
methods = [l.strip().split("\t") for l in f]
|
||||
|
||||
print("%d methods" % len(methods))
|
||||
|
||||
with open(constants_filename) as f:
|
||||
constants = [l[:-1].split("\t")[1] for l in f]
|
||||
|
||||
print("%d constants" % len(constants))
|
||||
|
||||
# Add JavaScripts
|
||||
jss = []
|
||||
for fn in glob.glob("static/js/*.js"):
|
||||
jss.append(open(fn).read())
|
||||
|
||||
print("%d javascripts" % len(jss))
|
||||
|
||||
L = []
|
||||
for method in methods:
|
||||
n = 0
|
||||
for c in constants:
|
||||
if method[1] in c:
|
||||
n += 1
|
||||
nj = 0
|
||||
for js in jss:
|
||||
if method[1] in js:
|
||||
nj += 1
|
||||
L.append(method + [n, nj])
|
||||
|
||||
# Sort by decreasing popularity
|
||||
L.sort(key=lambda x: (x[-1] + x[-2], x[1]), reverse=True)
|
||||
print("\n".join(["%s\t%s\t%s\t%d\t%d" % tuple(l) for l in L]))
|
|
@ -1,39 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Extract all string litterals from our code base.
|
||||
|
||||
Useful to check if an API function is used in a generated web page !
|
||||
|
||||
Usage:
|
||||
extract_code_strings.py source.py ... > string-constants.txt
|
||||
|
||||
|
||||
Résultat utilisé par check_zope_usage.py
|
||||
|
||||
E. Viennet 2021-01-09
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import ast
|
||||
import types
|
||||
|
||||
# L = []
|
||||
for srcfilename in sys.argv[1:]:
|
||||
# print("processing %s" % srcfilename, file=sys.stderr)
|
||||
with open(srcfilename) as f:
|
||||
p = ast.parse(f.read())
|
||||
# L.extend(x.s.strip() for x in ast.walk(p) if x.__class__ == ast.Str)
|
||||
for x in ast.walk(p):
|
||||
if x.__class__ == ast.Str:
|
||||
if type(x.s) == types.StringType:
|
||||
s = x.s
|
||||
else:
|
||||
s = x.s.encode("UTF-8")
|
||||
# remove tabs and cr
|
||||
s = s.translate(None, "\t\n")
|
||||
if len(s):
|
||||
print("%s\t%s" % (srcfilename, s))
|
||||
|
||||
# L = sorted(set(L)) # uniq | sort
|
||||
# print("\n".join(L))
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
"""List Zope published methods (helps redesign ScoDoc's API).
|
||||
|
||||
Usage:
|
||||
scotests/scointeractive.sh RT misc/zopelistmethods.py
|
||||
Launch ScoDoc as follows: (as root)
|
||||
|
||||
(replace RT by an existing departement id)
|
||||
/opt/scodoc/bin/zopectl debug
|
||||
|
||||
Then run this file
|
||||
|
||||
E. Viennet 2020-01-26
|
||||
"""
|
||||
|
@ -22,8 +23,6 @@ from ZAbsences import ZAbsences
|
|||
from ZScoUsers import ZScoUsers
|
||||
from ZEntreprises import ZEntreprises
|
||||
|
||||
RESFILENAME = "publishedmethods.csv"
|
||||
|
||||
|
||||
def get_methods_description(klass):
|
||||
D = klass.__dict__
|
||||
|
@ -64,6 +63,4 @@ for module_name in published_by_module:
|
|||
|
||||
print("Total: \t ", N)
|
||||
|
||||
print("Writing %s" % RESFILENAME)
|
||||
with open(RESFILENAME, "w") as f:
|
||||
f.write("\n".join(["\t".join(l) for l in lines]))
|
||||
open("publishedmethods.csv", "w").write("\n".join(["\t".join(l) for l in lines]))
|
||||
|
|
|
@ -8,10 +8,6 @@ import re
|
|||
import inspect
|
||||
import time
|
||||
import traceback
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||
MIMEMultipart,
|
|
@ -462,11 +462,11 @@ def get_templates_from_distrib(template="avis"):
|
|||
|
||||
if template in ["avis", "footer"]:
|
||||
# pas de preference pour le template: utilise fichier du serveur
|
||||
p = os.path.join(scu.SCO_SRC_DIR, pe_local_tmpl)
|
||||
p = os.path.join(scu.SCO_SRCDIR, pe_local_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
||||
p = os.path.join(scu.SCO_SRC_DIR, pe_default_tmpl)
|
||||
p = os.path.join(scu.SCO_SRCDIR, pe_default_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
|
@ -177,7 +177,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
|||
|
||||
Also copy logos
|
||||
"""
|
||||
PE_AUX_DIR = os.path.join(scu.SCO_SRC_DIR, "config/doc_poursuites_etudes")
|
||||
PE_AUX_DIR = os.path.join(scu.SCO_SRCDIR, "config/doc_poursuites_etudes")
|
||||
distrib_dir = os.path.join(PE_AUX_DIR, "distrib")
|
||||
distrib_pathnames = list_directory_filenames(
|
||||
distrib_dir
|
107
refactor.py
107
refactor.py
|
@ -1,107 +0,0 @@
|
|||
# -*- coding: UTF-8 -*
|
||||
|
||||
|
||||
"""Outil pour migration ScoDoc 7 => ScoDoc 8
|
||||
|
||||
Pour chaque module dans views:
|
||||
- construire la liste des fonctions définies dans ce module:
|
||||
get_module_functions
|
||||
|
||||
Pour chaque module dans views et dans scodoc:
|
||||
- remplacer context.xxx par app.views.M.xxx
|
||||
où M est le module de views définissant xxx
|
||||
Si xxx n'est pas trouvé, erreur !
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
|
||||
from pprint import pprint as pp
|
||||
import sys
|
||||
import types
|
||||
|
||||
import click
|
||||
import flask
|
||||
|
||||
import app
|
||||
from app import create_app, cli, db
|
||||
from app.auth.models import User, Role, UserRole
|
||||
|
||||
from config import Config
|
||||
|
||||
from app.views import notes
|
||||
|
||||
TYPES_TO_SCAN = {
|
||||
types.FunctionType,
|
||||
# types.ClassType,
|
||||
# types.DictionaryType,
|
||||
# types.FloatType,
|
||||
# types.IntType,
|
||||
# types.ListType,
|
||||
# types.StringType,
|
||||
# types.TupleType,
|
||||
}
|
||||
|
||||
|
||||
def get_module_symbols(module):
|
||||
"""returns list of symbols (functions and constants) defined in the given module"""
|
||||
return [
|
||||
f.__name__
|
||||
for f in [getattr(module, name) for name in dir(module)]
|
||||
if (type(f) in TYPES_TO_SCAN)
|
||||
and ((type(f) != types.FunctionType) or (f.__module__ == module.__name__))
|
||||
]
|
||||
|
||||
|
||||
# print("\n".join(f.__name__ for f in get_module_functions(notes)))
|
||||
|
||||
|
||||
def scan_views_symbols():
|
||||
"""Scan modules in app.views and returns
|
||||
{ }
|
||||
"""
|
||||
views_modules = [
|
||||
getattr(app.views, mod_name)
|
||||
for mod_name in dir(app.views)
|
||||
if type(getattr(app.views, mod_name)) == types.ModuleType
|
||||
]
|
||||
sym2mod = {} # symbole_name : module
|
||||
for module in views_modules:
|
||||
start = "app.views."
|
||||
assert module.__name__.startswith(start)
|
||||
module_name = module.__name__[len(start) :]
|
||||
symbols = set(get_module_symbols(module))
|
||||
print("%d symbols defined in %s" % (len(symbols), module))
|
||||
dups = symbols.intersection(sym2mod)
|
||||
if len(dups):
|
||||
print("duplicated symbols !")
|
||||
for dup in dups:
|
||||
print("%s:\t%s\t%s" % (dup, sym2mod[dup], module_name))
|
||||
|
||||
sym2mod.update({s: module_name for s in symbols})
|
||||
return sym2mod
|
||||
|
||||
|
||||
def replace_context_calls(sourcefilename, sym2mod):
|
||||
undefined_list = [] # noms de fonctions non présents dans les modules "views"
|
||||
|
||||
def repl(m):
|
||||
funcname = m.group(1)
|
||||
module = sym2mod.get(funcname, False)
|
||||
if module:
|
||||
return module + "." + funcname
|
||||
else:
|
||||
undefined_list.append((sourcefilename, funcname))
|
||||
return m.group(0) # leave unchanged
|
||||
|
||||
print("reading %s" % sourcefilename)
|
||||
source = open(sourcefilename).read()
|
||||
exp = re.compile(r"context\.([a-zA-Z0-9_]+)")
|
||||
source2 = exp.sub(repl, source)
|
||||
return source2, undefined_list
|
||||
|
||||
|
||||
sym2mod = scan_views_symbols()
|
||||
|
||||
source2, undefined_list = replace_context_calls("app/scodoc/sco_core.py", sym2mod)
|
|
@ -1,46 +0,0 @@
|
|||
alembic==1.5.5
|
||||
attrdict==2.0.1
|
||||
Babel==2.9.0
|
||||
blinker==1.4
|
||||
certifi==2021.5.30
|
||||
chardet==4.0.0
|
||||
click==7.1.2
|
||||
dnspython==1.16.0
|
||||
dominate==2.6.0
|
||||
email-validator==1.1.2
|
||||
Flask==1.1.4
|
||||
Flask-Babel==2.0.0
|
||||
Flask-Bootstrap==3.3.7.1
|
||||
Flask-Login==0.5.0
|
||||
Flask-Mail==0.9.1
|
||||
Flask-Migrate==2.7.0
|
||||
Flask-Moment==0.11.0
|
||||
Flask-SQLAlchemy==2.4.4
|
||||
Flask-WTF==0.14.3
|
||||
icalendar==4.0.7
|
||||
idna==2.10
|
||||
itsdangerous==1.1.0
|
||||
jaxml==3.2
|
||||
Jinja2==2.11.2
|
||||
Mako==1.1.4
|
||||
MarkupSafe==1.1.1
|
||||
Pillow==6.2.2
|
||||
pkg-resources==0.0.0
|
||||
psycopg2==2.8.6
|
||||
pyExcelerator==0.6.3a0
|
||||
PyJWT==1.7.1
|
||||
PyRSS2Gen==1.1
|
||||
python-dateutil==2.8.1
|
||||
python-dotenv==0.15.0
|
||||
python-editor==1.0.4
|
||||
pytz==2021.1
|
||||
reportlab==3.5.59
|
||||
requests==2.25.1
|
||||
six==1.15.0
|
||||
SQLAlchemy==1.3.23
|
||||
stripogram==1.5
|
||||
typing==3.7.4.3
|
||||
urllib3==1.26.5
|
||||
visitor==0.1.3
|
||||
Werkzeug==1.0.1
|
||||
WTForms==2.3.3
|
|
@ -32,11 +32,13 @@
|
|||
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||
MIMEMultipart,
|
||||
)
|
||||
from email.MIMEText import MIMEText # pylint: disable=no-name-in-module,import-error
|
||||
from email.MIMEBase import MIMEBase # pylint: disable=no-name-in-module,import-error
|
||||
from email.Header import Header # pylint: disable=no-name-in-module,import-error
|
||||
from email import Encoders # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user