plakateapp

Check-in [52e2986e75]
Login

Check-in [52e2986e75]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:first commit
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | descendants | master | trunk
Files: files | file ages | folders
SHA3-256: 52e2986e7563cad253570ce65c4dd4b942a6bf1a535744a601ffd6950f4f3796
User & Date: git@tuxproject.de 2016-09-25 00:40:50
Context
2017-05-03
08:10
LICENSE: Copyright erweitert; README ergänzt; Flask-Server wird jetzt über gevent gestartet. check-in: b097839206 user: git@tuxproject.de tags: master, trunk
2016-09-25
00:40
first commit check-in: 52e2986e75 user: git@tuxproject.de tags: master, trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace

Added LICENSE.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                    Version 2, December 2004

 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. You just DO WHAT THE FUCK YOU WANT TO.

Added README.md.







































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Plakate-App

Dies ist eine Webanwendung, die eine anklickbare Straßenkarte anzeigt, über die (zum Beispiel) die Position von Plakaten im Wahlkampf bestimmt werden kann.

## Hä? Haste mal ein Beispiel?

Klar. Nehmen wir an, ihr wollt für irgendeinen Verein eure Stadt vollplakatieren, wollt aber den Überblick behalten, wo überall Plakate hängen, um sie später wieder entfernen zu können. Genau diesem Zweck dient diese Anwendung.

## Technik

Ihr braucht auf eurem Server nur Python und das Flask-Modul (`pip install flask`), alles Weitere lädt die Website automatisch:

    python ./server.py

