Information
Diese Aufgabe basiert auf keinem CS50 Practice Problem.
Disclaimer: Diese Aufgabe wurde nicht vom Lehrstuhl herausgegeben und kann Fehler enthalten. Sie dient lediglich zu Übungszwecken!
Kontaktformulare sind ein zentraler Bestandteil fast jeder Website. Sie bieten eine einfache und strukturierte Möglichkeit, Informationen zwischen Nutzern und Website-Betreibern auszutauschen, sei es für Support-Anfragen, Feedback oder Geschäftsanfragen.
In dieser Aufgabe möchten wir unser eigenes Kontaktformular bauen, sodass auch wir kontaktiert werden könnten! Hierzu verwenden wir Flask auf der Server-Seite und Bootstrap auf der Client-Seite, dass unsere Website auch gut aussieht.
Um das Aufgabenmeterial herunterzuladen, gib folgenden Befehl in ein neues Terminal in deinem Codespace ein:
wget -O - https://inf-lab.dev/contact/material/lab-contact.zip.sh | bashWie immer, wenn wir einen vorgegebenen Code haben, sollten wir diesen zuerst verstehen. Betrachte deshalb den gegebenen Code in app.py, error.html und layout.html und beantworte folgende Fragen.
In der Datei app.py ist eine Klasse ContactRequest gegeben. Diese hat ein Attribut id welches automatisch einen eindeutigen String enthält um diese Anfrage zu identifizieren[1].
id Attribut zugegriffen werden?In der Datei error.html ist ein Jinja2 Template gegeben, welches eine Fehlermeldung ausgibt.
<html> oder <body> Element?`In der Datei layout.html ist ein weiteres Template gegeben. Dieses stellt die Struktur unserer Seite dar.
Ändere abschließend das Template layout.html so ab, dass es mittels extends erweitert werden kann um somit Inhalt einzufügen. Füge hierzu einen Block ein und nenne diesen body, sodass das error.html Template auch funktioniert.
Unsere HTML-Dateien verwenden hier Jinja2 Templates, welche von Flask ausgewertet werden können. Somit können wir recht einfach HTML dynamisch aus unseren Python Daten erstellen.
Im folgenden findet sich ein einfaches Beispiel, welches in abgewandelter Version auch in der Dokumentation gefunden werden kann. open_todos und todos sind hierbei Variablen, die dem Template explizit übergeben wurden.
<div>
<h1>My ToDos</h1>
Open todos: {{ open_todos }}
<ul id="list">
{% for todo in todos %}
<li>{{ todo }}</li>
{% endfor %}
</ul>
{# some comment #}
</div>Warnung
Viele unserer Implementierungen in dieser Aufgabe sind anfällig für diverse Angriffe und sollten in der Praxis anders umgesetzt werden. Für die Zwecke von Inf-Einf reicht das aber aus.
Da wir nun die Grundstruktur unserer Website verstanden und erweitert haben, ist es an der Zeit das eigentliche Kontaktformular zu erstellen.
Erstelle hierzu eine neue Datei index.html an der passenden Stelle. Erweitere in dieser das layout.html und erstelle ein Formular. Das Formular soll, sobald es abgesendet wird, eine POST Anfrage an den /submit Pfad (welche wir später in Python definieren werden) senden.
Im Formular muss der Benutzer die Möglichkeit haben, seinen Namen name, seine E-Mail email, einen Betreff subject und eine eigentliche Nachricht text einzugeben. Wähle für jedes dieser Felder ein sinnvolles HTML-Element mit gut gewählten Attributen und achte darauf, dass der Benutzer immer weiß in welchem Feld er sich gerade befindet. Vergiss nicht, auch einen Send Button hinzuzufügen.
Füge schließlich noch einen Button hinzu, um das Formular abzusenden.
Dass unser Kontaktformular auch gut aussieht, soll Bootstrap für das Styling verwendet werden. Achte deshalb darauf, allen Elementen passende Bootstrap Klassen zuzuweisen.
Das fertige Formular, inklusive des Layouts, könnte wie im folgenden Bild aussehen.

Folgender Code ist ein leicht abgeändertes Beispiel aus der Bootstrap Dokumentation zu Formularen.
<label for="title" class="form-label"> Titel </label>
<input type="text" class="form-control" id="title" name="title" />Da wir nun unsere index.html Datei fertig geschrieben haben, sollten wir diese auch über Flask bereitstellen. Erstelle hierzu in der Datei app.py deinen Flask Server.
Beginne damit, deine app zu erstellen und definiere schließlich eine route für den / Pfad. Der / Pfad soll GET Anfragen akzeptieren und das Template index.html ausgeben.
Wenn du alles richtig gemacht hast, solltest du nun deinen Server starten können, und direkt mit deinem Formular begrüßt werden!
Um Templates auszugeben (zu "rendern"), kann die Funktion render_template verwendet werden. Folgender Beispielcode würde beispielsweise das Template todos.html ausgeben. Nach dem Namen des Templates können optional weitere benannte Parameter folgen um einzelne Variablen im Template verfügbar zu machen.
from flask import render_template
render_template("todos.html", count=4)Wichtig: Vergiss nicht, den Rückgabewert von render_template auch zu returnen, sonst wird das Template zwar ausgeführt aber nicht ausgegeben!
Nun haben wir schon einen Flask Server, welcher unsere index.html mit Formular darstellt. Nun möchten wir noch die Eingaben des Formulars verarbeiten.
Erstelle hierzu eine weitere Flask route für den Pfad, welchen wir in Teilaufgabe 2 im <form> angegeben haben. Diese URL soll nur POST Anfragen akzeptieren. Lies dann in dieser Funktion die per Formular übermittelten Parameter aus und prüfe, ob diese überhaupt angegeben wurden. Sollte ein Parameter fehlen, kannst du das Template error.html verwenden um eine Fehlermeldung auszugeben.
Im folgenden findest du ein Beispielbild, wie Fehlermeldungen mit dem error.html Template aussehen können.

Sollten alle Daten korrekt übermittelt worden sein, soll aus diesen eine neue ContactRequest erstellt werden. Speichere diese ContactRequest schließlich in einer Datenstruktur deiner Wahl. Beachte hierbei, dass wir die ContactRequest später anhand ihrer id finden wollen. Gib im Erfolgsfall zusätzlich einen Success! Text zurück.
Information
Da wir die ContactRequests nur in einer Variable speichern bedeutet das, dass Kontaktanfragen nur gespeichert werden, solange der Server auch läuft. Dies wäre in der Praxis eher unpraktisch. Für die Zwecke dieser Übung ist das aber vollkommen ausreichend.
Achte darauf, dass deine Funktionen auch korrekte HTTP-Antwortstatuscodes verwenden.
Um den Wert eines übermittelten Formularfeldes auszulesen, kann die request.form.get(name) Funktion verwendet werden. Im folgenden findest du ein informelles Beispiel, um das im HTML dargestellte Feld auszulesen.
<label for="task_field">Task</label> <input name="task" id="task_field" />from flask import request
task = request.form.get("task")Wichtig: Dass du ein Feld im HTML-Formular erstellt hast, bedeutet nicht zwingend, dass es auch an den Server übermittelt wird. Prüfe deshalb immer erst ob das Feld nicht None ist.
Benutze flask run in einem Terminal, während du dich im Verzeichnis lab-contact befindest, um deinen Flask-Server zu starten, der die Webseite bereitstellt.
Für diese Aufgabe gibt es kein check50, da die Implementierungen sehr unterschiedlich ausfallen können.
Leider unterstützt style50 keine HTML-Dateien. Daher liegt es an dir, deine HTML-Tags sauber einzurücken und auszurichten. Deine app.py Datei kannst du jedoch mit folgendem Befehl überprüfen.
style50 app.py