Added examples
This commit is contained in:
52
uebung7/uebung07-examples/style.css
Normal file
52
uebung7/uebung07-examples/style.css
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
body, html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
background-color: #444;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea, table {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 1em auto;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 1em;
|
||||||
|
border: 1px solid darkblue;
|
||||||
|
color: black;
|
||||||
|
text-align: justify;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
max-width: 30em;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
max-width: 30em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.open {
|
||||||
|
/*...*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.done {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
td {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.min {
|
||||||
|
width: 1%;
|
||||||
|
|
||||||
|
}
|
24
uebung7/uebung07-examples/tasks-delete.py
Normal file
24
uebung7/uebung07-examples/tasks-delete.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
from tasks_lib import enc_print
|
||||||
|
from tasks_lib import delete_task, redirect, print_header, print_footer, print_exception_page
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Zugriff auf die Formulardaten
|
||||||
|
form = cgi.FieldStorage(encoding='utf8')
|
||||||
|
filename = form.getfirst('timestamp')
|
||||||
|
|
||||||
|
assert filename is not None
|
||||||
|
|
||||||
|
# Task löschen
|
||||||
|
delete_task(filename)
|
||||||
|
|
||||||
|
# Weiterleitung auf Übersichtsseite
|
||||||
|
redirect("tasks-show.py")
|
||||||
|
|
||||||
|
# Rudimentäres Error-Handling ...
|
||||||
|
except Exception as e:
|
||||||
|
print_exception_page("Fehler", "Fehler beim Löschen!", e)
|
32
uebung7/uebung07-examples/tasks-show.py
Normal file
32
uebung7/uebung07-examples/tasks-show.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
|
||||||
|
from tasks_lib import read_all_tasks, get_done_tasks, get_open_tasks
|
||||||
|
from tasks_lib import print_header, print_tasks, print_footer, print_form, print_navigation
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
form = cgi.FieldStorage(encoding='utf8')
|
||||||
|
|
||||||
|
# Welchen Zustand sollen die angezeigten Tasks haben? Default-Wert: all
|
||||||
|
state = form.getfirst('state', 'all')
|
||||||
|
|
||||||
|
all_tasks = read_all_tasks()
|
||||||
|
|
||||||
|
# Filtere die Tasks nach dem entsprechenden Zustand
|
||||||
|
if state == "open":
|
||||||
|
tasks = get_open_tasks(all_tasks)
|
||||||
|
prefix = "offene"
|
||||||
|
elif state == "done":
|
||||||
|
tasks = get_done_tasks(all_tasks)
|
||||||
|
prefix = "erledigte"
|
||||||
|
else:
|
||||||
|
tasks = all_tasks
|
||||||
|
prefix = ""
|
||||||
|
|
||||||
|
# Ab hier:Ausgabe des HTML-Codes
|
||||||
|
print_header("{} {} Aufgaben".format(len(tasks), prefix))
|
||||||
|
print_navigation()
|
||||||
|
print_tasks(tasks)
|
||||||
|
print_form()
|
||||||
|
print_footer()
|
26
uebung7/uebung07-examples/tasks-store.py
Normal file
26
uebung7/uebung07-examples/tasks-store.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
from tasks_lib import enc_print
|
||||||
|
from tasks_lib import create_task, write_task, redirect, print_exception_page
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Zugriff auf Formulardaten
|
||||||
|
form = cgi.FieldStorage(encoding='utf8')
|
||||||
|
title = form.getfirst('title')
|
||||||
|
|
||||||
|
assert title is not None
|
||||||
|
|
||||||
|
# Task erstellen und speichern
|
||||||
|
task = create_task(title)
|
||||||
|
write_task(task["timestamp"], task)
|
||||||
|
|
||||||
|
# Weiterleitung auf Übersichtsseite
|
||||||
|
redirect("tasks-show.py")
|
||||||
|
|
||||||
|
|
||||||
|
# Rudimentäres Error-Handling ...
|
||||||
|
except Exception as e:
|
||||||
|
print_exception_page("Fehler", "Fehler beim Hinzufügen!", e)
|
25
uebung7/uebung07-examples/tasks-update.py
Normal file
25
uebung7/uebung07-examples/tasks-update.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
from tasks_lib import enc_print
|
||||||
|
from tasks_lib import flip_task_state, read_task, write_task, redirect, print_exception_page
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Zugriff auf Formulardaten
|
||||||
|
form = cgi.FieldStorage(encoding='utf8')
|
||||||
|
filename = form.getfirst('timestamp')
|
||||||
|
|
||||||
|
assert filename is not None
|
||||||
|
|
||||||
|
# Zustand des Tasks ändern und speichern
|
||||||
|
task = flip_task_state(read_task(filename))
|
||||||
|
write_task(filename, task)
|
||||||
|
|
||||||
|
# Weiterleitung auf Übersichtsseite
|
||||||
|
redirect("tasks-show.py")
|
||||||
|
|
||||||
|
# Rudimentäres Error-Handling ...
|
||||||
|
except Exception as e:
|
||||||
|
print_exception_page("Fehler", "Fehler beim Ändern!", e)
|
1
uebung7/uebung07-examples/tasks/2019-06-14-11-11-14
Normal file
1
uebung7/uebung07-examples/tasks/2019-06-14-11-11-14
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"timestamp": "2019-06-14-11-11-14", "state": "open", "title": "F\u00fcr die Intech-Klausur lernen"}
|
1
uebung7/uebung07-examples/tasks/2019-06-14-11-11-27
Normal file
1
uebung7/uebung07-examples/tasks/2019-06-14-11-11-27
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"title": "Intech-\u00dcbungsblatt fertig machen", "state": "done", "timestamp": "2019-06-14-11-11-27"}
|
208
uebung7/uebung07-examples/tasks_lib.py
Normal file
208
uebung7/uebung07-examples/tasks_lib.py
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from os import listdir
|
||||||
|
from os.path import isfile, join
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
# Hilfsfunktionen
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# enc_print zur Behebung des UTF-Problems mit dem Übungsserver
|
||||||
|
def enc_print(string='', encoding='utf8'):
|
||||||
|
sys.stdout.buffer.write(string.encode(encoding) + b'\n')
|
||||||
|
|
||||||
|
|
||||||
|
# Erzeugt einen HTTP-Redirect
|
||||||
|
def redirect(location):
|
||||||
|
print("Status: 303 See Other")
|
||||||
|
print("Location: {}".format(location))
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# Liefert die aktuelle Uhrzeit im Format Jahr-Monat-Tag-Stunde-Minute-Sekunde
|
||||||
|
def get_timestamp():
|
||||||
|
return time.strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
|
||||||
|
# Konvertiert einene Timestamp im Format Jahr-Monat-Tag-Stunde-Minute-Sekunde in die Form Tag.Monat.Jahr
|
||||||
|
def readable_timestamp(timestamp):
|
||||||
|
return datetime.datetime.strptime(timestamp, "%Y-%m-%d-%H-%M-%S").strftime("%d.%m.%Y")
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
# Layout-Funktionen
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Gibt den Header der Seite mit optionalem Titel aus
|
||||||
|
def print_header(title=""):
|
||||||
|
enc_print("Content-type: text/html\n")
|
||||||
|
|
||||||
|
enc_print("""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{}</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{}</h1>
|
||||||
|
""".format(title, title))
|
||||||
|
|
||||||
|
|
||||||
|
# Gibt den Footer aus
|
||||||
|
def print_footer():
|
||||||
|
enc_print("""
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def print_navigation():
|
||||||
|
enc_print("""
|
||||||
|
<p>
|
||||||
|
<a href="tasks-show.py">Alle Aufgaben anzeigen</a> -
|
||||||
|
<a href="tasks-show.py?state=open">Offene Aufgaben anzeigen</a> -
|
||||||
|
<a href="tasks-show.py?state=done">Bereits erledigte Aufgaben anzeigen</a>
|
||||||
|
</p>
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
# Gibt alle Tasks in einer Tabelle aus
|
||||||
|
def print_tasks(tasks):
|
||||||
|
if len(tasks) == 0:
|
||||||
|
enc_print("Noch keine Aufgaben vorhanden ...")
|
||||||
|
else:
|
||||||
|
enc_print("<table>")
|
||||||
|
|
||||||
|
for t in tasks:
|
||||||
|
# Symbol für "Haken" und "Kreuz" in Abhängigkeit davon, ob der Task erledigt wurde
|
||||||
|
symbol = "✗" if t["state"] == "done" else "✓"
|
||||||
|
|
||||||
|
# Tabellenzeile ausgeben
|
||||||
|
enc_print("""<tr>
|
||||||
|
<td class="{}">{} <span style='font-size: x-small'>({})</span></td>
|
||||||
|
<td class="min"><form action="tasks-update.py" method="post"><button name="timestamp" value="{}">{}</button></form></td>
|
||||||
|
<td class="min"><form action="tasks-delete.py" method="post"><button name="timestamp" value="{}">🗑</button> </form></td>
|
||||||
|
</tr>""".format(t["state"],
|
||||||
|
t["title"],
|
||||||
|
readable_timestamp(t["timestamp"]),
|
||||||
|
t["timestamp"],
|
||||||
|
symbol,
|
||||||
|
t["timestamp"]))
|
||||||
|
|
||||||
|
enc_print("</table>")
|
||||||
|
|
||||||
|
|
||||||
|
# Gibt das Formular zum Anlegen eines Tasks aus
|
||||||
|
def print_form():
|
||||||
|
enc_print("""
|
||||||
|
<form action="tasks-store.py" method="post" style="margin-top: 2em">
|
||||||
|
|
||||||
|
<label for="title">Neue Aufgabe hinzufügen:</label>
|
||||||
|
<input type="text" name="title" id="title" required>
|
||||||
|
|
||||||
|
<button>Speichern</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def print_exception_page(title, message, exception):
|
||||||
|
print_header(title)
|
||||||
|
enc_print("<p>{}</p>".format(message))
|
||||||
|
|
||||||
|
# Exception ausgeben
|
||||||
|
enc_print(repr(exception))
|
||||||
|
|
||||||
|
print_footer()
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
# IO-Funktionen
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TASKS_PATH = "tasks/"
|
||||||
|
|
||||||
|
|
||||||
|
# Speichert den Task task json-codiert unter dem Namen filename
|
||||||
|
def write_task(filename, task):
|
||||||
|
# Speichere das Dictionary JSON-codiert
|
||||||
|
with open(join(TASKS_PATH, filename), 'w') as outfile:
|
||||||
|
json.dump(task, outfile)
|
||||||
|
|
||||||
|
|
||||||
|
# Liest den json-codiert gespeicherten Task mit Dateiname filename ein
|
||||||
|
def read_task(filename):
|
||||||
|
# Öffne den JSON-codierten Task
|
||||||
|
with open(join(TASKS_PATH, filename), 'r') as json_file:
|
||||||
|
# Decodiere die JSON-Datei in ein Dictionary
|
||||||
|
return json.load(json_file)
|
||||||
|
|
||||||
|
|
||||||
|
# Liefert alle gespeicherten Tasks
|
||||||
|
def read_all_tasks():
|
||||||
|
# Liefert alle Dateien im Ordner tasks_path
|
||||||
|
file_names = [f for f in listdir(TASKS_PATH) if isfile(join(TASKS_PATH, f))]
|
||||||
|
|
||||||
|
# Liest alle vorher bestimmten Tasks ein
|
||||||
|
tasks = [read_task(f) for f in file_names]
|
||||||
|
|
||||||
|
# Sortiert die Tasks aufsteigend nach title (mit reverse=TRUE absteigend)
|
||||||
|
sorted_tasks = sorted(tasks, key=lambda t: t["title"], reverse=False)
|
||||||
|
|
||||||
|
return sorted_tasks
|
||||||
|
|
||||||
|
|
||||||
|
# Löscht den Task mit Dateiname filename
|
||||||
|
def delete_task(filename):
|
||||||
|
os.remove(join(TASKS_PATH, filename))
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
# Task-Funktionen
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Erstellt einen neuen Task mit dem Titel title, dem aktuellen timestamp und dem state open
|
||||||
|
def create_task(title):
|
||||||
|
# Rufe die aktuelle Uhrzeit ab
|
||||||
|
timestamp = get_timestamp()
|
||||||
|
|
||||||
|
# Erstelle den Task als Dictionary
|
||||||
|
task = {
|
||||||
|
"title": title,
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"state": "open"
|
||||||
|
}
|
||||||
|
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
# Flippt den Zustand des Tasks zwischen done und open
|
||||||
|
def flip_task_state(task):
|
||||||
|
if task['state'] == 'done':
|
||||||
|
task['state'] = 'open'
|
||||||
|
else:
|
||||||
|
task['state'] = 'done'
|
||||||
|
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
# Filtert all_tasks nach allen Tasks state == open
|
||||||
|
def get_open_tasks(all_tasks):
|
||||||
|
open_tasks = [t for t in all_tasks if t["state"] == "open"]
|
||||||
|
|
||||||
|
return open_tasks
|
||||||
|
|
||||||
|
|
||||||
|
# Filtert all_tasks nach allen Tasks state == done
|
||||||
|
def get_done_tasks(all_tasks):
|
||||||
|
open_tasks = [t for t in all_tasks if t["state"] == "done"]
|
||||||
|
|
||||||
|
return open_tasks
|
Reference in New Issue
Block a user