# -*- 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 "nouvelles" """ import datetime import re import time from io import StringIO from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.header import Header from operator import itemgetter import six 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 _scolar_news_editor = ndb.EditableTable( "scolar_news", "news_id", ("date", "authenticated_user", "type", "object", "text", "url"), sortkey="date desc", output_formators={"date": ndb.DateISOtoDMY}, input_formators={"date": ndb.DateDMYtoISO}, html_quote=False, # no user supplied data, needed to store html links ) NEWS_INSCR = "INSCR" # inscription d'étudiants (object=None ou formsemestre_id) NEWS_NOTE = "NOTES" # saisie note (object=moduleimpl_id) NEWS_FORM = "FORM" # modification formation (object=formation_id) NEWS_SEM = "SEM" # creation semestre (object=None) NEWS_MISC = "MISC" # unused NEWS_MAP = { NEWS_INSCR: "inscription d'étudiants", NEWS_NOTE: "saisie note", NEWS_FORM: "modification formation", NEWS_SEM: "création semestre", NEWS_MISC: "opération", # unused } NEWS_TYPES = list(NEWS_MAP.keys()) scolar_news_create = _scolar_news_editor.create scolar_news_list = _scolar_news_editor.list _LAST_NEWS = {} # { (authuser_name, type, object) : time } def add(typ, object=None, text="", url=None, max_frequency=False): """Ajoute une nouvelle. Si max_frequency, ne genere pas 2 nouvelles identiques à moins de max_frequency secondes d'intervalle. """ authuser_name = current_user.user_name cnx = ndb.GetDBConnexion() args = { "authenticated_user": authuser_name, "user_info": sco_users.user_info(user_name=authuser_name), "type": typ, "object": object, "text": text, "url": url, } t = time.time() if max_frequency: last_news_time = _LAST_NEWS.get((authuser_name, typ, object), False) if last_news_time and (t - last_news_time < max_frequency): # log("not recording") return log("news: %s" % args) _LAST_NEWS[(authuser_name, typ, object)] = t _send_news_by_mail(args) return scolar_news_create(cnx, args) def scolar_news_summary(context, n=5): """Return last n news. News are "compressed", ie redondant events are joined. """ from app.scodoc import sco_etud cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor.execute("select * from scolar_news order by date desc limit 100") selected_news = {} # (type,object) : news dict news = cursor.dictfetchall() # la plus récente d'abord for r in reversed(news): # la plus ancienne d'abord # si on a deja une news avec meme (type,object) # et du meme jour, on la remplace dmy = ndb.DateISOtoDMY(r["date"]) # round key = (r["type"], r["object"], dmy) selected_news[key] = r news = list(selected_news.values()) # sort by date, descending news.sort(key=itemgetter("date"), reverse=True) news = news[:n] # mimic EditableTable.list output formatting: for n in news: n["date822"] = n["date"].strftime("%a, %d %b %Y %H:%M:%S %z") # heure n["hm"] = n["date"].strftime("%Hh%M") for k in n.keys(): if n[k] is None: n[k] = "" if k in _scolar_news_editor.output_formators: n[k] = _scolar_news_editor.output_formators[k](n[k]) # date resumee j, m = n["date"].split("/")[:2] mois = sco_etud.MONTH_NAMES_ABBREV[int(m) - 1] n["formatted_date"] = "%s %s %s" % (j, mois, n["hm"]) # indication semestre si ajout notes: infos = _get_formsemestre_infos_from_news(context, n) if infos: n["text"] += ( ' (%(descr_sem)s)' % infos ) n["text"] += ( " par " + sco_users.user_info(user_name=n["authenticated_user"])["nomcomplet"] ) return news def _get_formsemestre_infos_from_news(context, n): """Informations sur le semestre concerné par la nouvelle n {} si inexistant """ formsemestre_id = None if n["type"] == NEWS_INSCR: formsemestre_id = n["object"] elif n["type"] == NEWS_NOTE: moduleimpl_id = n["object"] mods = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id) if not mods: return {} # module does not exists anymore mod = mods[0] formsemestre_id = mod["formsemestre_id"] if not formsemestre_id: return {} try: sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) except: # semestre n'existe plus return {} if sem["semestre_id"] > 0: descr_sem = "S%d" % sem["semestre_id"] else: descr_sem = "" if sem["modalite"]: descr_sem += " " + sem["modalite"] return {"formsemestre_id": formsemestre_id, "sem": sem, "descr_sem": descr_sem} def scolar_news_summary_html(context, n=5): """News summary, formated in HTML""" news = scolar_news_summary(context, n=n) if not news: return "" H = ['