From 9e65fa765406e39186905002eeceac3195619f95 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Fri, 23 Apr 2021 10:24:45 +0200 Subject: [PATCH] Fixes #70 --- ZopeProducts/exUserFolder/exUserFolder.py | 6 +-- config/fix_bug70_db.py | 64 +++++++++++++++++++++++ config/postupgrade.py | 28 +++++++--- config/scodocutils.py | 1 + debug.py | 10 ++-- notes_table.py | 3 ++ scotests/scointeractive.sh | 49 +++++++++++------ scotests/test_capitalisation.py | 2 +- 8 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 config/fix_bug70_db.py mode change 100755 => 100644 config/postupgrade.py mode change 100644 => 100755 config/scodocutils.py diff --git a/ZopeProducts/exUserFolder/exUserFolder.py b/ZopeProducts/exUserFolder/exUserFolder.py index 1c330c9..a5b07c8 100644 --- a/ZopeProducts/exUserFolder/exUserFolder.py +++ b/ZopeProducts/exUserFolder/exUserFolder.py @@ -251,8 +251,8 @@ class exUserFolder(Folder,BasicUserFolder,BasicGroupFolderMixin, ('Manager',)), ('View', ('manage_changePassword', - 'manage_forgotPassword', 'docLogin','docLoginRedirect', - 'docLogout', 'logout', 'DialogHeader', + 'manage_forgotPassword','docLoginRedirect', + 'logout', 'DialogHeader', 'DialogFooter', 'manage_signupUser', 'MessageDialog', 'redirectToLogin','manage_changeProps'), ('Anonymous', 'Authenticated', 'Manager')), @@ -269,7 +269,7 @@ class exUserFolder(Folder,BasicUserFolder,BasicGroupFolderMixin, ('Access contents information', ('hasProperty', 'propertyIds', 'propertyValues','propertyItems', 'getProperty', 'getPropertyType', - 'propertyMap', 'docLogin','docLoginRedirect', + 'propertyMap', 'docLoginRedirect', 'DialogHeader', 'DialogFooter', 'MessageDialog', 'redirectToLogin',), ('Anonymous', 'Authenticated', 'Manager')), diff --git a/config/fix_bug70_db.py b/config/fix_bug70_db.py new file mode 100644 index 0000000..4c0d640 --- /dev/null +++ b/config/fix_bug70_db.py @@ -0,0 +1,64 @@ +# -*- mode: python -*- +# -*- coding: utf-8 -*- + +"""Fix bug #70 + +Utiliser comme: + scotests/scointeractive.sh DEPT config/fix_bug70_db.py + +""" +context = context.Notes # pylint: disable=undefined-variable +REQUEST = REQUEST # pylint: disable=undefined-variable +import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error +import os +import sys +import sco_utils +import notesdb +import sco_formsemestre +import sco_formsemestre_edit +import sco_moduleimpl + +G = sco_fake_gen.ScoFake(context.Notes) + + +def fix_formsemestre_formation_bug70(formsemestre_id): + """Le bug #70 a pu entrainer des incohérences + lors du clonage avorté de semestres. + Cette fonction réassocie le semestre à la formation + à laquelle appartiennent ses modulesimpls. + 2021-04-23 + """ + sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) + cursor = notesdb.SimpleQuery( + context, + """SELECT m.formation_id + FROM notes_modules m, notes_moduleimpl mi + WHERE mi.module_id = m.module_id + AND mi.formsemestre_id = %(formsemestre_id)s + """, + {"formsemestre_id": formsemestre_id}, + ) + modimpls_formations = set([x[0] for x in cursor]) + if len(modimpls_formations) > 1: + # this is should not occur + G.log( + "Warning: fix_formsemestre_formation_bug70: modules from several formations in sem %s" + % formsemestre_id + ) + elif len(modimpls_formations) == 1: + modimpls_formation_id = modimpls_formations.pop() + if modimpls_formation_id != sem["formation_id"]: + # Bug #70: fix + G.log("fix_formsemestre_formation_bug70: fixing %s" % formsemestre_id) + sem["formation_id"] = modimpls_formation_id + context.do_formsemestre_edit(sem, html_quote=False) + + +formsemestre_ids = [ + x[0] + for x in notesdb.SimpleQuery( + context, "SELECT formsemestre_id FROM notes_formsemestre", {} + ) +] +for formsemestre_id in formsemestre_ids: + fix_formsemestre_formation_bug70(formsemestre_id) diff --git a/config/postupgrade.py b/config/postupgrade.py old mode 100755 new mode 100644 index 1137357..b4bc02b --- a/config/postupgrade.py +++ b/config/postupgrade.py @@ -11,21 +11,22 @@ _before_ upgrading the database. E. Viennet, June 2008 Mar 2017: suppress upgrade of very old Apache configs Aug 2020: move photos to .../var/scodoc/ +Apr 2021: bug #70 """ import os import sys import glob -import shutil -from scodocutils import log, SCODOC_DIR, SCODOC_VAR_DIR, SCODOC_LOGOS_DIR +import shutil +from scodocutils import log, SCODOC_DIR, SCODOC_VAR_DIR, SCODOC_LOGOS_DIR, SCO_TMPDIR if os.getuid() != 0: - log('postupgrade.py: must be run as root') + log("postupgrade.py: must be run as root") sys.exit(1) # --- # Migrate photos (2020-08-16, svn 1908) old_photo_dir = os.path.join(SCODOC_DIR, "static", "photos") -photo_dirs = glob.glob( old_photo_dir + "/F*") +photo_dirs = glob.glob(old_photo_dir + "/F*") if photo_dirs: log("Moving photos to new directory...") shutil.move(old_photo_dir, SCODOC_VAR_DIR) @@ -33,7 +34,7 @@ if photo_dirs: # Migrate depts (2020-08-17, svn 1909) old_depts_dir = os.path.join(SCODOC_DIR, "config", "depts") -cfg_files = glob.glob( old_depts_dir + "/*.cfg") +cfg_files = glob.glob(old_depts_dir + "/*.cfg") depts_dir = os.path.join(SCODOC_VAR_DIR, "config/depts/") for cfg in cfg_files: log("Moving %s to new directory..." % cfg) @@ -41,7 +42,7 @@ for cfg in cfg_files: # Move logos if not os.path.exists(SCODOC_LOGOS_DIR): - old_logos = os.path.join(SCODOC_DIR,"logos") + old_logos = os.path.join(SCODOC_DIR, "logos") if os.path.exists(old_logos): log("Moving logos to new directory...") dest = os.path.normpath(os.path.join(SCODOC_LOGOS_DIR, "..")) @@ -50,10 +51,23 @@ if not os.path.exists(SCODOC_LOGOS_DIR): log("Warning: logos directory is missing (%s)" % SCODOC_LOGOS_DIR) # Move dept-specific logos -for d in glob.glob( SCODOC_DIR + "/logos_*" ): +for d in glob.glob(SCODOC_DIR + "/logos_*"): log("Moving %s to %s" % (d, SCODOC_LOGOS_DIR)) shutil.move(d, SCODOC_LOGOS_DIR) +# Fix bug #70 +depts = [ + os.path.splitext(os.path.basename(f))[0] for f in glob.glob(depts_dir + "/*.cfg") +] +for dept in depts: + fixed_filename = SCO_TMPDIR + "/.%s_bug70_fixed" % dept + if not os.path.exists(fixed_filename): + log("fixing #70 on %s" % dept) + os.system("../scotests/scointeractive.sh -x %s config/fix_bug70_db.py" % dept) + # n'essaie qu'une foixs, même en cas d'échec + f = open(fixed_filename, "a") + f.close() + # Continue here... # --- diff --git a/config/scodocutils.py b/config/scodocutils.py old mode 100644 new mode 100755 index 51d6c71..5141d00 --- a/config/scodocutils.py +++ b/config/scodocutils.py @@ -30,6 +30,7 @@ SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "") if not SCODOC_VAR_DIR: log("Error: environment variable SCODOC_VAR_DIR is not defined") sys.exit(1) +SCO_TMPDIR = os.path.join(SCODOC_VAR_DIR, "tmp") SCODOC_LOGOS_DIR = os.environ.get("SCODOC_LOGOS_DIR", "") diff --git a/debug.py b/debug.py index 52a31f7..4b7d3e4 100644 --- a/debug.py +++ b/debug.py @@ -57,18 +57,20 @@ import sco_bulletins_xml # Prend le premier departement comme context -def go(app, n=0): +def go(app, n=0, verbose=True): context = app.ScoDoc.objectValues("Folder")[n].Scolarite - print("context in dept ", context.DeptId()) + if verbose: + print("context in dept ", context.DeptId()) return context -def go_dept(app, dept): +def go_dept(app, dept, verbose=True): objs = app.ScoDoc.objectValues("Folder") for o in objs: context = o.Scolarite if context.DeptId() == dept: - print("context in dept ", context.DeptId()) + if verbose: + print("context in dept ", context.DeptId()) return context raise ValueError("dep %s not found" % dept) diff --git a/notes_table.py b/notes_table.py index 38de314..04be302 100644 --- a/notes_table.py +++ b/notes_table.py @@ -1132,6 +1132,9 @@ class NotesTable: def sem_has_decisions(self): """True si au moins une decision de jury dans ce semestre""" + if [x for x in self.decisions_jury_ues.values() if x]: + return True + return len([x for x in self.decisions_jury_ues.values() if x]) > 0 def etud_has_decision(self, etudid): diff --git a/scotests/scointeractive.sh b/scotests/scointeractive.sh index 2cecaf9..4db0485 100755 --- a/scotests/scointeractive.sh +++ b/scotests/scointeractive.sh @@ -9,9 +9,10 @@ # le département via l'interface web (Zope) usage() { - echo "Usage: $0 [-r] dept [script...]" + echo "Usage: $0 [-h] [-r] [-x] dept [script...]" echo "Lance un environnement interactif python/ScoDoc" echo " -r: supprime et recrée le département (attention: efface la base !)" + echo " -x: exit après exécution des scripts, donc mode non interactif" exit 1 } @@ -20,24 +21,38 @@ cd /opt/scodoc/Products/ScoDoc || exit 2 source config/config.sh source config/utils.sh -if [ $# -lt 1 ] -then - usage -fi +RECREATE_DEPT=0 +PYTHON_INTERACTIVE="-i" -if [ "$1" = "-r" ] -then +while [ -n "$1" ]; do + PARAM="$1" + [ "${PARAM::1}" != "-" ] && break + case $PARAM in + -h | --help) + usage + exit 0 + ;; + -r) + RECREATE_DEPT=1 + ;; + -x) + PYTHON_INTERACTIVE="" + ;; + *) + echo "ERROR: unknown parameter \"$PARAM\"" + usage + exit 1 + ;; + esac shift - recreate_dept=1 -else - recreate_dept=0 -fi +done + DEPT="$1" shift -if [ "$recreate_dept" = 1 ] +if [ "$RECREATE_DEPT" = 1 ] then cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg if [ -e "$cfg_pathname" ] @@ -48,13 +63,17 @@ then # systemctl start scodoc fi -cmd="from __future__ import print_function;from Zope2 import configure;configure('/opt/scodoc/etc/zope.conf');import Zope2; app=Zope2.app();from debug import *;context = go_dept(app, '""$DEPT""');" +cmd="from __future__ import print_function;from Zope2 import configure;configure('/opt/scodoc/etc/zope.conf');import Zope2; app=Zope2.app();from debug import *;context = go_dept(app, '""$DEPT""', verbose=False);" for f in "$@" do cmd="${cmd}exec(open(\"${f}\").read());" done -/opt/zope213/bin/python -i -c "$cmd" - +if [ -z "$PYTHON_INTERACTIVE" ] +then + /opt/zope213/bin/python -c "$cmd" +else + /opt/zope213/bin/python "$PYTHON_INTERACTIVE" -c "$cmd" +fi diff --git a/scotests/test_capitalisation.py b/scotests/test_capitalisation.py index 2bb88fb..7b4532f 100644 --- a/scotests/test_capitalisation.py +++ b/scotests/test_capitalisation.py @@ -11,7 +11,7 @@ Utiliser comme: """ # La variable context est définie par le script de lancement -# l'affecte ainsi pour évietr les warnins pylint: +# l'affecte ainsi pour éviter les warnings pylint: context = context # pylint: disable=undefined-variable import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error import sco_utils