From 72c63812fa7c82d4f596543734f7e5974b69811a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 26 Aug 2021 23:43:54 +0200 Subject: [PATCH] fonctions d'envoi de mails --- app/email.py | 13 ++- app/scodoc/notes_log.py | 24 ++--- app/scodoc/sco_abs_notification.py | 30 +++--- app/scodoc/sco_bulletins.py | 35 +++---- app/scodoc/sco_emails.py | 146 ----------------------------- app/scodoc/sco_etud.py | 14 +-- app/scodoc/sco_import_users.py | 16 ++-- app/scodoc/sco_news.py | 26 ++--- app/scodoc/sco_utils.py | 2 +- app/static/icons/scologo_img.png | Bin 17276 -> 18058 bytes sco_version.py | 2 +- tools/build_release.sh | 23 ++++- tools/configure-scodoc9.sh | 4 +- tools/get_scodoc_version.sh | 9 +- 14 files changed, 91 insertions(+), 253 deletions(-) delete mode 100644 app/scodoc/sco_emails.py diff --git a/app/email.py b/app/email.py index f2d8164d8c..226429df24 100644 --- a/app/email.py +++ b/app/email.py @@ -10,10 +10,21 @@ def send_async_email(app, msg): mail.send(msg) -def send_email(subject, sender, recipients, text_body, html_body): +def send_email( + subject: str, sender: str, recipients: list, text_body: str, html_body="" +): + """ + Send an email + If html_body is specified, build a multipart message with HTML content, + else send a plain text email. + """ msg = Message(subject, sender=sender, recipients=recipients) msg.body = text_body msg.html = html_body + send_message(msg) + + +def send_message(msg): Thread( target=send_async_email, args=(current_app._get_current_object(), msg) ).start() diff --git a/app/scodoc/notes_log.py b/app/scodoc/notes_log.py index 0781373405..6f91ec1220 100644 --- a/app/scodoc/notes_log.py +++ b/app/scodoc/notes_log.py @@ -4,12 +4,11 @@ import os import time import traceback -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.header import Header from flask import g, current_app +from app import email + """Simple & stupid file logguer, used only to debug (logging to SQL is done in scolog) """ @@ -19,7 +18,7 @@ DEFAULT_LOG_DIR = ( "/opt/scodoc-data/log" # clients should call set_log_directory to change this ) -ALARM_DESTINATION = "emmanuel.viennet@gmail.com" # XXX a mettre en preference +ALARM_DESTINATION = "emmanuel@scodoc.org" class _logguer(object): @@ -66,20 +65,11 @@ log = _logguer() # Alarms by email: -def sendAlarm(subj, txt): - from . import sco_utils - from . import sco_emails - from . import sco_preferences +def sendAlarm(subject, txt): + from app.scodoc import sco_preferences - msg = MIMEMultipart() - subj = Header(subj, sco_utils.SCO_ENCODING) - msg["Subject"] = subj - msg["From"] = sco_preferences.get_preference("email_from_addr") - msg["To"] = ALARM_DESTINATION - msg.epilogue = "" - txt = MIMEText(txt, "plain", sco_utils.SCO_ENCODING) - msg.attach(txt) - sco_emails.sendEmail(msg) + sender = sco_preferences.get_preference("email_from_addr") + email.send_email(subject, sender, [ALARM_DESTINATION], txt) # Debug: log call stack diff --git a/app/scodoc/sco_abs_notification.py b/app/scodoc/sco_abs_notification.py index c397c73f0a..5ac4315ef8 100644 --- a/app/scodoc/sco_abs_notification.py +++ b/app/scodoc/sco_abs_notification.py @@ -33,13 +33,9 @@ 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 flask import g, url_for +from flask_mail import Message -from app.scodoc import sco_emails import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app.scodoc.notes_log import log @@ -48,6 +44,7 @@ from app.scodoc import sco_etud from app.scodoc import sco_formsemestre from app.scodoc import sco_preferences from app.scodoc import sco_users +from app import email def abs_notify(etudid, date): @@ -108,12 +105,11 @@ def abs_notify_send(destinations, etudid, msg, nbabs, nbabsjust, formsemestre_id cnx = ndb.GetDBConnexion() log("abs_notify: sending notification to %s" % destinations) cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) - for email in destinations: - del msg["To"] - msg["To"] = email - sco_emails.sendEmail(msg) + for dest_addr in destinations: + msg.recipients = [dest_addr] + email.send_message(msg) ndb.SimpleQuery( - """insert into absences_notifications + """INSERT into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) VALUES (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s) """, @@ -229,7 +225,8 @@ def user_nbdays_since_last_notif(email_addr, etudid): def abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust): """Mime notification message based on template. - returns None if sending should be canceled (emplty template). + returns a Message instance + or None if sending should be canceled (empty template). """ from app.scodoc import sco_bulletins @@ -252,14 +249,9 @@ def abs_notification_message(sem, prefs, etudid, nbabs, nbabsjust): log("abs_notification_message: empty template, not sending message") return None - subject = """Trop d'absences pour %(nomprenom)s""" % etud - # - msg = MIMEMultipart() - subj = Header("[ScoDoc] " + subject, scu.SCO_ENCODING) - msg["Subject"] = subj - msg["From"] = prefs["email_from_addr"] - txt = MIMEText(txt, "plain", scu.SCO_ENCODING) - msg.attach(txt) + subject = """[ScoDoc] Trop d'absences pour %(nomprenom)s""" % etud + msg = Message(subject, sender=prefs["email_from_addr"]) + msg.body = txt return msg diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 9cbff15581..c1ce03ef62 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -42,8 +42,8 @@ import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error from flask import g from flask import url_for from flask_login import current_user +from flask_mail import Message -from app.scodoc import sco_emails import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc.notes_log import log @@ -68,7 +68,7 @@ from app.scodoc import sco_photos from app.scodoc import sco_preferences from app.scodoc import sco_pvjury from app.scodoc import sco_users - +from app import email # ----- CLASSES DE BULLETINS DE NOTES from app.scodoc import sco_bulletins_standard @@ -983,28 +983,21 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr): etud["etudid"], with_evals=False, format="text" ) - msg = MIMEMultipart() - subj = Header("Relevé de notes de %s" % etud["nomprenom"], scu.SCO_ENCODING) + subject = "Relevé de notes de %s" % etud["nomprenom"] recipients = [recipient_addr] - msg["Subject"] = subj - msg["From"] = sco_preferences.get_preference("email_from_addr", formsemestre_id) - msg["To"] = " ,".join(recipients) + sender = sco_preferences.get_preference("email_from_addr", formsemestre_id) if copy_addr: - msg["Bcc"] = copy_addr.strip() - # Guarantees the message ends in a newline - msg.epilogue = "" - # Text - txt = MIMEText(hea, "plain", scu.SCO_ENCODING) - # log('hea:\n' + hea) - msg.attach(txt) + bcc = copy_addr.strip() + else: + bcc = "" + msg = Message(subject, sender=sender, recipients=recipients, bcc=bcc) + msg.body = hea + # Attach pdf - att = MIMEBase("application", "pdf") - att.add_header("Content-Disposition", "attachment", filename=filename) - att.set_payload(pdfdata) - email.encoders.encode_base64(att) - msg.attach(att) - log("mail bulletin a %s" % msg["To"]) - sco_emails.sendEmail(msg) + msg.attach(filename, scu.PDF_MIMETYPE, pdfdata) + + log("mail bulletin a %s" % recipient_addr) + email.send_message(msg) def _formsemestre_bulletinetud_header_html( diff --git a/app/scodoc/sco_emails.py b/app/scodoc/sco_emails.py deleted file mode 100644 index a50db77f9d..0000000000 --- a/app/scodoc/sco_emails.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- mode: python -*- -# -*- coding: utf-8 -*- - -############################################################################## -# -# Gestion scolarite IUT -# -# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Emmanuel Viennet emmanuel.viennet@viennet.net -# -############################################################################## - -"""Gestion des emails -""" - -from flask import request - - -# XXX WIP: à ré-écrire pour ScoDoc 8 (étaient des méthodes de ZScoDoc) -import os -import time - -# 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 app.scodoc.sco_utils as scu -from app.scodoc.notes_log import log -import sco_version - - -def sendEmail(msg): # TODO A REECRIRE ScoDoc8 - """Send an email to the address using the mailhost, if there is one.""" - raise NotImplementedError() - try: - mail_host = xxx.MailHost - except: - log("warning: sendEmail: no MailHost found !") - return - # a failed notification shouldn't cause a Zope error on a site. - try: - mail_host.send(msg.as_string()) - log("sendEmail: ok") - except Exception as e: - log("sendEmail: exception while sending message") - log(e) - pass - - -def sendEmailFromException(msg): - # Send email by hand, as it seems to be not possible to use Zope Mail Host - # from an exception handler (see https://bugs.launchpad.net/zope2/+bug/246748) - log("sendEmailFromException") - try: - p = os.popen("sendmail -t", "w") # old brute force method - p.write(msg.as_string()) - exitcode = p.close() - if exitcode: - log("sendmail exit code: %s" % exitcode) - except: - log("an exception occurred sending mail") - - -def send_debug_alert(txt, REQUEST=None): - """Send an alert email (bug report) to ScoDoc developpers""" - if not scu.SCO_EXC_MAIL: - log("send_debug_alert: email disabled") - return - if REQUEST: - txt = _report_request(REQUEST) + txt - URL = REQUEST.URL - else: - URL = "send_debug_alert" - msg = MIMEMultipart() - subj = Header("[scodoc] exc %s" % URL, scu.SCO_ENCODING) - msg["Subject"] = subj - recipients = [scu.SCO_EXC_MAIL] - msg["To"] = " ,".join(recipients) - msg["From"] = "scodoc-alert" - msg.epilogue = "" - msg.attach(MIMEText(txt, "plain", scu.SCO_ENCODING)) - sendEmailFromException(msg) - log("Sent mail alert:\n" + txt) - - -def _report_request(REQUEST, fmt="txt"): - """string describing current request for bug reports""" - QUERY_STRING = REQUEST.QUERY_STRING - if QUERY_STRING: - QUERY_STRING = "?" + QUERY_STRING - if fmt == "txt": - REFERER = request.referrer - HTTP_USER_AGENT = request.user_agent - else: - REFERER = "na" - HTTP_USER_AGENT = "na" - - params = dict( - AUTHENTICATED_USER=REQUEST.AUTHENTICATED_USER, - dt=time.asctime(), - URL=REQUEST.URL, - QUERY_STRING=QUERY_STRING, - METHOD=request.method, - REFERER=REFERER, - HTTP_USER_AGENT=HTTP_USER_AGENT, - form=REQUEST.form, - HTTP_X_FORWARDED_FOR="?", - SCOVERSION=sco_version.SCOVERSION, - ) - txt = ( - """ -Version: %(SCOVERSION)s -User: %(AUTHENTICATED_USER)s -Date: %(dt)s -URL: %(URL)s%(QUERY_STRING)s -Method: %(METHOD)s - -REFERER: %(REFERER)s -Form: %(form)s -Origin: %(HTTP_X_FORWARDED_FOR)s -Agent: %(HTTP_USER_AGENT)s -""" - % params - ) - if fmt == "html": - txt = txt.replace("\n", "
") - return txt \ No newline at end of file diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index 0d8682a5e3..7915b0af6d 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -40,7 +40,6 @@ from email.header import Header from email.mime.base import MIMEBase from operator import itemgetter -from app.scodoc import sco_emails import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import SCO_ENCODING import app.scodoc.notesdb as ndb @@ -51,6 +50,8 @@ from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc import safehtml from app.scodoc import sco_preferences from app.scodoc.scolog import logdb +from flask_mail import Message +from app import mail MONTH_NAMES_ABBREV = [ "Jan ", @@ -454,14 +455,9 @@ def notify_etud_change(email_addr, etud, before, after, subject): log("notify_etud_change: sending notification to %s" % email_addr) log("notify_etud_change: subject: %s" % subject) log(txt) - msg = MIMEMultipart() - subj = Header("[ScoDoc] " + subject, SCO_ENCODING) - msg["Subject"] = subj - msg["From"] = sco_preferences.get_preference("email_from_addr") - msg["To"] = email_addr - mime_txt = MIMEText(txt, "plain", SCO_ENCODING) - msg.attach(mime_txt) - sco_emails.sendEmail(msg) + mail.send_email( + subject, sco_preferences.get_preference("email_from_addr"), [email_addr], txt + ) return txt diff --git a/app/scodoc/sco_import_users.py b/app/scodoc/sco_import_users.py index 81ba3a4eac..3a46257c3f 100644 --- a/app/scodoc/sco_import_users.py +++ b/app/scodoc/sco_import_users.py @@ -35,7 +35,6 @@ from email.mime.text import MIMEText from email.header import Header from app import db, Departement -from app.scodoc import sco_emails import app.scodoc.sco_utils as scu from app.scodoc.notes_log import log from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException @@ -47,6 +46,9 @@ from flask import g from flask_login import current_user from app.auth.models import User, UserRole +from app import email + + TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept") COMMENTS = ( """user_name: @@ -335,12 +337,8 @@ Pour plus d'informations sur ce logiciel, voir %s ) msg = MIMEMultipart() if reset: - msg["Subject"] = Header("Mot de passe ScoDoc", scu.SCO_ENCODING) + subject = "Mot de passe ScoDoc" else: - msg["Subject"] = Header("Votre accès ScoDoc", scu.SCO_ENCODING) - msg["From"] = sco_preferences.get_preference("email_from_addr") - msg["To"] = u["email"] - msg.epilogue = "" - txt = MIMEText(txt, "plain", scu.SCO_ENCODING) - msg.attach(txt) - # sco_emails.sendEmail(msg) # TODO ScoDoc9 pending function + subject = "Votre accès ScoDoc" + sender = sco_preferences.get_preference("email_from_addr") + email.send_email(subject, sender, [u["email"]], txt) diff --git a/app/scodoc/sco_news.py b/app/scodoc/sco_news.py index a564bfd8c8..22d50fae3d 100644 --- a/app/scodoc/sco_news.py +++ b/app/scodoc/sco_news.py @@ -27,13 +27,10 @@ """Gestion des "nouvelles" """ -import datetime import re import time -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.header import Header + from operator import itemgetter from flask import g @@ -42,13 +39,12 @@ from flask_login import current_user import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc.notes_log import log -from app.scodoc import safehtml -from app.scodoc import sco_emails -from app.scodoc.sco_utils import SCO_ENCODING, SCO_ANNONCES_WEBSITE from app.scodoc import sco_formsemestre from app.scodoc import sco_moduleimpl from app.scodoc import sco_preferences from app.scodoc import sco_users +from app import email + _scolar_news_editor = ndb.EditableTable( "scolar_news", @@ -225,7 +221,7 @@ def scolar_news_summary_html(n=5): abonner à la liste de diffusion. """ - % SCO_ANNONCES_WEBSITE + % scu.SCO_ANNONCES_WEBSITE ) H.append("") @@ -270,15 +266,7 @@ def _send_news_by_mail(n): # (si on veut des messages non html) txt = re.sub(r'(.*?)', r"\2: \1", txt) - msg = MIMEMultipart() - msg["Subject"] = Header("[ScoDoc] " + NEWS_MAP.get(n["type"], "?"), SCO_ENCODING) - msg["From"] = prefs["email_from_addr"] - txt = MIMEText(txt, "plain", SCO_ENCODING) - msg.attach(txt) + subject = "[ScoDoc] " + NEWS_MAP.get(n["type"], "?") + sender = prefs["email_from_addr"] - for email_addr in destinations: - if email_addr: - del msg["To"] - msg["To"] = email_addr - # log('xxx mail: %s' % msg) - sco_emails.sendEmail(msg) + email.send_email(subject, sender, destinations, txt) diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 72aba2be28..1a54104488 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -561,7 +561,7 @@ def sendResult(REQUEST, data, name=None, format=None, force_outer_xml_tag=True): def get_scodoc_version(): "return a string identifying ScoDoc version" - return os.popen("cd %s; ./get_scodoc_version.sh -s" % SCO_TOOLS_DIR).read().strip() + return sco_version.SCOVERSION def check_scodoc7_password(scodoc7_hash, password): diff --git a/app/static/icons/scologo_img.png b/app/static/icons/scologo_img.png index 2c55de0f05e35c3f8c6cf2f5dab013b6f8b0e0a2..830e1266848ebc642f1f734ec74170710e95b7df 100644 GIT binary patch delta 17437 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 /dev/null && pwd )" @@ -15,7 +17,7 @@ SCODOC_RELEASE=$(grep SCOVERSION "$SCRIPT_DIR/../sco_version.py" | awk '{ print # Dernière release GITEA_RELEASE_URL="https://scodoc.org/git/api/v1/repos/viennet/ScoDoc/releases?pre-release=true" -LAST_RELEASE_TAG=$(curl "$GITEA_RELEASE_URL" | jq ".[].tag_name" | sort | tail -1 | awk '{ print substr($1, 1, length($1)) }') +LAST_RELEASE_TAG=$(curl "$GITEA_RELEASE_URL" | jq ".[].tag_name" | sort | tail -1 | awk '{ print substr($1, 2, length($1)-2) }') echo echo "Version détectée dans le source: $SCODOC_RELEASE" @@ -75,7 +77,7 @@ SCODOC_DIR="$optdir"/scodoc [ -d "$SCODOC_DIR" ] || die "die Erreur: $SCODOC_DIR inexistant" # Inject version (eg 9.0.2) in debian:control -sed -i.bak "s/Version: x.y.z/Version: $PACKAGE_VERSION/g" /tmp/control +sed -i.bak "s/Version: x.y.z/Version: $PACKAGE_VERSION/g" "$SCODOC_DIR/tools/debian/control" # and double check v=$(grep Version "$SCODOC_DIR/tools/debian/control" | awk '{ print $2 }') if [ "$v" != "$PACKAGE_VERSION" ] @@ -106,7 +108,20 @@ chmod 755 "$slash"/DEBIAN/*inst || die "can't chmod debian scripts" # -------- THE END echo "Terminé." -echo "Après vérification, construire le paquet .deb avec:" -echo " dpkg-deb --build --root-owner-group $DEST_DIR" + +echo -n "Voulez-vous poursuivre et construire le .deb ? (y/n) [y] " +read -r ans +if [ "$(norm_ans "$ans")" != 'N' ] +then + echo "ok" +else + echo "arrêt." + exit 0 +fi + +dpkg-deb --build --root-owner-group $DEST_DIR +DEB_FILE="$DEST_DIR".deb +echo "paquet construit: $DEB_FILE" + diff --git a/tools/configure-scodoc9.sh b/tools/configure-scodoc9.sh index 0f2f694f4b..2c60d1563f 100755 --- a/tools/configure-scodoc9.sh +++ b/tools/configure-scodoc9.sh @@ -111,8 +111,8 @@ change_scodoc_file_ownership # ------------ CREATION BASE DE DONNEES echo echo "Voulez-vous créer la base SQL SCODOC ?" -echo "répondre O sauf si vous avez déjà une base existante" -echo "que vous souhaitez conserver." +echo "répondre oui sauf si vous avez déjà une base existante" +echo "que vous souhaitez conserver (mais pour les migrations, répondre oui)." echo -n 'Créer la base de données SCODOC ? (y/n) [y] ' read -r ans if [ "$(norm_ans "$ans")" != 'N' ] diff --git a/tools/get_scodoc_version.sh b/tools/get_scodoc_version.sh index 767eec454c..9c06bfcad9 100755 --- a/tools/get_scodoc_version.sh +++ b/tools/get_scodoc_version.sh @@ -1,5 +1,7 @@ #!/bin/bash +# Script non utilisé + # Get version information # Use VERSION.py, VERSION, last commit, diff, and last upstream commit date @@ -10,11 +12,10 @@ source "$SCRIPT_DIR/config.sh" source "$SCRIPT_DIR/utils.sh" # Source code version: -x=$(grep SCOVERSION "$SCODOC_DIR/app/scodoc/VERSION.py") || terminate "can't access VERSION.py" 1 -x=${x#*\"} -src_version=${x%\"*} +src_version=$(grep SCOVERSION "$SCRIPT_DIR/../sco_version.py" | awk '{ print substr($3, 2, length($3)-2) }') -release_version=$(cat "$SCODOC_DIR/VERSION") + +release_version="" git status >& /dev/null if [ $? = 0 ]