petit refactoring (photos)

This commit is contained in:
Emmanuel Viennet 2021-12-20 22:53:09 +01:00
parent 8532ab5134
commit f1c43a5bb8
5 changed files with 56 additions and 44 deletions

View File

@ -9,7 +9,6 @@ from app import models
from app.models import APO_CODE_STR_LEN from app.models import APO_CODE_STR_LEN
from app.models import SHORT_STR_LEN from app.models import SHORT_STR_LEN
from app.models import CODE_STR_LEN from app.models import CODE_STR_LEN
from app.scodoc import sco_photos
class Identite(db.Model): class Identite(db.Model):
@ -71,9 +70,11 @@ class Identite(db.Model):
"le mail associé à la première adrese de l'étudiant, ou None" "le mail associé à la première adrese de l'étudiant, ou None"
return self.adresses[0].email or None if self.adresses.count() > 0 else None return self.adresses[0].email or None if self.adresses.count() > 0 else None
def to_dict_bul(self): def to_dict_bul(self, include_photo=True):
"""Infos exportées dans les bulletins""" """Infos exportées dans les bulletins"""
return { from app.scodoc import sco_photos
d = {
"civilite": self.civilite, "civilite": self.civilite,
"code_ine": self.code_nip, "code_ine": self.code_nip,
"code_nip": self.code_ine, "code_nip": self.code_ine,
@ -84,9 +85,11 @@ class Identite(db.Model):
"emailperso": self.get_first_email("emailperso"), "emailperso": self.get_first_email("emailperso"),
"etudid": self.id, "etudid": self.id,
"nom": self.nom_disp(), "nom": self.nom_disp(),
"photo_url": sco_photos.get_etud_photo_url(self.id),
"prenom": self.prenom, "prenom": self.prenom,
} }
if include_photo:
d["photo_url"] = (sco_photos.get_etud_photo_url(self.id),)
return d
def inscription_courante(self): def inscription_courante(self):
"""La première inscription à un formsemestre _actuellement_ en cours. """La première inscription à un formsemestre _actuellement_ en cours.

View File

