Skip to content
Extraits de code Groupes Projets
adl-submit.py 15,3 ko
Newer Older
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (C) 2005 Thomas Petazzoni <thomas.petazzoni@enix.org>
#
# 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; version 2 of the License.
#
# 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

import xml.dom.minidom
import getopt
import sys
import pycurl
import StringIO
import re
import time
import locale

baseUrl = "http://www.agendadulibre.org/"
#baseUrl = "http://localhost:3000/"

locale.setlocale(locale.LC_ALL, ('fr_FR', 'utf-8'))

eventFields = [ "title", "start-date", "end-date", "start-hour",
                "end-hour", "description", "place_name", "address", "city",
                "region", "url", "contact", "submitter", "tags" ]
   u'Alsace-Champagne-Ardenne-Lorraine'  : 1,
   u'Aquitaine-Limousin-Poitou-Charentes': 2,
   u'Auvergne-Rhône-Alpes'               : 3,
   u'Normandie'                          : 4,
   u'Bourgogne-Franche-Comté'            : 5,
   u'Bretagne'                           : 6,
   u'Centre-Val de Loire'                : 7,
   u'Corse'                              : 9,
   u'Île-de-France'                      : 12,
   u'Languedoc-Roussillon-Midi-Pyrénées' : 13,
   u'Provence-Alpes-Côte-d\'Azur'        : 21,
   u'Pays de la Loire'                   : 18,
   u'Guadeloupe'                         : 23,
   u'Guyane'                             : 24,
   u'Martinique'                         : 25,
   u'La Réunion'                         : 26,
   u'Autre pays'                         : 27,
   u'Mayotte'                            : 28,
   u'Collectivités d\'outre-mer'         : 29,
   u'Collectivité sui generis'           : 30
}

def Usage():
    print u"""Soumettre un évènement dans l'Agenda du Libre

Options:
    --file        event.xml   Fichier XML décrivant l'évènement.
    --test-output test.html   Fichier de sortie HTML de test
    --start-date  YYYY-MM-DD  Date de début de l'évènement.
    --end-date    YYYY-MM-DD  Date de fin de l'évènement.
    --start-hour  HH:MM       Heure de début de l'évènement.
    --end-hour    HH:MM       Heure de fin de l'évènement.
    --title       chaine      Titre de l'évènement.
    --description chaine-html Description de l'évènement.
    --place_name  chaine      Nom du lieu (pas utilisé par OSM)
    --address     chaine      Position de l'événement (utile pour une carte OSM).
    --city        chaine      Ville de l'évènement.
    --region      chaine      Région de l'évènement.
    --url         chaine      URL décrivant l'évènement.
    --contact     chaine      E-mail de contact.
    --tags        chaine      Liste des tags.

Exemple de fichier XML:
    <?xml version="1.0" encoding="UTF-8"?>
    <event>
        <title>Permanence Logiciels Libres</title>
        <start-hour>18:00</start-hour>
        <end-hour>21:00</end-hour>
        <description><![CDATA[

         <p><a href="http://www.gulliver.eu.org">Gulliver</a> organise chaque
         semaine une permanence <i>Logiciels Libres</i> ouverte à tous,
         membre de l'association ou non.</p>

            <p>Durant cette permanence, vous pourrez trouver des réponses aux
            questions que vous vous posez au sujet du Logiciel Libre, ainsi que
            de l'aide pour résoudre vos problèmes d'installation, de
            configuration et d'utilisation de Logiciels Libres. N'hésitez pas
            à apporter votre ordinateur, afin que les autres participants
            puissent vous aider.</p>

            <p>Une connexion Internet est disponible sur place, ainsi que les
            mises à jour pour les distributions GNU/Linux les plus
            courantes.</p>

            <p>Cette permanence a lieu à la <a
            href=\"http://www.grand-cordel.com/\">MJC du Grand Cordel</a>, 18
            rue des Plantes à Rennes.</p>

        ]]></description>
        <place_name>Cabane du pêcheur</place_name>
        <address>Place de la république</address>
        <city>Rennes</city>
        <region>Bretagne</region>
        <url>http://www.gulliver.eu.org</url>
        <contact>contact@gulliver.eu.org</contact>
        <tags>gulliver permanence</tags>
    </event>

Valeurs des champs:
    Le fichier XML peut contenir des champs dont le nom est semblable
    à celui des options, à savoir start-date, end-date,
    start-hour, end-hour, title, description, place_name, address, city,
    region, url et contact. Si un champ est défini à la fois dans le fichier
    XML et sur la ligne de commande, alors c'est la valeur donnée sur la
    ligne de commande qui l'emporte. Entre le fichier XML et la ligne de
    commande, tous les champs doivent être définis, sinon l'ajout
    de l'évènement sera refusé. Le seul champ qui peut être
    vide est end-date, auquel cas il sera positionné à la même
    valeur que start-date.

Remplacements:
    Si la chaîne $month est trouvée dans la description, elle sera
    automatiquement remplacée par le nom du mois de la date de début
    de l'évènement.
    Si la chaîne $date est trouvée dans la description, elle sera
    automatiquement remplacée par la date de début de l'évènement
    (numéro du jour dans le mois puis nom du mois).

Exemple d'utilisation:
    ./adl-submit.py --file event.xml --start-date 2005-12-10

    Ajoutera l'évènement décrit dans le fichier event.xml
    (donné ci-dessous) pour la date du 10 décembre 2005. Puisque
    le champ end-date n'est pas spécifié, alors il vaudra la
    même chose que start-date, c'est à dire le 10 décembre
    2005.

    Pour vérifier que le formatage est correct avant l'envoi,
    on pourra utiliser:

    ./adl-submit.py --file event.xml --start-date 2005-12-10
        --test-output test.html

    et regarder le fichier test.html avec un navigateur Web.
"""
    sys.exit (1)

