# -*- 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 # ############################################################################## """Gestions des "nouvelles" """ import PyRSS2Gen # pylint: disable=import-error from cStringIO import StringIO import datetime, re import time from stripogram import html2text, html2safehtml from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.header import Header from notesdb import * # pylint: disable=unused-wildcard-import from notes_log import log import scolars from sco_utils import SCO_ENCODING, SCO_ANNONCES_WEBSITE import sco_formsemestre import sco_moduleimpl _scolar_news_editor = EditableTable( "scolar_news", "news_id", ("date", "authenticated_user", "type", "object", "text", "url"), sortkey="date desc", output_formators={"date": DateISOtoDMY}, input_formators={"date": 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 = 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(context, REQUEST, 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 = str(REQUEST.AUTHENTICATED_USER) cnx = context.GetDBConnexion() args = { "authenticated_user": authuser_name, "user_info": context.Users.user_info(user_name=authuser_name), "type": typ, "object": object, "text": text, "url": url, } log("news: %s" % args) 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 _LAST_NEWS[(authuser_name, typ, object)] = t _send_news_by_mail(context, args) return scolar_news_create(cnx, args, has_uniq_values=False) def scolar_news_summary(context, n=5): """Return last n news. News are "compressed", ie redondant events are joined. """ cnx = context.GetDBConnexion() cursor = cnx.cursor(cursor_factory=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 = DateISOtoDMY(r["date"]) # round key = (r["type"], r["object"], dmy) selected_news[key] = r news = selected_news.values() # sort by date, descending news.sort(lambda x, y: cmp(y["date"], x["date"])) 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") n["rssdate"] = n["date"].strftime("%d/%m %Hh%M") # pour affichage for k in n.keys(): if n[k] is None: n[k] = "" if _scolar_news_editor.output_formators.has_key(k): n[k] = _scolar_news_editor.output_formators[k](n[k]) # date resumee j, m = n["date"].split("/")[:2] mois = scolars.abbrvmonthsnames[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 " + context.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, rssicon=None): """News summary, formated in HTML""" news = scolar_news_summary(context, n=n) if not news: return "" H = ['