Die Karte ist anschließend über den Port 6090 (einstellbar direkt in der Datei `server.py`) erreichbar. Unter `/manageplakate` gibt es auch eine einfache Liste aller eingetragenen Plakate zum schnellen Löschen. Das Großteil des UIs wurde mit [Leafjet.js](http://leafletjs.com/) programmiert.

## Urheberrecht? Quatsch.

Die Plakateapp wurde ursprünglich für den Kommunalwahlkampf in Niedersachsen 2016 von [@tux0r](https://twitter.com/tux0r) hektisch (also eher zweckmäßig als gut) für die Piratenpartei Braunschweig programmiert (weshalb der Standard für die Position mitten in Braunschweig liegt, aber das könnt ihr im Javascript-Code ändern). All dies hier steht unter der [WTFPL v2](http://www.wtfpl.net/txt/copying/), ihr dürft also gern damit wegrennen und es teuer verscherbeln. Viel Spaß!

Added src/plakate.db.

cannot compute difference between binary files

Added src/server.py.



















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import sqlite3
import json
from flask import Flask, render_template, request, send_from_directory, redirect

app = Flask(__name__)

PORT = 6090

@app.route('/')
def hauptseite():
    return render_template("index.htm")


@app.route("/manageplakate")
def manage_plakate():
    try:
        conn = sqlite3.connect("plakate.db")
        with conn:
            c = conn.cursor()
            c.execute("SELECT * FROM plakate")
            plakate = [dict(id=row[0], lat=row[1], lon=row[2]) for row in c.fetchall()]
            return render_template("delete.htm",plakate=plakate)
    except:
        return "err"


@app.route("/listplakate", methods=['POST'])
def list_plakate():
    try:
        conn = sqlite3.connect("plakate.db")
        with conn:
            c = conn.cursor()
            c.execute("SELECT * FROM plakate")
            plakate = [dict(id=row[0], lat=row[1], lon=row[2]) for row in c.fetchall()]
            return json.dumps(plakate)
    except:
        return "err"


@app.route("/neuesplakat", methods=['POST'])
def neues_plakat():
    try:
        latitude = request.form["lat"]
        longitude = request.form["lon"]

        conn = sqlite3.connect("plakate.db", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
        with conn:
            c = conn.cursor()
            c.execute("INSERT INTO plakate (lat, lon) VALUES ({}, {});".format(float(latitude), float(longitude)))
            conn.commit()

        return "Plakat erfolgreich eingetragen!"
    except sqlite3.Error as e:
        return "Fehler! :-( {}".format(e.message)


@app.route("/del/<int:plakatid>", strict_slashes = False)
def del_plakat(plakatid):
    try:
        conn = sqlite3.connect("plakate.db", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
        with conn:
            c = conn.cursor()
            c.execute("DELETE FROM plakate WHERE id={}".format(plakatid))
            conn.commit()
        return redirect("/manageplakate")
    except sqlite3.Error as e:
        return "Fehler! :-( {}".format(e.message)


@app.route("/delpost", methods=['POST'])
def delpost():
    try:
        plakatid = request.form["id"]
        conn = sqlite3.connect("plakate.db", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
        with conn:
            c = conn.cursor()
            c.execute("DELETE FROM plakate WHERE id={}".format(plakatid))
            conn.commit()
        return "Geklappt."
    except sqlite3.Error as e:
        return "Fehler! :-( {}".format(e.message)


@app.route('/templates/<path:path>', strict_slashes = False)
def web_static(path):
    # Statische Templatedateien ausliefern
    return send_from_directory('templates', path)

app.run(host='0.0.0.0', port=PORT, debug=False)

Added src/templates/delete.htm.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<table>
<tr>
<th><b>Latitude</b></th>
<th><b>Longitude</b></th>
<th><b>Löschen</b></th>
</tr>
{% for plakat in plakate %}
<tr>
<td>{{ plakat.lat }}</td>
<td>{{ plakat.lon }}</td>
<td><a href="/del/{{ plakat.id }}">X</a></td>
</tr>
{% endfor %}
</table>

Added src/templates/index.htm.





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html>
    <head>
        <title>Piratenplakate</title>

        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

        <link rel="stylesheet" href="https://npmcdn.com/leaflet@1.0.0-rc.2/dist/leaflet.css" />
        <script src="https://npmcdn.com/leaflet@1.0.0-rc.2/dist/leaflet.js"></script>
        <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
        <script src="/templates/script.js"></script>
    </head>
    <body style="overflow:none">
        <div id="map" style="height:100%;width:100%;position:absolute;top:0px;left:0px;"></div>
    </body>
</html>

Added src/templates/script.js.



























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
var map;
var ajaxRequest;
var plotlist;
var plotlayers=[];

function initmap() {
    // Karte initialisieren
    map = new L.Map('map');

    var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
    var osmAttrib='Karte von <a href="http://openstreetmap.org">OpenStreetMap</a>';
    var osm = new L.TileLayer(osmUrl, {minZoom: 12, maxZoom: 28, attribution: osmAttrib});

    // OSM anzeigen
    map.addLayer(osm);

    // bei Ortungserfolg Standort anzeigen:
    map.on('locationfound', function() {
        var radius = e.accuracy / 2;

        L.marker(e.latlng).addTo(map)
            .bindPopup("Du bist ungefähr hier.").openPopup();

        L.circle(e.latlng, radius).addTo(map);
    });

    // bei Ortungsmisserfolg Karte mitten in Braunschweig setzen:
    map.on('locationerror', function() {
        map.setView(new L.LatLng(52.269167, 10.521111), 17);
    });

    // bestehende Marker laden:
    $.post(
      "/listplakate",
      {},
      function(data) {
          var json = JSON.parse(data);
          for (var i = 0; i < json.length; i++) {
              var plakat = json[i];
              var plakatlatlng = new L.LatLng(plakat.lat,plakat.lon)
              var marker = new L.Marker(plakatlatlng, {draggable:false})
.bindPopup("<input type='button' value='Plakat löschen' data-id='"+plakat.id+"' class='marker-delete-button'/>");

              marker.on("popupopen", onPopupOpen);
              map.addLayer(marker);
          }
      }
    );

    // neue Marker setzen:
    map.on('click', function(e) {
        if (confirm("Möchtest du hier ein neues Plakat melden?")) {
            var marker = new L.Marker(e.latlng, {draggable:false});
            marker.on("popupopen", onPopupOpen);
            map.addLayer(marker);
            $.post(
              "/neuesplakat",
              {
                lat: e.latlng.lat,
                lon: e.latlng.lng
              },
              function(data) {
                alert(data);
              }
            );
        }
    });

    $(".dellink").on("click", function() {
    });

    // Ortung versuchen:
    map.locate({ setView: true, maxZoom: 28 });
}

function onPopupOpen() {
    var tempMarker = this;

    $(".marker-delete-button:visible").click(function () {
        $.post(
          "/delpost",
          { id: $(this).attr("data-id") },
          function(data) {
              // noop
	   }
        );
        map.removeLayer(tempMarker);
    });
}

$(document).ready(function() {
    initmap();
});