Code source de Wiki

#!/usr/bin/python
# -*- coding: utf-8 -*-

u"""Module de la Note Kfet 2015 chargé des éditions des pages wiki."""

import urllib
import urllib2
import sys
import threading
import copy
import datetime
# parser HTML
from BeautifulSoup import BeautifulSoup

# Avant toute chose, on n'a pas envie d'être au mauvais endroit
# On est obligé de le faire tout de suite, avant d'importer ../config
import os
thisfile = os.path.realpath(__file__)
thisdirectory = thisfile.rsplit("/", 1)[0]
os.chdir(thisdirectory)

sys.path.append("../config")
import config
import BaseFonctions

# Pour avoir les jours en français
import locale
locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8")

# On déclare les textes utlisés pour render les pages

acl_header = u"#acl NoteKfet2015:read,write,admin All:read Default\n"

warning_header = u"""## NE PAS ÉDITER CETTE PAGE MANUELLEMENT
## ELLE EST GÉNÉRÉE AUTOMATIQUEMENT PAR LA NOTE KFET 2015
## Made by 20-100, largement inspiré de la version de Barbichu.

"""

intro_calendar_raw = u"""= Introduction =

 * Cette page a pour but de recenser les activités BDE afin d'être signalées sur le calendrier de la [[PageAccueil|page d'accueil]] du wiki.
"""

intro_calendar_humanreadable = u"""= Planning de soirées =
== Introduction ==
 * Cette page est destinée à accueillir le planning des soirées BDE.
"""

intro_generic = u""" * Elle est générée automatiquement par la [[NoteKfet/NoteKfet2015|Note Kfet 2015]]
 * Ne pas éditer cette page manuellement, toute modification sera annulée automatiquement.
 * Pour annoncer un nouvel événement, rendez-vous sur %smes_activites

""" % config.url_note

intro_future = u"""== Planning des activités à venir ==
||'''Date''' ||'''Jour''' ||'''Description'''||'''Par''' ||'''Lieu'''||
"""

intro_past = u"""== Planning des activités passées ==
||'''Date''' ||'''Jour''' ||'''Club''' ||'''Par'''||'''Lieu'''||
"""

template_raw = u"""== %(titre)s ==
 start:: %(debut)s
 end:: %(fin)s
 description:: %(description)s -- %(signature)s
 location:: %(lieu)s
"""

template_humanreadable = u"""|| %(date)s || %(jour)s || %(titre)s%(description_formatted)s || %(signature)s || %(lieu)s ||"""

footer_raw = u"\n----\nCatégorieCalendrierCampus"

[docs]def connection(url): """Se logue sur le wiki et renvoie le cookie de session""" parameters = {'action': 'login', 'login': 'Connexion', 'name': config.wiki_pseudo, 'password': config.wiki_password} # Il faut encoder ça proprement data = urllib.urlencode(parameters) request = urllib2.Request(url, data) # La requête est envoyée en HTTP POST response = urllib2.urlopen(request) # a priori la page elle-même je m'en carre… page = response.read(2) # …ce qui m'intéresse, c'est le cookie qu'elle me file cookie = response.headers['set-cookie'] return cookie
[docs]def get_edition_ticket(url, cookie): """Récupère le ticket d'édition de la page""" # On crée la requête d'édition… suffix = "?action=edit&editor=text" request = urllib2.Request(url + suffix) # …avec le cookie request.add_header("Cookie", cookie) # On l'envoie pagecontent = urllib2.urlopen(request) html = pagecontent.read() soup = BeautifulSoup(html) # On va chercher le formulaire form = soup.find(name="form", attrs={"id": "editor"}) # On récupère le ticket dedans ticket = soup.find(name="input", attrs={"name": "ticket"}) return ticket["value"]
[docs]def modif_wiki(page, content, comment=''): """Modifie une page du wiki""" url = "https://wiki.crans.org/" + page # On définit ce qu'on va faire dans une fonction pour # pouvoir l'exécuter dans un thread fils et pas avoir à # attendre que les choses se fassent def send_modif(): # On se connecte et on récupère le cookie de session cookie = connection(url) # On demande l'édition et on récupère le ticket d'édition de la page ticket = get_edition_ticket(url, cookie) # On construit la requête data = {'button_save': 'Enregistrer les modifications', 'category': '', 'comment': comment.encode("utf-8"), 'savetext': content.encode("utf-8"), 'action': 'edit', 'ticket': ticket } request = urllib2.Request(url, urllib.urlencode(data)) request.add_header("Cookie", cookie) # On la poste urllib2.urlopen(request) # On lance tout ça dans un thread fils threading.Thread(target=send_modif).start()
[docs]def str_activite(act, raw=True): """Wiki-formate une activité, pour le calendrier raw si ``raw``, pour le human-readable sinon.""" # Comme on va bidouiller le dico, on préfère en faire une copie act = copy.deepcopy(dict(act)) template = template_raw if raw else template_humanreadable if raw: act["debut"] = act["debut"].strftime("%Y-%m-%d %H:%M") act["fin"] = act["fin"].strftime("%Y-%m-%d %H:%M") else: # La "date" d'une activité est son jour de début act["jour"] = act["debut"].strftime("%A").title() act["date"] = act["debut"].strftime("%d/%m/%Y") d = act["description"] act["description_formatted"] = (u" (%s)" % d) if d else u"" return template % act
[docs]def update_calendrier(liste_activites, really_update=False, comment="", raw=True): """Met à jour la page du Calendrier des activités si ``raw``, le planning sinon.""" page = config.wiki_calendar_raw if raw else config.wiki_calendar_humanreadable header = acl_header + warning_header if raw: header += intro_calendar_raw body = "\n".join([str_activite(a, raw=raw) for a in liste_activites]) footer = footer_raw else: header += intro_calendar_humanreadable now = datetime.datetime.now() future = intro_future future += u"\n".join([str_activite(a, raw=raw) for a in liste_activites if a["debut"] > now]) past = intro_past past += u"\n".join([str_activite(a, raw=raw) for a in liste_activites if a["debut"] <= now]) body = future + u"\n\n" + past footer = u"" header += intro_generic content = header + body + footer if really_update: modif_wiki(page, content, comment) else: print content.encode("utf-8")
[docs]def get_activites(): """Va chercher la liste des activités dans la table.""" con, cur = BaseFonctions.getcursor() # Le "ORDER BY debut, nom" permet d'avoir un ordre déterministe pour les activités ayant même début cur.execute("SELECT * FROM activites WHERE validepar > 0 ORDER BY debut DESC, titre ASC;") l = cur.fetchall() return l
[docs]def refresh_calendar(comment): """Fonction appelée par la note en cas de validation/dévalidation.""" activites = get_activites() update_calendrier(activites, really_update=True, comment=comment, raw=True) update_calendrier(activites, really_update=True, comment=comment, raw=False)
if __name__ == "__main__": activites = get_activites() really_update = not("--debug" in sys.argv) if "--human" in sys.argv: update_calendrier(activites, really_update, comment=u"refresh", raw=False) if "--raw" in sys.argv: update_calendrier(activites, really_update, comment=u"refresh", raw=True)