forked from WEB-IB-SS26/development-ib
Compare commits
No commits in common. "fe3e216752092f6ebaa42516b056609d2bffcd88" and "20691f5d4fb560a53fa3317ac13ef5eeee2f6505" have entirely different histories.
fe3e216752
...
20691f5d4f
|
|
@ -1,7 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("hello world")
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
module example.com/taskmanager
|
|
||||||
|
|
||||||
go 1.24.5
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
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.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
# Ü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`). Hierzu müssen Sie Module verwenden. Eine kurze Anleitung dazu finden Sie hier: [Abhängigkeiten mit go.mod](anleitung_extlib.md)
|
|
||||||
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
# Abhängigkeitsverwaltung mit `go.mod`
|
|
||||||
|
|
||||||
## Hintergrund
|
|
||||||
|
|
||||||
Externe Pakete, die im Code importiert werden, werden über eine `go.mod`‑Datei verwaltet. Diese Datei definiert das Modul und listet alle Abhängigkeiten auf. Sie gehört fest zum Projekt und wird im Quellcode‑Repository mitgeführt.
|
|
||||||
|
|
||||||
## Anweisungen
|
|
||||||
|
|
||||||
*Annahme*: Go-Programm ist bereits vorhanden und die Imports im Code sind gesetzt. Außerdem befinden Sie sich in dem Ordner mit dem Go-Programm.
|
|
||||||
|
|
||||||
1. **Modul initialisieren (falls noch nicht geschehen)**
|
|
||||||
```bash
|
|
||||||
go mod init example.com/myapp
|
|
||||||
```
|
|
||||||
Der Modulpfad entspricht in der Praxis meist der Repository‑Adresse, z. B. `github.com/mymodule`. Für einfache Beispiele genügt ein Platzhalter wie z.B. `example.com/myapp`
|
|
||||||
|
|
||||||
2. **Abhängigkeiten auflösen und aufräumen**
|
|
||||||
```bash
|
|
||||||
go mod tidy
|
|
||||||
```
|
|
||||||
Dadurch werden alle im Code verwendeten Imports heruntergeladen und ins `go.mod` eingetragen. Nicht mehr benötigte Pakete werden entfernt.
|
|
||||||
|
|
||||||
3. **Programm starten**
|
|
||||||
```bash
|
|
||||||
go run .
|
|
||||||
```
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<!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