From f140d7c7bdf0aaf6456f5308a4a28f515d959f60 Mon Sep 17 00:00:00 2001
From: echarp
Date: Fri, 18 Jul 2014 01:24:55 +0200
Subject: [PATCH] =?UTF-8?q?Script=20python=20pour=20propose=20des=20=C3=A9?=
=?UTF-8?q?vts=20en=20ligne=20de=20commande!?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/assets/javascripts/application.js.coffee | 24 --
app/assets/javascripts/events.js.coffee | 23 ++
public/adl-submit-latest-version | 1 +
public/adl-submit.py | 387 +++++++++++++++++++
4 files changed, 411 insertions(+), 24 deletions(-)
create mode 100644 public/adl-submit-latest-version
create mode 100755 public/adl-submit.py
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 5e6624f9..6f95c4d7 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -32,27 +32,3 @@ $(document).on 'page:receive', ->
$(document).on 'page:load', ->
# Reload polyfill when turbolinks loads a new page
$(this).updatePolyfill()
-
-$(document).on 'page:receive', ->
- # Delete existing tinymce editors, very important in the turbolinks context!
- tinymce.remove()
-
-$(document).ready ->
- tinyMCE.init
- selector: 'textarea',
- menubar : false,
- schema: 'html5',
- add_unload_trigger: true,
- browser_spellcheck: true,
- toolbar: [
- ' bold italic strikethrough
- | bullist numlist outdent indent
- | alignleft aligncenter alignright alignjustify
- | link media insertdatetime charmap table
- | undo redo
- | searchreplace
- | code visualblocks preview fullscreen'
- ],
- plugins: 'lists, advlist, autolink, link, charmap, paste, print, preview,
- table, fullscreen, searchreplace, media, insertdatetime, visualblocks,
- visualchars, wordcount, contextmenu, code'
diff --git a/app/assets/javascripts/events.js.coffee b/app/assets/javascripts/events.js.coffee
index 728976d4..3b39edd6 100644
--- a/app/assets/javascripts/events.js.coffee
+++ b/app/assets/javascripts/events.js.coffee
@@ -1,3 +1,26 @@
$(document).ready ->
$('form.region_selector select').change ->
this.form.submit()
+
+ tinyMCE.init
+ selector: 'textarea#event_description',
+ menubar : false,
+ schema: 'html5',
+ add_unload_trigger: true,
+ browser_spellcheck: true,
+ toolbar: [
+ ' bold italic strikethrough
+ | bullist numlist outdent indent
+ | alignleft aligncenter alignright alignjustify
+ | link media insertdatetime charmap table
+ | undo redo
+ | searchreplace
+ | code visualblocks preview fullscreen'
+ ],
+ plugins: 'lists, advlist, autolink, link, charmap, paste, print, preview,
+ table, fullscreen, searchreplace, media, insertdatetime, visualblocks,
+ visualchars, wordcount, contextmenu, code'
+
+$(document).on 'page:receive', ->
+ # Delete existing tinymce editors, very important in the turbolinks context!
+ tinymce.remove()
diff --git a/public/adl-submit-latest-version b/public/adl-submit-latest-version
new file mode 100644
index 00000000..9f55b2cc
--- /dev/null
+++ b/public/adl-submit-latest-version
@@ -0,0 +1 @@
+3.0
diff --git a/public/adl-submit.py b/public/adl-submit.py
new file mode 100755
index 00000000..839bbbcb
--- /dev/null
+++ b/public/adl-submit.py
@@ -0,0 +1,387 @@
+#!/usr/bin/python
+# -*- 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 StringIO
+import re
+import time
+import locale
+
+locale.setlocale(locale.LC_ALL, ('fr_FR', 'utf-8'))
+
+eventFields = [ "title", "start-date", "end-date", "start-hour",
+ "end-hour", "description", "city", "region",
+ "url", "contact", "submitter", "tags" ]
+
+regions = {
+ u'Alsace' : 1,
+ u'Aquitaine' : 2,
+ u'Auvergne' : 3,
+ u'Basse-Normandie' : 4,
+ u'Bourgogne' : 5,
+ u'Bretagne' : 6,
+ u'Centre' : 7,
+ u'Champagne-Ardenne' : 8,
+ u'Corse' : 9,
+ u'Franche-Comté' : 10,
+ u'Haute-Normandie' : 11,
+ u'Île-de-France' : 12,
+ u'Languedoc-Roussillon' : 13,
+ u'Limousin' : 14,
+ u'Lorraine' : 15,
+ u'Midi-Pyrénées' : 16,
+ u'Nord-Pas-de-Calais' : 17,
+ u'Pays' : 18,
+ u'Picardie' : 19,
+ u'Poitou-Charentes' : 20,
+ u'Provence-Alpes-Côte-d\'Azur' : 21,
+ u'Rhône-Alpes' : 22,
+ u'Guadeloupe' : 23,
+ u'Guyane' : 24,
+ u'Martinique' : 25,
+ u'Réunion' : 26,
+ u'Autre' : 27
+}
+
+baseUrl = "http://www.agendadulibre.org"
+#baseUrl = "http://localhost:3000/"
+
+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.
+ --city chaine Ville de l'évènement.
+ --region entier 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.
+
+ ]]>
+ 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, 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.search(r'()', contents.getvalue())
+ m = re.search(r'"(.*?)"', m.group())
+ return m.group().strip('"')
+
+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?visu=true')
+ 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[city]', event['city'].encode('utf-8')),
+ ('event[region]', 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[tags]', 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) and sys.argv[1] == "--help":
+ Usage()
+
+(event, testOutputFile) = ParseOptions(sys.argv[1:])
+
+# Check that we are running the latest version of the adl-submit
+# script
+if not testOutputFile:
+ 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.0'):
+ 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)