diff --git a/forms.html b/forms.html
deleted file mode 100644
index cff32e1..0000000
--- a/forms.html
+++ /dev/null
@@ -1,192 +0,0 @@
-
-
-
-
-
-
- D&D Monster Form
-
-
-
-
-
-
-
-
-
-
-
diff --git a/handlers/about_handler.go b/handlers/about_handler.go
new file mode 100644
index 0000000..83e2b6c
--- /dev/null
+++ b/handlers/about_handler.go
@@ -0,0 +1,26 @@
+package handlers
+
+import (
+ "embed"
+ "html/template"
+ "log"
+ "net/http"
+)
+
+func AboutHandler(content embed.FS) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ tmpl, err := template.ParseFS(content, "templates/base.html", "templates/header.html", "templates/main.html", "templates/footer.html", "templates/about.html")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = tmpl.ExecuteTemplate(w, "about", map[string]interface{}{
+ "Title": "Dungeons & Dragons Monster Generator",
+ })
+ if err != nil {
+ log.Printf("Template execution error: %v\n", err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ }
+}
diff --git a/handlers/add_monster_handler.go b/handlers/add_monster_handler.go
new file mode 100644
index 0000000..222e7f4
--- /dev/null
+++ b/handlers/add_monster_handler.go
@@ -0,0 +1,85 @@
+package handlers
+
+import (
+ "ddServer/model"
+ "net/http"
+ "strconv"
+)
+
+func AddMonster(Monsters *[]model.Monster) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ // TODO
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ err := r.ParseForm()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ monster := model.Monster{
+ Name: r.FormValue("name"),
+ Source: r.FormValue("source"),
+ Size: []string{r.FormValue("size")},
+ Type: r.FormValue("type"),
+ Alignment: []string{r.FormValue("alignment")},
+ AC: []model.AC{
+ {
+ AC: parseInt(r.FormValue("ac")),
+ From: []string{r.FormValue("acFrom")},
+ },
+ },
+ HP: model.HP{
+ Average: parseInt(r.FormValue("hpAverage")),
+ Formula: r.FormValue("hpFormula"),
+ },
+ Speed: model.Speed{
+ Walk: parseInt(r.FormValue("speed")),
+ },
+ Str: parseInt(r.FormValue("str")),
+ Dex: parseInt(r.FormValue("dex")),
+ Con: parseInt(r.FormValue("con")),
+ Int: parseInt(r.FormValue("int")),
+ Wis: parseInt(r.FormValue("wis")),
+ Cha: parseInt(r.FormValue("cha")),
+ Save: model.Save{
+ Dex: r.FormValue("saveDex"),
+ Con: r.FormValue("saveCon"),
+ Wis: r.FormValue("saveWis"),
+ },
+ Skill: model.Skill{
+ Perception: r.FormValue("perception"),
+ Stealth: r.FormValue("stealth"),
+ },
+ DamageRes: []string{r.FormValue("damageRes")},
+ Senses: []string{r.FormValue("senses")},
+ Languages: []string{r.FormValue("languages")},
+ CR: r.FormValue("cr"),
+ Traits: []model.Trait{
+ {
+ Name: r.FormValue("traitName"),
+ Entries: []string{r.FormValue("traitEntry")},
+ },
+ },
+ Actions: []model.Action{
+ {
+ Name: r.FormValue("actionName"),
+ Entries: []string{r.FormValue("actionEntry")},
+ },
+ },
+ }
+ *Monsters = append(*Monsters, monster)
+ }
+}
+
+// parseInt konvertiert einen String zu einem Integer und gibt 0 zurück, wenn die Konvertierung fehlschlägt
+func parseInt(s string) int {
+ i, err := strconv.Atoi(s)
+ if err != nil {
+ return 0
+ }
+ return i
+}
diff --git a/handlers/contact_handler.go b/handlers/contact_handler.go
new file mode 100644
index 0000000..407fe75
--- /dev/null
+++ b/handlers/contact_handler.go
@@ -0,0 +1,26 @@
+package handlers
+
+import (
+ "embed"
+ "html/template"
+ "log"
+ "net/http"
+)
+
+func ContactHandler(content embed.FS) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ tmpl, err := template.ParseFS(content, "templates/base.html", "templates/header.html", "templates/main.html", "templates/footer.html", "templates/about.html", "templates/contact.html")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = tmpl.ExecuteTemplate(w, "contact", map[string]interface{}{
+ "Title": "Dungeons & Dragons Monster Generator",
+ })
+ if err != nil {
+ log.Printf("Template execution error: %v\n", err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ }
+}
diff --git a/handlers/form_handler.go b/handlers/form_handler.go
new file mode 100644
index 0000000..dc57041
--- /dev/null
+++ b/handlers/form_handler.go
@@ -0,0 +1,26 @@
+package handlers
+
+import (
+ "embed"
+ "html/template"
+ "log"
+ "net/http"
+)
+
+func FormHandler(content embed.FS, filename string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ tmpl, err := template.ParseFS(content, "templates/base.html", "templates/header.html", "templates/main.html", "templates/footer.html", "templates/monsterForm.html")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = tmpl.ExecuteTemplate(w, "base", map[string]interface{}{
+ "Title": "Dungeons & Dragons Monster Generator",
+ })
+ if err != nil {
+ log.Printf("Template execution error: %v\n", err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ }
+}
diff --git a/handlers/submit_handler.go b/handlers/submit_handler.go
new file mode 100644
index 0000000..744b879
--- /dev/null
+++ b/handlers/submit_handler.go
@@ -0,0 +1,65 @@
+package handlers
+
+import (
+ "ddServer/model"
+ "embed"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "os"
+ "sync"
+)
+
+var mu sync.Mutex
+
+// submitHandler verarbeitet die Formulardaten
+func SubmitHandler(content embed.FS, chars *[]model.Character, Monsters *[]model.Monster, filename string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // Formulardaten parsen
+ err := r.ParseForm()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Monster-Objekt erstellen
+ filename := r.FormValue("filename")
+
+ // Charakter-Objekt erstellen oder aktualisieren
+ mu.Lock()
+ defer mu.Unlock()
+
+ char := model.GetOrCreateCharacter(filename, *chars)
+ char.Monster = append(char.Monster, *Monsters...)
+
+ // Charakterdaten in JSON umwandeln
+ charJSON, err := json.Marshal(char)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // JSON-Daten in die Datei schreiben
+ err = model.WriteToFile(filename, charJSON)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ // Dateiinhalt lesen
+ fileContent, err := os.ReadFile(filename)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Datei zum Download anbieten
+ w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
+ w.Header().Set("Content-Type", "application/json")
+ w.Write(fileContent)
+ }
+}
diff --git a/main.go b/main.go
index d2f8ba3..e91edee 100644
--- a/main.go
+++ b/main.go
@@ -1,366 +1,33 @@
package main
import (
+ "ddServer/handlers"
+ "ddServer/model"
"embed"
- "encoding/json"
"fmt"
- "html/template"
"net/http"
- "os"
- "strconv"
"sync"
- "time"
)
-// Monster struct für die Daten des Monsters
-type Monster struct {
- Name string `json:"name"`
- Source string `json:"source"`
- Size []string `json:"size"`
- Type string `json:"type"`
- Alignment []string `json:"alignment"`
- AC []AC `json:"ac"`
- HP HP `json:"hp"`
- Speed Speed `json:"speed"`
- Save Save `json:"save"`
- Skill Skill `json:"skill"`
- DamageRes []string `json:"damageResistances"`
- Senses []string `json:"senses"`
- Languages []string `json:"languages"`
- CR string `json:"cr"`
- Traits []Trait `json:"trait"`
- Actions []Action `json:"action"`
- Str int `json:"str"`
- Dex int `json:"dex"`
- Con int `json:"con"`
- Int int `json:"int"`
- Wis int `json:"wis"`
- Cha int `json:"cha"`
-}
-
-type AC struct {
- AC int `json:"ac"`
- From []string `json:"from"`
-}
-
-type HP struct {
- Average int `json:"average"`
- Formula string `json:"formula"`
-}
-
-type Speed struct {
- Walk int `json:"walk"`
-}
-
-type Save struct {
- Dex string `json:"dex"`
- Con string `json:"con"`
- Wis string `json:"wis"`
-}
-
-type Skill struct {
- Perception string `json:"perception"`
- Stealth string `json:"stealth"`
-}
-
-type Trait struct {
- Name string `json:"name"`
- Entries []string `json:"entries"`
-}
-
-type Action struct {
- Name string `json:"name"`
- Entries []string `json:"entries"`
-}
-
-// Character struct für die Daten des Charakters
-type Character struct {
- Meta Meta `json:"_meta"`
- Monster []Monster `json:"monster"`
-}
-
-// Meta struct für Meta-Informationen
-type Meta struct {
- Sources []Source `json:"sources"`
- DateAdded int64 `json:"dateAdded"`
- DateLastModified int64 `json:"dateLastModified"`
- DateLastModifiedHash string `json:"_dateLastModifiedHash"`
-}
-
-type Source struct {
- Json string `json:"json"`
- Abbreviation string `json:"abbreviation"`
- Authors []string `json:"authors"`
- ConvertedBy []string `json:"convertedBy"`
- Version string `json:"version"`
-}
-
var (
mu sync.Mutex
- chars []Character
+ chars []model.Character
//go:embed templates/*.html
//go:embed images/*
content embed.FS
- Monsters []Monster
+ Monsters []model.Monster
)
func main() {
filename := ""
- http.HandleFunc("/", formHandler(filename))
- http.HandleFunc("/submit", submitHandler(filename))
+ http.HandleFunc("/", handlers.FormHandler(content, filename))
+ http.HandleFunc("/submit", handlers.SubmitHandler(content, &chars, &Monsters, filename))
http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.FS(content))))
- http.HandleFunc("/addMonster", addMonster())
+ http.HandleFunc("/addMonster", handlers.AddMonster(&Monsters))
+ http.HandleFunc("/about", handlers.AboutHandler(content))
+ http.HandleFunc("/contact", handlers.ContactHandler(content))
fmt.Println("Server gestartet, erreichbar unter http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
-
-func formHandler(filename string) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- tmpl, err := template.ParseFS(content, "templates/base.html", "templates/header.html", "templates/main.html", "templates/footer.html", "templates/monsterForm.html")
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- err = tmpl.ExecuteTemplate(w, "base", map[string]interface{}{
- "Title": "Dungeons & Dragons Monster Generator",
- })
- if err != nil {
- fmt.Println("Template execution error:", err)
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
- }
-}
-
-// submitHandler verarbeitet die Formulardaten
-func submitHandler(filename string) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodPost {
- http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
- return
- }
-
- // Formulardaten parsen
- err := r.ParseForm()
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- // Monster-Objekt erstellen
- filename := r.FormValue("filename")
- /*monster := Monster{
- Name: r.FormValue("name"),
- Source: r.FormValue("source"),
- Size: []string{r.FormValue("size")},
- Type: r.FormValue("type"),
- Alignment: []string{r.FormValue("alignment")},
- AC: []AC{
- {
- AC: parseInt(r.FormValue("ac")),
- From: []string{r.FormValue("acFrom")},
- },
- },
- HP: HP{
- Average: parseInt(r.FormValue("hpAverage")),
- Formula: r.FormValue("hpFormula"),
- },
- Speed: Speed{
- Walk: parseInt(r.FormValue("speed")),
- },
- Str: parseInt(r.FormValue("str")),
- Dex: parseInt(r.FormValue("dex")),
- Con: parseInt(r.FormValue("con")),
- Int: parseInt(r.FormValue("int")),
- Wis: parseInt(r.FormValue("wis")),
- Cha: parseInt(r.FormValue("cha")),
- Save: Save{
- Dex: r.FormValue("saveDex"),
- Con: r.FormValue("saveCon"),
- Wis: r.FormValue("saveWis"),
- },
- Skill: Skill{
- Perception: r.FormValue("perception"),
- Stealth: r.FormValue("stealth"),
- },
- DamageRes: []string{r.FormValue("damageRes")},
- Senses: []string{r.FormValue("senses")},
- Languages: []string{r.FormValue("languages")},
- CR: r.FormValue("cr"),
- Traits: []Trait{
- {
- Name: r.FormValue("traitName"),
- Entries: []string{r.FormValue("traitEntry")},
- },
- },
- Actions: []Action{
- {
- Name: r.FormValue("actionName"),
- Entries: []string{r.FormValue("actionEntry")},
- },
- },
- }*/
-
- // Charakter-Objekt erstellen oder aktualisieren
- mu.Lock()
- defer mu.Unlock()
-
- char := getOrCreateCharacter(filename)
- char.Monster = append(char.Monster, Monsters...)
-
- // Charakterdaten in JSON umwandeln
- charJSON, err := json.Marshal(char)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- // JSON-Daten in die Datei schreiben
- err = writeToFile(filename, charJSON)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- // Dateiinhalt lesen
- fileContent, err := os.ReadFile(filename)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- // Datei zum Download anbieten
- w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
- w.Header().Set("Content-Type", "application/json")
- w.Write(fileContent)
- }
-}
-
-// writeToFile schreibt Daten in eine Datei
-func writeToFile(filename string, data []byte) error {
- file, err := os.Create(filename)
- if err != nil {
- return err
- }
- defer file.Close()
-
- _, err = file.Write(data)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// getOrCreateCharacter gibt das aktuelle Charakterobjekt zurück oder erstellt ein neues
-func getOrCreateCharacter(filename string) Character {
- for _, char := range chars {
- if char.Meta.DateLastModified == 0 {
- // Ein leeres Charakterobjekt wurde gefunden
- return char
- }
- }
-
- // Erstelle ein neues Charakterobjekt
- now := time.Now().Unix()
- newChar := Character{
- Meta: Meta{
- Sources: []Source{
- {
- Json: "Malgorgon",
- Abbreviation: "MG",
- Authors: []string{"Krzysztof"},
- ConvertedBy: []string{"Krzysztof"},
- Version: "unknown",
- },
- },
- DateAdded: now,
- DateLastModified: now,
- DateLastModifiedHash: fmt.Sprintf("%x", now),
- },
- Monster: []Monster{},
- }
-
- chars = append(chars, newChar)
-
- return newChar
-}
-
-// parseInt konvertiert einen String zu einem Integer und gibt 0 zurück, wenn die Konvertierung fehlschlägt
-func parseInt(s string) int {
- i, err := strconv.Atoi(s)
- if err != nil {
- return 0
- }
- return i
-}
-
-func addMonster() http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- // TODO
- if r.Method != http.MethodPost {
- http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
- return
- }
-
- err := r.ParseForm()
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- monster := Monster{
- Name: r.FormValue("name"),
- Source: r.FormValue("source"),
- Size: []string{r.FormValue("size")},
- Type: r.FormValue("type"),
- Alignment: []string{r.FormValue("alignment")},
- AC: []AC{
- {
- AC: parseInt(r.FormValue("ac")),
- From: []string{r.FormValue("acFrom")},
- },
- },
- HP: HP{
- Average: parseInt(r.FormValue("hpAverage")),
- Formula: r.FormValue("hpFormula"),
- },
- Speed: Speed{
- Walk: parseInt(r.FormValue("speed")),
- },
- Str: parseInt(r.FormValue("str")),
- Dex: parseInt(r.FormValue("dex")),
- Con: parseInt(r.FormValue("con")),
- Int: parseInt(r.FormValue("int")),
- Wis: parseInt(r.FormValue("wis")),
- Cha: parseInt(r.FormValue("cha")),
- Save: Save{
- Dex: r.FormValue("saveDex"),
- Con: r.FormValue("saveCon"),
- Wis: r.FormValue("saveWis"),
- },
- Skill: Skill{
- Perception: r.FormValue("perception"),
- Stealth: r.FormValue("stealth"),
- },
- DamageRes: []string{r.FormValue("damageRes")},
- Senses: []string{r.FormValue("senses")},
- Languages: []string{r.FormValue("languages")},
- CR: r.FormValue("cr"),
- Traits: []Trait{
- {
- Name: r.FormValue("traitName"),
- Entries: []string{r.FormValue("traitEntry")},
- },
- },
- Actions: []Action{
- {
- Name: r.FormValue("actionName"),
- Entries: []string{r.FormValue("actionEntry")},
- },
- },
- }
- Monsters = append(Monsters, monster)
- }
-}
diff --git a/model/model.go b/model/model.go
new file mode 100644
index 0000000..03f2949
--- /dev/null
+++ b/model/model.go
@@ -0,0 +1,140 @@
+package model
+
+import (
+ "fmt"
+ "os"
+ "time"
+)
+
+// Monster struct für die Daten des Monsters
+type Monster struct {
+ Save Save `json:"save"`
+ Skill Skill `json:"skill"`
+ HP HP `json:"hp"`
+ Source string `json:"source"`
+ CR string `json:"cr"`
+ Type string `json:"type"`
+ Name string `json:"name"`
+ DamageRes []string `json:"damageResistances"`
+ Traits []Trait `json:"trait"`
+ AC []AC `json:"ac"`
+ Alignment []string `json:"alignment"`
+ Senses []string `json:"senses"`
+ Languages []string `json:"languages"`
+ Size []string `json:"size"`
+ Actions []Action `json:"action"`
+ Speed Speed `json:"speed"`
+ Str int `json:"str"`
+ Dex int `json:"dex"`
+ Con int `json:"con"`
+ Int int `json:"int"`
+ Wis int `json:"wis"`
+ Cha int `json:"cha"`
+}
+
+type AC struct {
+ From []string `json:"from"`
+ AC int `json:"ac"`
+}
+
+type HP struct {
+ Formula string `json:"formula"`
+ Average int `json:"average"`
+}
+
+type Speed struct {
+ Walk int `json:"walk"`
+}
+
+type Save struct {
+ Dex string `json:"dex"`
+ Con string `json:"con"`
+ Wis string `json:"wis"`
+}
+
+type Skill struct {
+ Perception string `json:"perception"`
+ Stealth string `json:"stealth"`
+}
+
+type Trait struct {
+ Name string `json:"name"`
+ Entries []string `json:"entries"`
+}
+
+type Action struct {
+ Name string `json:"name"`
+ Entries []string `json:"entries"`
+}
+
+// Character struct für die Daten des Charakters
+type Character struct {
+ Monster []Monster `json:"monster"`
+ Meta Meta `json:"_meta"`
+}
+
+// Meta struct für Meta-Informationen
+type Meta struct {
+ DateLastModifiedHash string `json:"_dateLastModifiedHash"`
+ Sources []Source `json:"sources"`
+ DateAdded int64 `json:"dateAdded"`
+ DateLastModified int64 `json:"dateLastModified"`
+}
+
+type Source struct {
+ Json string `json:"json"`
+ Abbreviation string `json:"abbreviation"`
+ Version string `json:"version"`
+ Authors []string `json:"authors"`
+ ConvertedBy []string `json:"convertedBy"`
+}
+
+// writeToFile schreibt Daten in eine Datei
+func WriteToFile(filename string, data []byte) error {
+ file, err := os.Create(filename)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ _, err = file.Write(data)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// getOrCreateCharacter gibt das aktuelle Charakterobjekt zurück oder erstellt ein neues
+func GetOrCreateCharacter(filename string, chars []Character) Character {
+ for _, char := range chars {
+ if char.Meta.DateLastModified == 0 {
+ // Ein leeres Charakterobjekt wurde gefunden
+ return char
+ }
+ }
+
+ // Erstelle ein neues Charakterobjekt
+ now := time.Now().Unix()
+ newChar := Character{
+ Meta: Meta{
+ Sources: []Source{
+ {
+ Json: "Malgorgon",
+ Abbreviation: "MG",
+ Authors: []string{"Krzysztof"},
+ ConvertedBy: []string{"Krzysztof"},
+ Version: "unknown",
+ },
+ },
+ DateAdded: now,
+ DateLastModified: now,
+ DateLastModifiedHash: fmt.Sprintf("%x", now),
+ },
+ Monster: []Monster{},
+ }
+
+ chars = append(chars, newChar)
+
+ return newChar
+}
diff --git a/templates/about.html b/templates/about.html
new file mode 100644
index 0000000..cff355b
--- /dev/null
+++ b/templates/about.html
@@ -0,0 +1,2 @@
+{{ define "about" }}
+{{ end }}
diff --git a/templates/base.html b/templates/base.html
index 0fba542..cbfd77f 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -6,7 +6,6 @@
{{.Title}}
-