forked from ScoDoc/ScoDoc
petit refactoring (photos)
This commit is contained in:
parent
8532ab5134
commit
f1c43a5bb8
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
@ -292,9 +293,9 @@ 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 aplatypus 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
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user