@ -42,9 +42,6 @@ Les images sont servies par ScoDoc, via la méthode getphotofile?etudid=xxx
- support for legacy ZODB removed in v1909. - support for legacy ZODB removed in v1909.
""" """
from flask.helpers import make_response, url_for
from app.scodoc.sco_exceptions import ScoGenError
import datetime import datetime
import glob import glob
import io import io
@ -52,24 +49,26 @@ import os
import random import random
import requests import requests
import time import time
import traceback
import PIL import PIL
from PIL import Image as PILImage from PIL import Image as PILImage
from flask import request, g from flask import request, g
from flask.helpers import make_response, url_for
from config import Config from app import log
from app import db
from app.models import Identite
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_portal_apogee from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app import log from app.scodoc.sco_exceptions import ScoGenError
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from config import Config
# Full paths on server's filesystem. Something like "/opt/scodoc/var/scodoc/photos" # Full paths on server's filesystem. Something like "/opt/scodoc-data/photos"
PHOTO_DIR = os.path.join(Config.SCODOC_VAR_DIR, "photos") PHOTO_DIR = os.path.join(Config.SCODOC_VAR_DIR, "photos")
ICONS_DIR = os.path.join(Config.SCODOC_DIR, "app", "static", "icons") ICONS_DIR = os.path.join(Config.SCODOC_DIR, "app", "static", "icons")
UNKNOWN_IMAGE_PATH = os.path.join(ICONS_DIR, "unknown.jpg") UNKNOWN_IMAGE_PATH = os.path.join(ICONS_DIR, "unknown.jpg")
@ -97,14 +96,15 @@ def get_etud_photo_url(etudid, size="small"):
) )
def etud_photo_url(etud, size="small", fast=False): def etud_photo_url(etud: dict, size="small", fast=False) -> str:
"""url to the image of the student, in "small" size or "orig" size. """url to the image of the student, in "small" size or "orig" size.
If ScoDoc doesn't have an image and a portal is configured, link to it. If ScoDoc doesn't have an image and a portal is configured, link to it.
""" """
photo_url = get_etud_photo_url(etud["etudid"], size=size) photo_url = get_etud_photo_url(etud["etudid"], size=size)
if fast: if fast:
return photo_url return photo_url
path = photo_pathname(etud, size=size) path = photo_pathname(etud["photo_filename"], size=size)
if not path: if not path:
# Portail ? # Portail ?
ext_url = photo_portal_url(etud) ext_url = photo_portal_url(etud)
@ -131,8 +131,8 @@ def get_photo_image(etudid=None, size="small"):
if not etudid: if not etudid:
filename = UNKNOWN_IMAGE_PATH filename = UNKNOWN_IMAGE_PATH
else: else:
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] etud = Identite.query.get_or_404(etudid)
filename = photo_pathname(etud, size=size) filename = photo_pathname(etud.photo_filename, size=size)
if not filename: if not filename:
filename = UNKNOWN_IMAGE_PATH filename = UNKNOWN_IMAGE_PATH
return _http_jpeg_file(filename) return _http_jpeg_file(filename)
@ -171,8 +171,8 @@ def _http_jpeg_file(filename):
return response return response
def etud_photo_is_local(etud, size="small"): def etud_photo_is_local(etud: dict, size="small"):
return photo_pathname(etud, size=size) return photo_pathname(etud["photo_filename"], size=size)
def etud_photo_html(etud=None, etudid=None, title=None, size="small"): def etud_photo_html(etud=None, etudid=None, title=None, size="small"):
@ -215,9 +215,12 @@ def etud_photo_orig_html(etud=None, etudid=None, title=None):
return etud_photo_html(etud=etud, etudid=etudid, title=title, size="orig") return etud_photo_html(etud=etud, etudid=etudid, title=title, size="orig")
def photo_pathname(etud, size="orig"): def photo_pathname(photo_filename: str, size="orig"):
"""Returns full path of image file if etud has a photo (in the filesystem), or False. """Returns full path of image file if etud has a photo (in the filesystem),
or False.
Do not distinguish the cases: no photo, or file missing. Do not distinguish the cases: no photo, or file missing.
Argument: photo_filename (Identite attribute)
Resultat: False or str
""" """
if size == "small": if size == "small":
version = H90 version = H90
@ -225,9 +228,9 @@ def photo_pathname(etud, size="orig"):
version = "" version = ""
else: else:
raise ValueError("invalid size parameter for photo") raise ValueError("invalid size parameter for photo")
if not etud["photo_filename"]: if not photo_filename:
return False return False
path = os.path.join(PHOTO_DIR, etud["photo_filename"]) + version + IMAGE_EXT path = os.path.join(PHOTO_DIR, photo_filename) + version + IMAGE_EXT
if os.path.exists(path): if os.path.exists(path):
return path return path
else: else:
@ -264,15 +267,14 @@ def store_photo(etud, data):
return 1, "ok" return 1, "ok"
def suppress_photo(etud): def suppress_photo(etud: Identite) -> None:
"""Suppress a photo""" """Suppress a photo"""
log("suppress_photo etudid=%s" % etud["etudid"]) log("suppress_photo etudid=%s" % etud.id)
rel_path = photo_pathname(etud) rel_path = photo_pathname(etud.photo_filename)
# 1- remove ref. from database # 1- remove ref. from database
etud["photo_filename"] = None etud.photo_filename = None
cnx = ndb.GetDBConnexion() db.session.add(etud)
sco_etud.identite_edit_nocheck(cnx, etud)
cnx.commit()
# 2- erase images files # 2- erase images files
if rel_path: if rel_path:
# remove extension and glob # remove extension and glob
@ -281,8 +283,10 @@ def suppress_photo(etud):
for filename in filenames: for filename in filenames:
log("removing file %s" % filename) log("removing file %s" % filename)
os.remove(filename) os.remove(filename)
db.session.commit()
# 3- log # 3- log
logdb(cnx, method="changePhoto", msg="suppression", etudid=etud["etudid"]) cnx = ndb.GetDBConnexion()
logdb(cnx, method="changePhoto", msg="suppression", etudid=etud.id)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -373,6 +377,9 @@ def copy_portal_photo_to_fs(etud):
log("copy_portal_photo_to_fs: failure (exception in store_photo)!") log("copy_portal_photo_to_fs: failure (exception in store_photo)!")
if status == 1: if status == 1:
log("copy_portal_photo_to_fs: copied %s" % url) log("copy_portal_photo_to_fs: copied %s" % url)
return photo_pathname(etud), "%s: photo chargée" % etud["nomprenom"] return (
photo_pathname(etud["photo_filename"]),
f"{etud['nomprenom']}: photo chargée",
)
else: else:
return None, "%s: <b>%s</b>" % (etud["nomprenom"], diag) return None, "%s: <b>%s</b>" % (etud["nomprenom"], diag)

View File

@ -183,10 +183,11 @@ def trombino_html(groups_infos):
def check_local_photos_availability(groups_infos, format=""): def check_local_photos_availability(groups_infos, format=""):
"""Verifie que toutes les photos (des gropupes indiqués) sont copiées localement """Vérifie que toutes les photos (des groupes indiqués) sont copiées
dans ScoDoc (seules les photos dont nous disposons localement peuvent être exportées localement dans ScoDoc (seules les photos dont nous disposons localement
en pdf ou en zip). peuvent être exportées en pdf ou en zip).
Si toutes ne sont pas dispo, retourne un dialogue d'avertissement pour l'utilisateur. Si toutes ne sont pas dispo, retourne un dialogue d'avertissement
pour l'utilisateur.
""" """
nb_missing = 0 nb_missing = 0
for t in groups_infos.members: for t in groups_infos.members:
@ -221,7 +222,7 @@ def _trombino_zip(groups_infos):
# assume we have the photos (or the user acknowledged the fact) # assume we have the photos (or the user acknowledged the fact)
# Archive originals (not reduced) images, in JPEG # Archive originals (not reduced) images, in JPEG
for t in groups_infos.members: for t in groups_infos.members:
im_path = sco_photos.photo_pathname(t, size="orig") im_path = sco_photos.photo_pathname(t["photo_filename"], size="orig")
if not im_path: if not im_path:
continue continue
img = open(im_path, "rb").read() img = open(im_path, "rb").read()
@ -294,7 +295,7 @@ def trombino_copy_photos(group_ids=[], dialog_confirmed=False):
def _get_etud_platypus_image(t, image_width=2 * cm): def _get_etud_platypus_image(t, image_width=2 * cm):
"""Returns a platypus object for the photo of student t""" """Returns a platypus object for the photo of student t"""
try: try:
path = sco_photos.photo_pathname(t, size="small") path = sco_photos.photo_pathname(t["photo_filename"], size="small")
if not path: if not path:
# log('> unknown') # log('> unknown')
path = sco_photos.UNKNOWN_IMAGE_PATH path = sco_photos.UNKNOWN_IMAGE_PATH

View File

@ -134,7 +134,7 @@ def get_etud_dept():
last_etud = None last_etud = None
last_date = None last_date = None
for etud in etuds: for etud in etuds:
inscriptions = FormSemestreInscription.query.filter_by(etudid=etud.id).all() inscriptions = FormsemestreInscription.query.filter_by(etudid=etud.id).all()
for ins in inscriptions: for ins in inscriptions:
date_fin = FormSemestre.query.get(ins.formsemestre_id).date_fin date_fin = FormSemestre.query.get(ins.formsemestre_id).date_fin
if (last_date is None) or date_fin > last_date: if (last_date is None) or date_fin > last_date:

View File

@ -49,6 +49,7 @@ from app.decorators import (
admin_required, admin_required,
login_required, login_required,
) )
from app.models.etudiants import Identite
from app.views import scolar_bp as bp from app.views import scolar_bp as bp
@ -944,21 +945,21 @@ def formChangePhoto(etudid=None):
@scodoc7func @scodoc7func
def formSuppressPhoto(etudid=None, dialog_confirmed=False): def formSuppressPhoto(etudid=None, dialog_confirmed=False):
"""Formulaire suppression photo étudiant""" """Formulaire suppression photo étudiant"""
etud = sco_etud.get_etud_info(filled=True)[0] etud = Identite.query.get_or_404(etudid)
if not dialog_confirmed: if not dialog_confirmed:
return scu.confirm_dialog( return scu.confirm_dialog(
"<p>Confirmer la suppression de la photo de %(nomprenom)s ?</p>" % etud, f"<p>Confirmer la suppression de la photo de {etud.nom_disp()} ?</p>",
dest_url="", dest_url="",
cancel_url=url_for( cancel_url=url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
), ),
parameters={"etudid": etudid}, parameters={"etudid": etud.id},
) )
sco_photos.suppress_photo(etud) sco_photos.suppress_photo(etud)
return flask.redirect( return flask.redirect(
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
) )