#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2005 Thomas Petazzoni # # 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 io import re import time import locale from urllib.parse import urlencode baseUrl = "https://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" ] regions = { 'Alsace-Champagne-Ardenne-Lorraine' : 1, 'Aquitaine-Limousin-Poitou-Charentes': 2, 'Auvergne-Rhône-Alpes' : 3, 'Normandie' : 4, 'Bourgogne-Franche-Comté' : 5, 'Bretagne' : 6, 'Centre-Val de Loire' : 7, 'Corse' : 9, 'Île-de-France' : 12, 'Languedoc-Roussillon-Midi-Pyrénées' : 13, 'Hauts-de-France' : 17, 'Provence-Alpes-Côte-d\'Azur' : 21, 'Pays de la Loire' : 18, 'Guadeloupe' : 23, 'Guyane' : 24, 'Martinique' : 25, 'La Réunion' : 26, 'Autre pays' : 27, 'Mayotte' : 28, 'Collectivités d\'outre-mer' : 29, 'Collectivité sui generis' : 30 } def Usage(): print("""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: Permanence Logiciels Libres 18:00 21:00 Gulliver organise chaque semaine une permanence Logiciels Libres ouverte à tous, membre de l'association ou non.

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.

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

Cette permanence a lieu à la MJC du Grand Cordel, 18 rue des Plantes à Rennes.

]]>
Cabane du pêcheur
Place de la république
Rennes Bretagne http://www.gulliver.eu.org contact@gulliver.eu.org gulliver permanence
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 = [elt + "=" for elt in eventFields] getoptOptions.append ("file=") getoptOptions.append ("help") getoptOptions.append("test-output=") eventFieldValues = {} testOutputFile = "" try: opts, args = getopt.getopt(options, "", getoptOptions) except getopt.GetoptError: print("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): contents = io.BytesIO() curl = pycurl.Curl() try: curl.setopt(curl.URL, baseUrl) curl.setopt(curl.WRITEDATA, contents) curl.setopt(pycurl.COOKIEJAR, '/tmp/cookie.txt') curl.setopt(pycurl.COOKIEFILE, '/tmp/cookie.txt') curl.perform() finally: curl.close() contents = contents.getvalue().decode() m = re.findall(r'()', contents) return m[0][1] def SubmitEvent(event, testOutputFile): if "end-date" not in event and 'start-date' in event: event ["end-date"] = event ["start-date"] if "submitter" not in event and 'contact' in event: event ['submitter'] = event['contact'] for field in eventFields: if field not in event: print(("Le champ '%s' n'est pas renseigné") % field) return if re.compile(r'^[^\<\>]*$').search (event['title']) is None: print(("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(("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(("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(("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(("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(("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("ERREUR: La date de début de l'évènement est dans le passé.") return if time.mktime(endDate) <= time.time(): print("ERREUR: La date de fin de l'évènement est dans le passé.") return if time.mktime(endDate) < time.mktime(startDate): print("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(("ERREUR: Problème de formatage dans le nom de la ville: '%s'. Les tags HTML sont interdits.") % event['city']) return if (event['region'] in regions) is False: print(("ERREUR: La région '%s' n'existe pas.") % event['region']) print("Les régions existantes sont:") for name in regions: print((" - ") + name) return if re.compile(r'^http://.*$').search (event['url']) is None and re.compile(r'^https://.*$').search (event['url']) is None: print(("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(("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(("ERREUR: Problème de formatage dans l'adresse e-mail.") % event ['submitter']) return monthstr = time.strftime("%B", startDate) datestr = time.strftime("%d %B", startDate) event['description'] = event['description'].replace("$month", monthstr) event['description'] = event['description'].replace("$date", datestr) curl = pycurl.Curl() try: contents = io.BytesIO() curl.setopt(curl.WRITEFUNCTION, contents.write) if testOutputFile: curl.setopt (curl.URL, baseUrl + 'events/preview') else: curl.setopt (curl.URL, baseUrl + 'events') fields = { 'authenticity_token': str(getAuthToken(baseUrl+'events/new')), 'event[title]': event['title'], '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'], 'event[place_name]': event['place_name'], 'event[address]': event['address'], 'event[city]': event['city'], 'event[region_id]': str(regions[event['region']]), 'event[locality]': str(0), 'event[url]': event['url'], 'event[contact]': event['contact'], 'event[submitter]': event['submitter'], 'event[tag_list]': event['tags'] } fields = urlencode(fields) curl.setopt(curl.POSTFIELDS, fields) 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("Erreur lors de la récupération de la sortie HTML") sys.exit(0) fp = open(testOutputFile, "w") s = contents.getvalue().decode() s = re.sub(r'', r'\g<0>' % baseUrl, s, flags=re.IGNORECASE) fp.write(s) fp.close() else: if curl.getinfo(curl.HTTP_CODE) != 302: print("Erreur lors de la soumission de l'évènement") sys.exit(0) else: print("Évènement soumis avec succès. Il sera prochainement validé par un modérateur.") finally: curl.close() def ensure_latest_version_is_used(): # Check that we are running the latest version of the adl-submit # script contents = io.BytesIO() curl = pycurl.Curl() try: curl.setopt(curl.WRITEDATA, contents) curl.setopt (curl.URL, baseUrl + './adl-submit-latest-version') curl.perform() if curl.getinfo(curl.HTTP_CODE) == 200: contents = contents.getvalue().decode() if float(contents) != float('3.5'): print("Votre script n'est plus à jour, merci de télécharger la nouvelle version à l'adresse") print(("%sadl-submit.py") % baseUrl) sys.exit(1) finally: curl.close() if __name__ == "__main__": if (len(sys.argv) <= 1) or sys.argv[1] == "--help": Usage() (event, testOutputFile) = ParseOptions(sys.argv[1:]) ensure_latest_version_is_used() SubmitEvent(event, testOutputFile)