06: Demos und Labor

main
Teena Steger 2026-04-21 15:26:29 +02:00
parent cfb847341f
commit 0317d26add
7 changed files with 315 additions and 0 deletions

View File

@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("hello world")
}

View File

@ -0,0 +1,3 @@
module example.com/taskmanager
go 1.24.5

View File

@ -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.")
}
}

View File

@ -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
}

View File

@ -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
}
]
}

View File

@ -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`).

View File

@ -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>