def HandleXmlFile(file, values):
    dom = xml.dom.minidom.parse(file)
    for node in dom.getElementsByTagName("event")[0].childNodes:
        if node.nodeType == node.ELEMENT_NODE:
            val = node.childNodes[0]
            for field in eventFields:
                if node.nodeName == field:
                    values[field] = val.data

def HandleParamValue(param, val, values):
    for field in eventFields:
        if param == "--" + field:
            values[field] = val

def ParseOptions(options):
    getoptOptions = map (lambda elt: elt + "=", eventFields)
    getoptOptions.append ("file=")
    getoptOptions.append ("help")
    getoptOptions.append("test-output=")
    eventFieldValues = {}

    testOutputFile = ""

    try:
        opts, args = getopt.getopt(options, "", getoptOptions)
    except getopt.GetoptError:
        print u"Option inconnue."
        Usage()

    if opts == []:
        Usage()

    for param, val in opts:
        if param == "--help":
            Usage()

        if param == "--file":
            HandleXmlFile(val, eventFieldValues)

        if param == "--test-output":
            testOutputFile = val

    for param, val in opts:
        HandleParamValue (param, val, eventFieldValues)

    return (eventFieldValues, testOutputFile)

def getAuthToken(baseUrl):
    curl = pycurl.Curl()

    contents = StringIO.StringIO()
    curl.setopt(curl.WRITEFUNCTION, contents.write)

    curl.setopt(curl.URL, baseUrl)
    curl.setopt(pycurl.COOKIEJAR, '/tmp/cookie.txt')
    curl.setopt(pycurl.COOKIEFILE, '/tmp/cookie.txt')

    curl.perform()

    m = re.findall(r'(<meta name="csrf-token" content="(.*?)" />)', contents.getvalue())
    return m[0][1]

