import cgi import datetime import configparser import pymysql GJSON = 0 def getDatabase(path = "config.cfg"): config = configparser.RawConfigParser() config.read(path) host = config.get("Database", "host") user = config.get("Database", "user") pwd = config.get("Database", "pass") name = config.get("Database", "name") conn = pymysql.connect(host, user, pwd, name) cur = conn.cursor(pymysql.cursors.DictCursor) return conn, cur def buildGJSON(data): output = """{ "type": "FeatureCollection", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "Name": null, "description": null, "timestamp": null, "begin": null, "end": null, "altitudeMode": null, "tessellate": -1, "extrude": 0, "visibility": -1, "drawOrder": null, "icon": null, "styleUrl": "#style", "styleHash": "1a1ac94e", "stroke": "#ffff00", "stroke_opacity": "0.4980392156862745", "stroke_width": "4", "fill": "#00ff00", "fill_opacity": "0.4980392156862745" }, "geometry": { "type": "LineString", "coordinates": [ """ for row in data: output += " [ %s, %s ],\n" % (row["lon"], row["lat"]) output = "".join(output.rsplit(",", 1)) output += """ ] } } ] }""" headers = [["Content-Type", "application/vnd.geo+json"], ['Content-Disposition', 'attachment; filename="export.geojson"']] return headers, output def buildGPX(data): output = """ export.gpx GPS Data Export pygps """ for row in data: output += """ """ % (row["lat"], row["lon"], row["ts"].isoformat()) output += """ """ headers = [["Content-Type", "application/gpx+xml"], ['Content-Disposition', 'attachment; filename="export.gpx"']] return headers, output def buildKML(data): output = """ """ for row in data: output += """ %s %s %s %s""" % (row["ts"].isoformat(), row["lon"], row["lat"], row["alt"] or "0") output += """ """ headers = [["Content-Type", "application/vnd.google-earth.kml+xml"], ['Content-Disposition', 'attachment; filename="export.kml"']] return headers, output def application(env, re): if env["REQUEST_METHOD"] == "POST": args = cgi.parse_qs(env['wsgi.input'].readline().decode(), True) elif env["REQUEST_METHOD"] == "GET": args = cgi.parse_qs(env['QUERY_STRING'], True) else: re("405 Method Not Allowed", []) return if env["PATH_INFO"] in ("/endpoint", "/endpoint.php"): try: device = args["device"][0] except: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "device is required.".encode() return try: latitude = float(args["lat"][0].replace(",", ".")) longitude = float(args["lon"][0].replace(",", ".")) except Exception: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "lat and lon are required.".encode() return try: altitude = float(args["alt"][0].replace(",", ".")) except: altitude = None try: timestamp = datetime.datetime.fromtimestamp(float(args["t"][0]) / 1000) except: timestamp = datetime.datetime.now() timestr = timestamp.strftime('%Y-%m-%d %H:%M:%S') conn, cur = getDatabase() sql = "INSERT INTO tracker(ts, device, lat, lon, alt) VALUES (%s, %s, %s, %s, %s);" cur.execute(sql, (timestr, device, str(latitude), str(longitude), str(altitude) if altitude != None else None)) conn.commit() cur.close() conn.close() re("200 OK", []) yield "OK".encode() return if env["PATH_INFO"] in ("/location", "/location.php"): try: device = args["device"][0] except: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "device is required.".encode() return conn, cur = getDatabase() cur.execute("SELECT * FROM tracker WHERE device = %s ORDER BY ts DESC LIMIT 1;", device) row = cur.fetchone() cur.close() conn.close() re("200 OK", [["Content-Type", "text/html"]]) yield (""" Current Location

My location at %s

(last known position where I had a GPS signal, a network connection, and some battery power)

""" % (row["ts"], row["lat"], row["lon"], row["lat"], row["lon"])).encode() return if env["PATH_INFO"] in ("/access", "/access.php", "/export", "/export.php"): try: device = args["device"][0] except: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "device is required.".encode() return on = args["on"][0] if "on" in args else None since = args["since"][0] if "since" in args else None frm = since if since else on if on else args["from"][0] if "from" in args else None to = None if since else on if on else args["to"][0] if "to" in args else None if not "format" in args or args["format"][0] in ("json", "gjson", "geojson", "gj") or not args["format"]: builder = buildGJSON elif args["format"][0] == "gpx": builder = buildGPX elif args["format"][0] == "kml": builder = buildKML else: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "Unknown format: %s" % args["format"] return frm = frm or "2000-01-01" to = to or datetime.datetime.now().strftime('%Y-%m-%d') for time in frm, to: try: datetime.datetime.strptime(time, "%Y-%m-%d") except: re("400 Bad Request", []) yield "

400 Bad Request

".encode() yield "Dates must be in YYYY-MM-DD format.".encode() return conn, cur = getDatabase() sql = "SELECT * FROM tracker WHERE device=%s AND DATE(ts)>=%s and DATE(ts)<=%s ORDER BY ts ASC;"; cur.execute(sql, (device, frm, to)) data = cur.fetchall() headers, output = builder(data) re("200 OK", headers) cur.close() conn.close() yield output.encode() return