diff --git a/umfrage_kirchenplatz2012/media/option1.png b/umfrage_kirchenplatz2012/media/option1.png new file mode 100644 index 0000000..294a66f Binary files /dev/null and b/umfrage_kirchenplatz2012/media/option1.png differ diff --git a/umfrage_kirchenplatz2012/media/option2.png b/umfrage_kirchenplatz2012/media/option2.png new file mode 100644 index 0000000..2770978 Binary files /dev/null and b/umfrage_kirchenplatz2012/media/option2.png differ diff --git a/umfrage_kirchenplatz2012/media/option3.png b/umfrage_kirchenplatz2012/media/option3.png new file mode 100644 index 0000000..83ec231 Binary files /dev/null and b/umfrage_kirchenplatz2012/media/option3.png differ diff --git a/umfrage_kirchenplatz2012/media/option4.png b/umfrage_kirchenplatz2012/media/option4.png new file mode 100644 index 0000000..15b4f4b Binary files /dev/null and b/umfrage_kirchenplatz2012/media/option4.png differ diff --git a/umfrage_kirchenplatz2012/media/style.css b/umfrage_kirchenplatz2012/media/style.css new file mode 100644 index 0000000..83f93ae --- /dev/null +++ b/umfrage_kirchenplatz2012/media/style.css @@ -0,0 +1,85 @@ +body { + font-size: 12px; + color: #464646; +} + +h1, h2, h3 { + margin: 0; + font-weight: normal; + color: #549900; +} + +h1 { + font-size: 250%; + margin-bottom: 10px; +} + +h2 { font-size: 140%; } + +p, ul, ol { + margin-top: 0; + line-height: 240%; + text-align: justify; +} + +a { color: #D99821; } + +a:hover { text-decoration: none; } + +a img { + border: none; +} + +table.options label { + font-style: italic; +} + +table.options td { + padding: 5px; + vertical-align: top; +} + +table.options td ul { + padding: 2px 20px 2px 20px; +} + +table.options td ul li { + margin-left: 2px; +} + +table.options td.answer { + text-align: center; +} + +ul.radio li { + list-style-type: none; +} + +table.options tr.option_title { + font-size: 150%; + font-weight:bold; +} + +table.options tr.option_image td { + text-align: center; +} + +table.options td.column0 { + background-color: #c5c5ff; +} + +table.options td.column1 { + background-color: #c5ffc5; +} + +input.submit { + font-size: 14px; + font-weight:bold; + display: inline-block; + padding:0px; + padding-bottom:5px; + padding-left:10px; + margin-left:10px; + width:30%; + line-height:100%; +} diff --git a/umfrage_kirchenplatz2012/src/dataset.py b/umfrage_kirchenplatz2012/src/dataset.py new file mode 100644 index 0000000..bc87ded --- /dev/null +++ b/umfrage_kirchenplatz2012/src/dataset.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +DEFINITION_OPTIONS = ( + (u"Grüner Platz", "http://stadtgestalten.org/umfrage/kirchenplatz2012/media/option1.png", + (u"verbreiterte Gehwege", u"Wochenmarkt auf Ostseite", u"Grüne Platzfläche im Westen (keine Nutzung der Freiflächen für Stände, Außengastronomie, etc. möglich)", u"Grünes Kirchenumfeld", u"51 PKW-Stellplätze auf dem Platz (Ostseite) und an der Südseite", u"Bushaltestelle im Bestand", u"Taxistand vor Kirchenplatz Nr. 13", u"Baumpflanzungen auf dem Platz und straßenbegleitend an den Gehwegen")), + (u"Karo", "http://stadtgestalten.org/umfrage/kirchenplatz2012/media/option2.png", + (u"verbreiterte Gehwege", u"Wochenmarkt auf Ostseite", u"gepflasterte Platzfläche im Westen (Nutzung der Freiflächen für Stände, Außengastronomie, etc. möglich)", u"Kirchenumfeld als befestigte Fläche und Grün", u"30 PKW-Stellplätze auf dem Platz (Ostseite)", u"Bushaltestelle auf der Westseite (gegenüber Mühlenstraße)", u"Taxistand vor Kirchenplatz Nr. 1-2", u"Baumpflanzungen auf dem Platz und straßenbegleitend an den Gehwegen")), + (u"Marktplatz mit Baumhain", "http://stadtgestalten.org/umfrage/kirchenplatz2012/media/option3.png", + (u"verbreiterte Gehwege", u"Wochenmarkt auf Ostseite (ingeschränkte Fläche wg. Baumpflanzungen)", u"teilweise gepflasterte Platzfläche im Westen (Nutzung der Freiflächen (nicht unter den Bäumen) für Stände, Außengastronomie, etc. möglich) sowie starke Baumpflanzungen", u"Kirchenumfeld als befestigte Fläche", u"44 PKW-Stellplätze straßenbegleitend auf der Nord- und Südseite", u"Bushaltestelle auf der Westseite (gegenüber Mühlenstraße)", u"Taxistand vor Kirchenplatz Nr. 13", u"Baumpflanzungen auf dem Platz und straßenbegleitend an den Gehwegen")), + (u"Befestigter Platz", "http://stadtgestalten.org/umfrage/kirchenplatz2012/media/option4.png", + (u"verbreiterte Gehwege", u"Wochenmarkt auf Ostseite (ingeschränkte Fläche wg. Baumpflanzungen)", u"teilweise gepflasterte Platzfläche im Westen (Nutzung der Freiflächen für Stände, Außengastronomie, etc. möglich) sowie starke Baumpflanzungen", u"Kirchenumfeld als befestigte Fläche", u"39 PKW-Stellplätze straßenbegleitend auf der Nord- und Südseite", u"Bushaltestelle im Bestand", u"Taxistand vor Kirchenplatz Nr. 13", u"Baumpflanzungen auf dem Platz und auf der West- und Ostseite straßenbegleitend an den Gehwegen"))) + + +DEFINITION_QUALITY_RANGES = { + "mehr_weniger": ( + (u"++", u"++ Ja, trifft voll zu"), + (u"+", u"+ Ja, mit Abstrichen"), + (u"-", u"- Kaum bis wenig"), + (u"--", u"-- Überhaupt nicht")), + "baeume": ( + (u"++", u"++ Lineare Anordnung (Baumreihen)"), + (u"--", u"-- Beliebige Anordnung in Einzelbäume, Baumgruppen, Baumhainen")), + "gesamt": ( + (u"++", u"++ Sehr gute Variante, berücksichtigt so gut wie alle Anforderungen"), + (u"+", u"+ In Teilen gut gelungene Variante"), + (u"-", u"- Wenig attraktiv, berücksichtigt zu wenige Anforderungen"), + (u"--", u"-- Unattraktiv, unpassende Variante")), +} + + +DEFINITION_QUESTIONS = ( + (u"Frage 1: Lädt der Platz durch seine geplante Neugestaltung insgesamt zum Flanieren/Verweilen/Aufenthalt ein?", "mehr_weniger"), + (u"Frage 2: Wird die Funktion des Platzes als Orts- und Versorgungsmittelpunkt durch den Entwurf gestärkt?", "mehr_weniger"), + (u"Frage 3: Wird die Kirche als Bauwerk mit Portal und grünem Umfeld durch den Entwurf entsprechend betont?", "mehr_weniger"), + (u"Frage 4: Berücksichtigt die Variante ausreichend Fläche/ Teilbereiche für temporäre Nutzungen (Markt, Festivitäten)?", "mehr_weniger"), + (u"Frage 5: Sind die Hauptwege für Fußgänger über den Platz erkennbar und nutzbar (u.a. Verbindung Mühlenstraße-Kirchenstraße)?", "mehr_weniger"), + (u"Frage 6: Steht die Anordnung der Stellplätze im Einklang mit der Neugestaltung des Platzes und wird die Anzahl als ausreichend eingeschätzt?", "mehr_weniger"), + (u"Frage 7: Sind Bushaltestelle und Taxistand für die Benutzer gut und aus Sicht der Platzgestaltung attraktiv angeordnet?", "mehr_weniger"), + (u"Frage 8: Ist das zugrunde gelegte Begrünungskonzept gestalterisch attraktiv (Straßenraum, Kirchenumfeld)?", "mehr_weniger"), + (u"Frage 9: Sind ausreichend Baumanpflanzungen an der Straße sowie im Kirchenumfeld berücksichtigt worden?", "mehr_weniger"), + (u"Frage 10: Ist eine lineare Anordnung der Bäume (Baumreihen) im Kirchenumfeld oder eine beliebige Anordnung von Einzelbäumen neben Baumgruppen, Baumhainen gestalterisch und funktional besser?", "baeume"), + (u"Abschließende Gesamtbewertung der Planungsvarianten", "gesamt"), +) + diff --git a/umfrage_kirchenplatz2012/src/umfrage.py b/umfrage_kirchenplatz2012/src/umfrage.py new file mode 100644 index 0000000..eff6459 --- /dev/null +++ b/umfrage_kirchenplatz2012/src/umfrage.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python2.6 +# -*- coding: utf-8 -*- + +import os +# the basedir is the parent dir of the location of this script +BASE_DIR = os.path.dirname(os.path.abspath(os.path.join(__file__, os.path.pardir))) +# add the project directory to the python search path +import sys +sys.path.insert(0, os.path.join(BASE_DIR, "src")) + + +from dataset import DEFINITION_OPTIONS, DEFINITION_QUALITY_RANGES, \ + DEFINITION_QUESTIONS + +import ConfigParser +import datetime +import uuid +import sqlobject +import bobo +import genshi +import genshi.template +import genshi.filters + + +CONFIG_FILE = os.path.join(BASE_DIR, "umfrage.conf") + +config = ConfigParser.SafeConfigParser() +config.read(CONFIG_FILE) +db_uri = config.get("database", "uri") +sqlobject.sqlhub.processConnection = sqlobject.connectionForURI(db_uri) +loader = genshi.template.TemplateLoader(os.path.join(BASE_DIR, 'templates'), auto_reload=False) + + +BASE_DICT = { + "base_url": "/umfrage/kirchenplatz2012/", # the trailing slash is necessary + "errors": {}, +} + +class Session(sqlobject.SQLObject): + created = sqlobject.DateTimeCol(default=sqlobject.DateTimeCol.now) + name = sqlobject.UnicodeCol(default=lambda: uuid.uuid4().hex) + + +class Question(sqlobject.SQLObject): + text = sqlobject.UnicodeCol() + weight = sqlobject.IntCol() + quality_levels = sqlobject.PickleCol() + + +class Option(sqlobject.SQLObject): + title = sqlobject.UnicodeCol() + text = sqlobject.UnicodeCol() + image = sqlobject.UnicodeCol() + weight = sqlobject.IntCol() + + +class Answer(sqlobject.SQLObject): + text = sqlobject.UnicodeCol(default="") + quality = sqlobject.UnicodeCol(default="") + question = sqlobject.ForeignKey("Question") + option = sqlobject.ForeignKey("Option") + session = sqlobject.ForeignKey("Session") + + +def get_default_values(**kwargs): + value_dict = dict(BASE_DICT) + # we always need "options" (e.g. on frontpage) + value_dict["options"] = list(Option.select()) + value_dict["options"].sort(key=lambda item: item.weight) + for key, value in kwargs.items(): + value_dict[key] = value + return value_dict + +def render(filename, input_data=None, **values): + stream = loader.load(filename).generate(**values) + if not input_data is None: + stream |= genshi.filters.HTMLFormFiller(data=input_data) + return stream.render("html", doctype="html") + + +def get_previous_question(question): + questions = Question.select().orderBy("-weight") + for one_q in questions: + if one_q.weight < question.weight: + return one_q + return None + +def get_next_question(question): + questions = Question.select().orderBy("weight") + for one_q in questions: + if one_q.weight > question.weight: + return one_q + return None + +@bobo.query('/') +def show_question(session_id=None, question_id=None, go_backward=False, + **kwargs): + params = get_default_values() + session = None + if session_id: + session = list(Session.selectBy(name=session_id)) + if session: + session = session[0] + if not session: + session = Session() + params["session"] = session + return render("start.html", **params) + question = None + if question_id: + try: + question = Question.get(int(question_id)) + except ValueError: + pass + # any new input values? (update "Answer" objects) + target_question = None + if question: + for option in Option.select(): + opt_params = {} + for key in ("text", "quality"): + dict_key = "option_%s_%s" % (option.id, key) + if dict_key in kwargs: + opt_params[key] = kwargs[dict_key] + # at least one item was found + if opt_params: + answer = Answer.selectBy(session=session, question=question, + option=option) + if not answer: + # create new one + answer = Answer(session=session, question=question, + option=option) + else: + answer = answer[0] + # update one value + for key in opt_params: + setattr(answer, key, opt_params[key]) + if go_backward: + target_question = get_previous_question(question) + else: + target_question = get_next_question(question) + if not target_question: + # special case: we are finished + return render("summary.html", session=session) + if not target_question: + target_question = Question.select().orderBy("weight")[0] + # populate the next question + input_data = {} + for answer in Answer.selectBy(session=session, question=target_question): + for key in ("text", "quality"): + input_data["option_%s_%s" % (answer.option.id, key)] = \ + getattr(answer, key) + params.update({"session": session, + "question": target_question, + "next_question": get_next_question(target_question), + "previous_question": get_previous_question(target_question), + }) + return render("question.html", input_data=input_data, **params) + + +@bobo.query('') +def redirect_startpage(): + return bobo.redirect(BASE_DICT["base_url"]) + + +# initialize the tables (do it only once!) +if True: + tables = (Session, Question, Option, Answer) + # drop all + drop_tables = list(tables) + drop_tables.reverse() + for table in drop_tables: + if table.tableExists(): + table.dropTable() + for table in tables: + table.createTable() + for index, (title, image_url, lines) in enumerate(DEFINITION_OPTIONS): + Option(title=title, image=image_url, + text=os.linesep.join(lines), weight=index) + for index, (text, quality_levels) in enumerate(DEFINITION_QUESTIONS): + Question(text=text, weight=index, quality_levels=DEFINITION_QUALITY_RANGES[quality_levels]) + +# this application should be usable with mod_wsgi +application = bobo.Application(bobo_resources=__name__) + diff --git a/umfrage_kirchenplatz2012/templates/layout.html b/umfrage_kirchenplatz2012/templates/layout.html new file mode 100644 index 0000000..8961a6b --- /dev/null +++ b/umfrage_kirchenplatz2012/templates/layout.html @@ -0,0 +1,39 @@ + + + + + + + + Umfrage<py:if test="title">: ${title}</py:if> + + + ${select('*[local-name()!="title"]')} + + + + + ${option.title} + + + + + + + + + + + + + +
+ ${select('*|text()')} +
+ + +
+ + + diff --git a/umfrage_kirchenplatz2012/templates/question.html b/umfrage_kirchenplatz2012/templates/question.html new file mode 100644 index 0000000..4884fcb --- /dev/null +++ b/umfrage_kirchenplatz2012/templates/question.html @@ -0,0 +1,46 @@ + + + + + + + + +

${question.text}

+ +
+ + + + + + + + + + + + + + + +
+
+ +
+
    +
  • + ${unicode(text)}
    +
  • +
+
+ +

+
+ + + + diff --git a/umfrage_kirchenplatz2012/templates/start.html b/umfrage_kirchenplatz2012/templates/start.html new file mode 100644 index 0000000..2b66013 --- /dev/null +++ b/umfrage_kirchenplatz2012/templates/start.html @@ -0,0 +1,38 @@ + + + + + + + + +

Bürgerbeteiligung: Neugestaltung des Kirchplatzes in Warnemünde

+

Die Stadt Rostock möchte die +Meinung Ihrer Bürgerinnen und Bürger erfragen. +Dazu bietet sie leider nur ein etwas unhandliches PDF-Formular an.
+Das folgende web-basierte Formular soll die gewünschte Meinungsbekundung dagegen +erleichtern und somit die Breite der Umfrage vergrößern. +

+

+ + +
+

+ + + + + + diff --git a/umfrage_kirchenplatz2012/templates/summary.html b/umfrage_kirchenplatz2012/templates/summary.html new file mode 100644 index 0000000..8279558 --- /dev/null +++ b/umfrage_kirchenplatz2012/templates/summary.html @@ -0,0 +1,30 @@ + + + + + + + + +

Zusammenfassung

+Der folgende Text fasst Ihre Eingaben zusammen. Sie können ihn nun nach +Belieben anpassen. Anschließend haben Sie zwei Möglichkeiten: + +
    +
  • Übertragen Sie den Text in Ihr gewohntes Mailprogramm und senden Sie die Mail an stadtplanung@rostock.de.
  • + ODER +
  • Geben Sie unterhalb des Textes Ihre Mailadresse an und klicken Sie auf Senden. Dadurch wird die Mail sofort ihn Ihrem Namen an die obige Mailadresse der Stadtverwaltung verschickt.
  • +
+ +Falls Sie Anregungen oder Kritik bezüglich des Planungsverfahrens +äußern wollen, dann fügen Sie diese bitte am Ende des Textes an. +(Im Formular der Stadt war dafür kein Eingabefeld vorgesehen.) + +Die Stadt wird für Ihre Eingabe sicherlich dankbar sein! + + + +