def SubmitEvent(event, testOutputFile):
    if not event.has_key ("end-date") and event.has_key('start-date'):
        event ["end-date"] = event ["start-date"]

    if not event.has_key("submitter") and event.has_key('contact'):
        event ['submitter'] = event['contact']

    for field in eventFields:
        if not event.has_key(field):
            print u"Le champ '%s' n'est pas renseigné" % field
            return

    if re.compile(r'^[^\<\>]*$').search (event['title']) is None:
        print u"Problème de formatage dans le titre: '%s'. Les tags HTML ne sont pas autorisés." % event['title']
        return

    try:
        startDate = time.strptime(event['start-date'], "%Y-%m-%d")
    except ValueError:
        print u"Problème de formatage dans la date de début: '%s'. Elle doit être de la forme AAAA-MM-JJ" % event['start-date']
        return

    try:
        endDate = time.strptime(event['end-date'], "%Y-%m-%d")
    except ValueError:
        print u"Problème de formatage dans la date de fin: '%s'. Elle doit être de la forme AAAA-MM-JJ" % event['end-date']
        return

    try:
        startHour = time.strptime(event['start-hour'], "%H:%M")
    except ValueError:
        print u"Problème de formatage dans l'heure de début: '%s'. Elle doit être de la forme: HH:MM" % event['start-hour']
        return

    try:
        endHour = time.strptime(event['end-hour'], "%H:%M")
    except ValueError:
        print u"Problème de formatage dans l'heure de fin: '%s'. Elle doit être de la forme HH:MM" % event['start-hour']
        return

    for tag in event['tags'].split(' '):
        if len(tag) < 3:
            print u"Le tag '%s' est trop petit, minimum de 3 caractères" % tag
            return

    startDate = (startDate[0], startDate[1], startDate[2], startHour[3],
                 startHour[4], startDate[5], startDate[6], startDate[7], startDate[8])
    endDate   = (endDate[0],   endDate[1],   endDate[2],   endHour[3],
                 endHour[4],   endDate[5],   endDate[6],   endDate[7],   endDate[8])

    if time.mktime(startDate) <= time.time():
        print u"ERREUR: La date de début de l'évènement est dans le passé."
        return

    if time.mktime(endDate) <= time.time():
        print u"ERREUR: La date de fin de l'évènement est dans le passé."
        return

    if time.mktime(endDate) < time.mktime(startDate):
        print u"ERREUR: La date de fin de l'évènement est avant la date de début."
        return

    if re.compile(r'^[^\<\>]*$').search (event['city']) is None:
        print u"ERREUR: Problème de formatage dans le nom de la ville: '%s'. Les tags HTML sont interdits." % event['city']
        return

    if regions.has_key(event['region']) is False:
        print u"ERREUR: La région '%s' n'existe pas." % event['region']
        print u"Les régions existantes sont:"
        for name in regions:
            print u" - " + name
        return

    if re.compile(r'^http://.*$').search (event['url']) is None and re.compile(r'^https://.*$').search (event['url']) is None:
        print u"ERREUR: Problème de formatage dans l'URL: '%s'. Elle doit commencer par http:// ou https://." % event['url']
        return

    if re.compile(r'^([A-Za-z0-9_\.\-]*)@([A-Za-z0-9_\-]*)\.([A-Za-z0-9_\.\-]*)$').search (event['contact']) is None:
        print u"ERREUR: Problème de formatage dans l'adresse e-mail." % event ['contact']
        return

    if re.compile(r'^([A-Za-z0-9_\.\-]*)@([A-Za-z0-9_\-]*)\.([A-Za-z0-9_\.\-]*)$').search (event['submitter']) is None:
        print u"ERREUR: Problème de formatage dans l'adresse e-mail." % event ['submitter']
        return

    monthstr = unicode(time.strftime("%B", startDate), 'utf-8')
    datestr  = unicode(time.strftime("%d %B", startDate), 'utf-8')

    event['description'] = event['description'].replace("$month", monthstr)
    event['description'] = event['description'].replace("$date", datestr)

    curl = pycurl.Curl()

    contents = StringIO.StringIO()
    curl.setopt(curl.WRITEFUNCTION, contents.write)

    if testOutputFile:
        curl.setopt (curl.URL, baseUrl + 'events/preview')
    else:
        curl.setopt (curl.URL, baseUrl + 'events')

    curl.setopt(curl.HTTPPOST,  [('authenticity_token',    str(getAuthToken(baseUrl+'events/new'))),
                                 ('event[title]',          event['title'].encode('utf-8')),
                                 ('event[start_time(3i)]', str(startDate[2])),
                                 ('event[start_time(2i)]', str(startDate[1])),
                                 ('event[start_time(1i)]', str(startDate[0])),
                                 ('event[start_time(4i)]', str(startDate[3])),
                                 ('event[start_time(5i)]', str(startDate[4])),
                                 ('event[end_time(3i)]',   str(endDate[2])),
                                 ('event[end_time(2i)]',   str(endDate[1])),
                                 ('event[end_time(1i)]',   str(endDate[0])),
                                 ('event[end_time(4i)]',   str(endHour[3])),
                                 ('event[end_time(5i)]',   str(endHour[4])),
                                 ('event[description]',    event['description'].encode('utf-8')),
                                 ('event[place_name]',     event['place_name'].encode('utf-8')),
                                 ('event[address]',        event['address'].encode('utf-8')),
                                 ('event[city]',           event['city'].encode('utf-8')),
                                 ('event[region_id]',      str(regions[event['region']])),
                                 ('event[locality]',       str(0)),
                                 ('event[url]',            event['url'].encode('utf-8')),
                                 ('event[contact]',        event['contact'].encode('utf-8')),
                                 ('event[submitter]',      event['submitter'].encode('utf-8')),
                                 ('event[tag_list]',       event['tags'].encode('utf-8'))])

    curl.setopt(pycurl.COOKIEJAR, '/tmp/cookie.txt')
    curl.setopt(pycurl.COOKIEFILE, '/tmp/cookie.txt')
    curl.perform()

    if testOutputFile:
        if curl.getinfo(curl.HTTP_CODE) != 200:
            print u"Erreur lors de la récupération de la sortie HTML"
            sys.exit(0)
        fp = open(testOutputFile, "wb")
        s = contents.getvalue()
        s = re.sub(r'href="([A-Za-z0-9]*).css"', r'href="'+baseUrl+'\1.css"', s)
        fp.write(s)
        fp.close()

    else:
        if curl.getinfo(curl.HTTP_CODE) != 302:
            print u"Erreur lors de la soumission de l'évènement"
            sys.exit(0)
        else:
            print u"Évènement soumis avec succès. Il sera prochainement validé par un modérateur."


if (len(sys.argv) <= 1) or sys.argv[1] == "--help":
    Usage()

(event, testOutputFile) = ParseOptions(sys.argv[1:])

# Check that we are running the latest version of the adl-submit
# script
contents = StringIO.StringIO()
curl = pycurl.Curl()
curl.setopt(curl.WRITEFUNCTION, contents.write)
curl.setopt (curl.URL, baseUrl + './adl-submit-latest-version')
curl.perform()
if curl.getinfo(curl.HTTP_CODE) == 200:
    if float(contents.getvalue()) != float('3.5'):
        print u"Votre script n'est plus à jour, merci de télécharger la nouvelle version à l'adresse"
        print u"%sadl-submit.py" % baseUrl
        sys.exit(1)

SubmitEvent(event, testOutputFile)