find-a-bike / index.py

#! /usr/bin/env python3.1
#-*- coding: utf-8 -*-

# Find a Bike
# Copyright (C) 2013  Cédric Bonhomme - http://cedricbonhomme.org/
#
# For more information : https://bitbucket.org/cedricbonhomme/find-a-bike
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

__author__ = "Cedric Bonhomme"
__version__ = "$Revision: 0.3 $"
__date__ = "$Date: 2012/06/04 $"
__revision__ = "$Date: 2013/06/10 $"
__copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "AGPLv3"

import cgi
import json
import datetime
import urllib.request, urllib.parse, urllib.error
from xml.dom.minidom import parseString

import configparser
config = configparser.SafeConfigParser()
config.read("./conf.cfg")
API_KEY = config.get('globals', 'api_key')

form = cgi.FieldStorage()
city = form.getvalue("city", "")
parking = form.getvalue("parking", "1")
latitude = form.getvalue("latitude", "")
longitude = form.getvalue("longitude", "")
zoom = form.getvalue("zoom", "10")

stations = []
cities = []
errors = []

html = '<html>\n' + \
        '<head>\n\t<meta charset="utf-8" />\n\t<title>Find a Bike</title>\n\t' + \
        '<link rel="stylesheet" href="./style.css" />\n'

try:
    url = "https://api.jcdecaux.com/vls/v1/stations?apiKey="+API_KEY
    if city == "":
        try:
            request = urllib.request.urlopen(url)
            text = request.read()
            stations = json.loads(text.decode())
        except:
            pass
    else:
        cities = city.split(',')
        for current_city in cities:
            try:
                request = urllib.request.urlopen(url + "&contract=" + current_city)
                text = request.read()
                stations.extend(json.loads(text.decode()))
            except:
                errors.append(current_city)

        for error in errors:
            cities.remove(error)
except:
    html += '</head>\n'
    html += '<body>\n'
    html += '<p>Unable to contact JCDecaux Web service or API key disabled.</p>\n'
    html += '</body>\n'
    html += '</html>\n'

parkings = None
if parking == "1":
    request = urllib.request.urlopen("http://service.vdl.lu/rss/circulation_guidageparking.php")
    text = request.read()
    parkings = parseString(text)


if len(stations) == 0:
    html += '</head>\n'
    html += '<body>\n'
    html += '<p>No stations.</p>\n'
    html += '</body>\n'
    html += '</html>\n'
else:

    html += '<script src="http://openlayers.org/api/OpenLayers.js"></script>\n' + \
            '<script src="./scripts.js"></script>\n'
    html += """<script>
            var stations_location;
            function init(position) {
                var size = new OpenLayers.Size(21,25);
                var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
                var popupClass, popupContentHTML;
                var zoom=%s;
                AutoSizeAnchoredMinSize = OpenLayers.Class(OpenLayers.Popup.Anchored, {
                'autoSize': true,
                'minSize': new OpenLayers.Size(10,10)
                });
                map = new OpenLayers.Map("mapdiv" , {
                    controls:[
                        new OpenLayers.Control.Navigation(),
                        new OpenLayers.Control.PanZoomBar(),
                        new OpenLayers.Control.LayerSwitcher(),
                        new OpenLayers.Control.Attribution()]});
                stations_location = new OpenLayers.Layer.Markers("Bikes");
                map.addLayer(stations_location);
                map.addLayer(new OpenLayers.Layer.OSM());\n""" % (zoom,)
    if "" in (latitude, longitude):
        html += """var lonLatCenter = new OpenLayers.LonLat(position.coords.longitude, position.coords.latitude).transform(
                                        new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject() )
            map.setCenter (lonLatCenter, %s);\n""" % (zoom,)
    else:
        html += """var lonLatCenter = new OpenLayers.LonLat(%s, %s).transform(
                                        new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject() )
            map.setCenter (lonLatCenter, %s);\n""" % (longitude, latitude, zoom)


    for idx, station in enumerate(stations):
        try:
            # just to test the number
            float(station["position"]["lng"])
        except:
            continue
        html += """
                var station%s = new OpenLayers.LonLat(%s, %s).transform(
                    new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
                    popupClass = AutoSizeAnchoredMinSize;""" % \
                        (idx, station["position"]["lng"], station["position"]["lat"])

        if station["available_bikes"] == 0:
            html += """
                        popupContentHTML = "<p>No bikes available.<br />Payment terminal: %s<br />Last update: %s</p>";""" % \
                            ([station["banking"]==True and "yes" or "no"][0], \
                                datetime.datetime.fromtimestamp(station['last_update']/1000).strftime('%Y-%m-%d %H:%M:%S'))
            html += """
                        addMarker(station%s, popupClass, popupContentHTML, true, true, "./marker-red.png", stations_location);""" % \
                            (idx,)
        else:
            html += """
                        popupContentHTML = "<p>Available bikes: %s<br />Payment terminal: %s<br />Last update: %s</p>";""" % \
                            (station["available_bikes"], [station["banking"]==True and "yes" or "no"][0], \
                                datetime.datetime.fromtimestamp(station['last_update']/1000).strftime('%Y-%m-%d %H:%M:%S'))
            html += """
                        addMarker(station%s, popupClass, popupContentHTML, true, true, "./marker-green.png", stations_location);""" % \
                            (idx,)

    if parkings != None:
        
        html += """
            parking_lots = new OpenLayers.Layer.Markers("Parking lots");
            map.addLayer(parking_lots);\n"""
        
        for parking in parkings.getElementsByTagName('item'):
            title = parking.getElementsByTagName('title')[0].childNodes[0].nodeValue
            link = parking.getElementsByTagName('guid')[0].childNodes[0].nodeValue
            try:
                total_places = parking.getElementsByTagName('vdlxml:total')[0].childNodes[0].nodeValue
            except:
                total_places = "no data"
            try:
                available_places = parking.getElementsByTagName('vdlxml:actuel')[0].childNodes[0].nodeValue
            except:
                available_places = "no data"

            latitude = parking.getElementsByTagName('vdlxml:localisation')[0]. \
                        getElementsByTagName('vdlxml:localisationLatitude')[0].childNodes[0].nodeValue
            longitude = parking.getElementsByTagName('vdlxml:localisation')[0]. \
                        getElementsByTagName('vdlxml:localisationLongitude')[0].childNodes[0].nodeValue

            html += """
                    var parking%s = new OpenLayers.LonLat(%s, %s).transform(
                        new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
                        popupClass = AutoSizeAnchoredMinSize;""" % \
                            (idx, longitude, latitude)
            html += """
                        popupContentHTML = "<p><b>%s</b><br />Total places: %s<br />Available places: %s<br /><a href='%s'>More information</a></p>";""" % \
                            (title, total_places, available_places, link)
            html += """
                        addMarker(parking%s, popupClass, popupContentHTML, true, true, "./parking.png", parking_lots);""" % \
                            (idx,)


    html += "}\n</script>\n</head>\n"
    html += '<body onload="getLocation();">\n'
    if city != "":
        html += """<h1>Bikes available in  %s</h1>\n""" % ", ".join(cities)
        if errors != []:
            html += """<p>No results found for %s.</p>\n""" % ", ".join(errors)
    else:
        html += """<h1>Bikes available in the world</h1>\n"""
    html += '<div id="mapdiv" style="width:100%;height:100%;"></div>\n'
    html += '<p>This software is under Affero GPL license. You are welcome to copy, modify or ' + \
            'redistribute the <a href="https://bitbucket.org/cedricbonhomme/find-a-bike/">source code</a> ' + \
            'according to the <a href="https://www.gnu.org/licenses/agpl-3.0.txt">AGPLv3</a> license.\n'
    html += "</body>\n</html>"


# Finally print the web page.
print("Content-type:text/html\r\n\r\n")
print(html)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.