forked from WEB-IB-SS26/development-ib
06: Demos und Labor
parent
cfb847341f
commit
0317d26add
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("hello world")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
module example.com/taskmanager
|
||||||
|
|
||||||
|
go 1.24.5
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Frage: Was macht dieser Teil genau?
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Println("Usage: add <task> | list | done <id>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lädt alle Tasks aus JSON-Datei in eine Liste
|
||||||
|
// Gibt eine leere Liste zurück, falls die JSON-Datei noch nicht existiert
|
||||||
|
// Gibt Fehlermeldung vom Typ error zurück, falls etwas schief gelaufen ist
|
||||||
|
tasklist, err := LoadTasks("tasks.json")
|
||||||
|
|
||||||
|
// TODO: Fehlerbehandlung
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Fehler beim Laden der JSON-Datei: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Je nach Kommandozeilenargument wird:
|
||||||
|
// - Task neu erstellt und zur Liste hinzugefügt (auch in JSON-Datei)
|
||||||
|
// - Alle Tasks aus der Liste ausgegeben inkl. Status ("✓" für done, sonst " ")
|
||||||
|
// - Task als done markiert und Ergebnis ausgegeben
|
||||||
|
switch os.Args[1] {
|
||||||
|
case "add":
|
||||||
|
// TODO: Prüfen, ob 3. Kommandozeilenargument für Title vorliegt
|
||||||
|
if len(os.Args) < 3 {
|
||||||
|
fmt.Println("Geben Sie einen Titel ein.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Task zur Liste hinzufügen
|
||||||
|
tasklist.Add(os.Args[2])
|
||||||
|
|
||||||
|
// TODO: Liste in JSON-Datei speichern
|
||||||
|
tasklist.Save("tasks.json")
|
||||||
|
|
||||||
|
// Ergebnis ausgeben
|
||||||
|
fmt.Println("Task added.")
|
||||||
|
|
||||||
|
case "list":
|
||||||
|
// TODO: Durch alle Tasks der Liste iterieren
|
||||||
|
for _, task := range tasklist.Tasks {
|
||||||
|
// TODO: Task-Status bestimmen und inklusive ID und Title ausgeben
|
||||||
|
status := " "
|
||||||
|
if task.Done {
|
||||||
|
status = "✓"
|
||||||
|
}
|
||||||
|
fmt.Printf("[%s] %d: %s\n", status, task.ID, task.Title)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case "done":
|
||||||
|
// TODO: Prüfen, ob 3. Kommandozeilenargument für ID vorliegen
|
||||||
|
if len(os.Args) < 3 {
|
||||||
|
fmt.Println("Geben Sie eine ID ein.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Prüfen, ob ID vom Typ integer, sonst Fehlermeldung und Abbruch
|
||||||
|
// Tipp: strconv.Atoi(string)
|
||||||
|
id, err := strconv.Atoi(os.Args[2])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Falsche Eingabe der ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: Task auf done setzen
|
||||||
|
tasklist.Complete(id)
|
||||||
|
|
||||||
|
// TODO: Taskliste in JSON-Datei speichern
|
||||||
|
tasklist.Save("tasks.json")
|
||||||
|
|
||||||
|
// Ergebnis ausgeben
|
||||||
|
fmt.Println("Task marked as done.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Task repräsentiert eine einzelne To-Do-Aufgabe mit ID, Titel und Status.
|
||||||
|
// Tipp: struct verwenden
|
||||||
|
type Task struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Done bool `json:"done"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: TaskList enthält eine Liste von Aufgaben (Tasks).
|
||||||
|
type TaskList struct {
|
||||||
|
Tasks []Task `json:"tasks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Fügt einen neuen Task mit übergebenen Titel in die Liste ein.
|
||||||
|
// Die neue ID entspricht der Anzahl der Elemente in der Liste. (ok, weil keine Tasks gelöscht werden)
|
||||||
|
func (tl *TaskList) Add(title string) {
|
||||||
|
id := len(tl.Tasks) + 1
|
||||||
|
newTask := Task{ID: id, Title: title, Done: false}
|
||||||
|
tl.Tasks = append(tl.Tasks, newTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Setzt vorhandenen Task mit übergebener ID auf den Status done.
|
||||||
|
// Annahme: Wir wissen nicht, wie ID erstellt wird.
|
||||||
|
func (tl *TaskList) Complete(id int) {
|
||||||
|
for i := range tl.Tasks {
|
||||||
|
if tl.Tasks[i].ID == id {
|
||||||
|
tl.Tasks[i].Done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liste wird im JSON-Format in einer Datei mit übergebenen Dateinamen gespeichert
|
||||||
|
func (tl *TaskList) Save(filename string) error {
|
||||||
|
data, err := json.MarshalIndent(tl, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(filename, data, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Lädt eine Liste von Tasks aus einer JSON-Datei (Dateiname als Parameter übergeben)
|
||||||
|
// Falls die Datei noch nicht existiert, wird eine leere Liste (neu) zurückgegeben
|
||||||
|
// Tipp 1: Einlesen einer Datei: os.ReadFile(filename)
|
||||||
|
// Tipp 2: JSON-Daten in TaskList-Struktur umwandeln: json.Unmarshal(data, &tl)
|
||||||
|
func LoadTasks(filename string) (*TaskList, error) {
|
||||||
|
data, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return &TaskList{}, nil
|
||||||
|
}
|
||||||
|
var tl TaskList
|
||||||
|
jsonErr := json.Unmarshal(data, &tl)
|
||||||
|
return &tl, jsonErr
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "Vorlesung besuchen",
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "Go by Example durcharbeiten",
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "Webserver lokal installieren",
|
||||||
|
"done": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "Uebungen durcharbeiten",
|
||||||
|
"done": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Übungsblatt 06
|
||||||
|
|
||||||
|
## 1. SWAGGER-Übung: Workshop-API
|
||||||
|
|
||||||
|
**Aufgabenstellung**: Erstellen Sie eine OpenAPI-Spezifikation für die Workshop-Anmeldung aus Übungsblatt 04 ([HTML-Formular](workshop-anmeldung.html)).
|
||||||
|
|
||||||
|
#### Arbeitsschritte
|
||||||
|
|
||||||
|
1. Setzen die OpenAPI-Version auf `3.0.0`.
|
||||||
|
2. Setzen Sie Meta-Daten wie Titel und API-Version im Info-Objekt.
|
||||||
|
3. Setzen Sie `https://web4-637691723779.europe-west1.run.app` als URL im Servers-Objekt.
|
||||||
|
4. Setzen Sie einen **Pfad** `/registrierung` für die HTTP-Methode `POST`. Definieren Sie eine Beschreibung, den Request-Body sowie mögliche Antworten des Servers.
|
||||||
|
1. Request-Body für die Übergabe von **Formulardaten**
|
||||||
|
2. Request-Body für die Übergabe von **JSON-Daten**
|
||||||
|
|
||||||
|
_Tipp: Verwenden Sie das Components-Objekt._
|
||||||
|
|
||||||
|
5. Verwenden Sie Enums (https://swagger.io/docs/specification/v3_0/data-models/enums/) für die Spezifikation der Checkboxen und der Radiobuttons (s. Hinweis unten).
|
||||||
|
- Beispiel für `enum` in JSON-OpenAPI:
|
||||||
|
```json
|
||||||
|
"farbe": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["rot","gruen","blau"],
|
||||||
|
"example": "gruen"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
6. Testen Sie Ihre API-Spezifikation mit Swagger.
|
||||||
|
|
||||||
|
#### Hinweis
|
||||||
|
Der serverseitige API-Endpunkt hat sich geändert (neue URL: `https://web4-637691723779.europe-west1.run.app`) und wurde nun folgendermaßen implementiert:
|
||||||
|
|
||||||
|
1. Wenn die Checkbox aktiviert wurde, wird für **agb**, **newsletter** und **equipment** nur noch der Wert (`value`-Attribut) _ja_ akzeptiert.
|
||||||
|
2. Für **format** werden die Werte (`value`-Attribut) _online_ und _praesenz_ akzeptiert, je nach dem, welcher Radiobutton aktiviert wurde.
|
||||||
|
3. Die Eingabefelder zu Vorname, Nachname, AGB und Format sind nun Pflichtfelder.
|
||||||
|
|
||||||
|
## 2. Go-Übung: Kommandozeilenprogramm
|
||||||
|
|
||||||
|
**Aufgabenstellung**: Entwickeln Sie ein Kommandozeilenprogramm in Go, mit dem Nutzer:innen ihre persönliche Büchersammlung verwalten können.
|
||||||
|
|
||||||
|
#### Arbeitsschritte
|
||||||
|
|
||||||
|
Implementieren Sie ein Programm mit folgenden Funktionen:
|
||||||
|
|
||||||
|
1. **Buch hinzufügen**
|
||||||
|
```bash
|
||||||
|
go run main.go book.go add "Titel" "Autor"
|
||||||
|
```
|
||||||
|
→ Fügt ein neues Buch zur Sammlung hinzu.
|
||||||
|
|
||||||
|
2. **Bücher auflisten**
|
||||||
|
```bash
|
||||||
|
go run main.go book.go list
|
||||||
|
```
|
||||||
|
→ Zeigt alle Bücher mit ID, Titel, Autor und Lesestatus.
|
||||||
|
|
||||||
|
3. **Buch als gelesen markieren**
|
||||||
|
```bash
|
||||||
|
go run main.go book.go read <ID>
|
||||||
|
```
|
||||||
|
→ Markiert das Buch mit der angegebenen ID als gelesen.
|
||||||
|
|
||||||
|
4. **Persistenz**
|
||||||
|
- Die Bücher sollen in einer Datei `books.json` gespeichert und beim Programmstart wieder geladen werden.
|
||||||
|
- Verwenden Sie dafür das `encoding/json`-Paket und `os.ReadFile` / `os.WriteFile`.
|
||||||
|
|
||||||
|
### Hinweise
|
||||||
|
|
||||||
|
- Verwenden Sie `struct` für die Buch- und Bibliotheksdaten.
|
||||||
|
- Arbeiten Sie mit `slice` zur Verwaltung der Bücherliste.
|
||||||
|
- Nutzen Sie Methoden zur Kapselung von Logik (z. B. `Add`, `MarkRead`, `Save`).
|
||||||
|
- Behandeln Sie Fehler sinnvoll und benutzerfreundlich.
|
||||||
|
- Strukturieren Sie Ihr Projekt in mindestens zwei Dateien (`main.go`, `book.go`).
|
||||||
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Workshop-Anmeldung</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form action="https://web4-637691723779.europe-west1.run.app/registrierung" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Persönliche Angaben:</legend>
|
||||||
|
<label for="vorname">Vorname:</label><br>
|
||||||
|
<input type="text" name="vorname" id="vorname" placeholder="Vorname" required><br>
|
||||||
|
|
||||||
|
<label for="nachname">Nachname:</label><br>
|
||||||
|
<input type="text" name="nachname" id="nachname" placeholder="Nachname" required><br>
|
||||||
|
|
||||||
|
<label for="email">E-Mail:</label><br>
|
||||||
|
<input type="email" name="email" id="email" autocomplete="email"><br>
|
||||||
|
|
||||||
|
<label for="telefon">Handynummer:</label><br>
|
||||||
|
<input type="tel" name="telefon" id="telefon" pattern="^01[5-7][0-9]{7,10}$"><br><br>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Kursauswahl:</legend>
|
||||||
|
<label for="kurs">Kurs:</label><br>
|
||||||
|
<input type="text" name="kurs" id="kurs" value="Webentwicklung Basics" disabled><br><br>
|
||||||
|
|
||||||
|
<label for="sessions">Bevorzugte Session:</label><br>
|
||||||
|
<select id="sessions" name="sessions" multiple size="4">
|
||||||
|
<option value="vormittag">Vormittag</option>
|
||||||
|
<option value="nachmittag">Nachmittag</option>
|
||||||
|
<option value="abendsession">Abend</option>
|
||||||
|
<option value="wochenende">Wochenende</option>
|
||||||
|
</select><br>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Zusätzliche Optionen:</legend>
|
||||||
|
<input type="checkbox" id="agb" name="agb" value="ja" required>
|
||||||
|
<label for="agb">Ich akzeptiere die Teilnahmebedingungen.</label><br>
|
||||||
|
|
||||||
|
<input type="checkbox" id="newsletter" name="newsletter" value="ja">
|
||||||
|
<label for="newsletter">Newsletter abonnieren.</label><br>
|
||||||
|
|
||||||
|
<input type="checkbox" id="equipment" name="equipment" value="ja">
|
||||||
|
<label for="equipment">Ich benötige spezielles Equipment.</label><br>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Teilnahmeformat:</legend>
|
||||||
|
Format wählen:<br>
|
||||||
|
<input type="radio" id="online" name="format" value="online" required>
|
||||||
|
<label for="online">Online</label><br>
|
||||||
|
|
||||||
|
<input type="radio" id="praesenz" name="format" value="praesenz">
|
||||||
|
<label for="praesenz">Präsenz</label><br>
|
||||||
|
</fieldset>
|
||||||
|
<br>
|
||||||
|
<input type="submit" value="Jetzt anmelden">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue