diff --git a/go.mod b/go.mod index dfe5d47..7db1ebd 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module ddServer go 1.21.4 -require github.com/stretchr/testify v1.8.4 +require ( + github.com/stretchr/testify v1.8.4 + golang.org/x/text v0.14.0 +) require ( github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index fa4b6e6..e228b7b 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/handlers/add_monster_handler.go b/handlers/add_monster_handler.go index 38cb1a1..5174c3a 100644 --- a/handlers/add_monster_handler.go +++ b/handlers/add_monster_handler.go @@ -2,10 +2,14 @@ package handlers import ( "ddServer/model" + "fmt" "log" "net/http" "strconv" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) // AddMonster is a http.HandlerFunc that adds a new monster to the Monsters slice. @@ -94,32 +98,32 @@ func parseMonster(r *http.Request) model.Monster { 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"), - Str: r.FormValue("saveStr"), - Cha: r.FormValue("saveCha"), - Int: r.FormValue("saveInt"), + Dex: checkCheckbox("savedex", r), + Con: checkCheckbox("savecon", r), + Wis: checkCheckbox("savewis", r), + Str: checkCheckbox("savestr", r), + Cha: checkCheckbox("savecha", r), + Int: checkCheckbox("saveint", r), }, Skill: model.Skill{ - Perception: r.FormValue("perception"), - Stealth: r.FormValue("stealth"), - Acrobatics: r.FormValue("acrobatics"), - AnimalHandling: r.FormValue("animalHandling"), - Arcana: r.FormValue("arcana"), - Athletics: r.FormValue("athletics"), - Deception: r.FormValue("deception"), - History: r.FormValue("history"), - Insight: r.FormValue("insight"), - Intimidation: r.FormValue("intimidation"), - Investigation: r.FormValue("investigation"), - Medicine: r.FormValue("medicine"), - Nature: r.FormValue("nature"), - Performance: r.FormValue("performance"), - Persuasion: r.FormValue("persuasion"), - SleightOfHand: r.FormValue("sleightOfHand"), - Survival: r.FormValue("survival"), - Religion: r.FormValue("religion"), + Perception: checkCheckbox("perception", r), + Stealth: checkCheckbox("stealth", r), + Acrobatics: checkCheckbox("acrobatics", r), + AnimalHandling: checkCheckbox("animalhandling", r), + Arcana: checkCheckbox("arcana", r), + Athletics: checkCheckbox("athletics", r), + Deception: checkCheckbox("deception", r), + History: checkCheckbox("history", r), + Insight: checkCheckbox("insight", r), + Intimidation: checkCheckbox("intimidation", r), + Investigation: checkCheckbox("investigation", r), + Medicine: checkCheckbox("medicine", r), + Nature: checkCheckbox("nature", r), + Performance: checkCheckbox("performance", r), + Persuasion: checkCheckbox("persuasion", r), + SleightOfHand: checkCheckbox("sleightofhand", r), + Survival: checkCheckbox("survival", r), + Religion: checkCheckbox("religion", r), }, Resist: []string{r.FormValue("resist")}, ConditionImmune: []string{r.FormValue("conditionImmune")}, @@ -142,3 +146,10 @@ func parseMonster(r *http.Request) model.Monster { }, } } + +func checkCheckbox(field string, r *http.Request) string { + if r.FormValue(fmt.Sprintf("check%v", cases.Caser(cases.Title(language.Und)).String(field))) == "on" { + return r.FormValue(field) + } + return "" +} diff --git a/handlers/load_file_handler.go b/handlers/load_file_handler.go new file mode 100644 index 0000000..cfaaac4 --- /dev/null +++ b/handlers/load_file_handler.go @@ -0,0 +1,46 @@ +package handlers + +import ( + "ddServer/model" + "encoding/json" + "fmt" + "log" + "net/http" +) + +func LoadFileHandler(monsters *[]model.Monster) http.HandlerFunc { + log.Print("LoadFileHandler called") + return func(w http.ResponseWriter, r *http.Request) { + r.ParseMultipartForm(10 << 20) // 10 MB limit + + // Get the file from the request + file, _, err := r.FormFile("uploadFile") + if err != nil { + http.Error(w, "Error retrieving file", http.StatusBadRequest) + return + } + defer file.Close() + + // Parse the file content + decoder := json.NewDecoder(file) + var loadedChars model.Character + err = decoder.Decode(&loadedChars) + if err != nil { + http.Error(w, "Error decoding file content", http.StatusInternalServerError) + return + } + + // Lock the Monsters slice and append the loaded monsters, then unlock the slice + mu.Lock() + defer mu.Unlock() + + // Assuming 'loadedChars' contains an array of Monster objects + for _, monster := range loadedChars.Monster { + *monsters = append(*monsters, monster) + } + + fmt.Printf("%v\n", monsters) + // Send a success response + http.Redirect(w, r, "/monsterTable", http.StatusTemporaryRedirect) + } +} diff --git a/handlers/main_handler.go b/handlers/main_handler.go index f060e3b..19d2cdf 100644 --- a/handlers/main_handler.go +++ b/handlers/main_handler.go @@ -16,7 +16,7 @@ func MainHandler(content embed.FS, monsters *[]model.Monster) http.HandlerFunc { log.Print("MainHandler called") // Parse the templates from the embedded file system - tmpl, err := template.ParseFS(content, "templates/main.html", "templates/monsterForm.html", "templates/monster.html", "templates/monsterTable.html", "templates/base.html") + tmpl, err := template.ParseFS(content, "templates/main.html", "templates/monsterForm.html", "templates/monster.html", "templates/monsterTable.html", "templates/base.html", "templates/skills.html") if err != nil { log.Printf("Template parsing error: %v\n", err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/handlers/skill_calculation_handler.go b/handlers/skill_calculation_handler.go index 48935cf..55ce57b 100644 --- a/handlers/skill_calculation_handler.go +++ b/handlers/skill_calculation_handler.go @@ -8,40 +8,44 @@ import ( "strconv" ) -// SkillCalculationHandler ist ein http.HandlerFunc, der von htmx getriggert wird, -// wenn der Benutzer Einträge in bestimmten Feldern macht, und dann die Skill-Felder befüllt. +// SkillCalculationHandler is an http.HandlerFunc triggered by htmx when the user makes entries in certain fields and then populates the skill fields. func SkillCalculationHandler(content embed.FS) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - log.Print("SkillCalculationHandler called") - - // Überprüfen Sie, ob die Anfrage eine POST-Anfrage ist. + // Check if the request is a POST request. if r.Method != http.MethodPost { - log.Print("Method not allowed") http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } - // Parse Formulardaten. + // Parse form data. err := r.ParseForm() if err != nil { - log.Printf("Error parsing form data: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - tmplFiles := []string{"templates/base.html", "templates/header.html", "templates/skills.html", "templates/main.html", "templates/footer.html", "templates/about.html"} + // Parse template files. + tmplFiles := []string{ + "templates/base.html", + "templates/header.html", + "templates/skills.html", + "templates/main.html", + "templates/footer.html", + "templates/about.html", + } tmpl, err := template.ParseFS(content, tmplFiles...) if err != nil { - log.Printf("Template parsing error: %v\n", err) http.Error(w, err.Error(), http.StatusBadRequest) return } + // Parse form field values and calculate skill values. str := parseFieldValue(r.FormValue("str")) dex := parseFieldValue(r.FormValue("dex")) int := parseFieldValue(r.FormValue("int")) cha := parseFieldValue(r.FormValue("cha")) wis := parseFieldValue(r.FormValue("wis")) + con := parseFieldValue(r.FormValue("con")) cr := parseFieldValue(r.FormValue("cr")) crBonus := calcBonus(cr) @@ -64,79 +68,124 @@ func SkillCalculationHandler(content embed.FS) http.HandlerFunc { "sleightOfHand": strconv.Itoa(calcAbilityScore(dex) + crBonus), "stealth": strconv.Itoa(calcAbilityScore(dex) + crBonus), "survival": strconv.Itoa(calcAbilityScore(wis) + crBonus), + "saveStr": strconv.Itoa(calcAbilityScore(str) + crBonus), + "saveWis": strconv.Itoa(calcAbilityScore(wis) + crBonus), + "saveCon": strconv.Itoa(calcAbilityScore(con) + crBonus), + "saveInt": strconv.Itoa(calcAbilityScore(int) + crBonus), + "saveCha": strconv.Itoa(calcAbilityScore(cha) + crBonus), + "saveDex": strconv.Itoa(calcAbilityScore(dex) + crBonus), } + // Execute template with skill values. err = tmpl.ExecuteTemplate(w, "skills", skillValues) if err != nil { - log.Printf("Template execution error: %v\n", err) http.Error(w, err.Error(), http.StatusBadRequest) } } } +// calcBonus calculates the bonus based on the given credit rating. +// It returns the bonus value as an integer. func calcBonus(cr int) int { - if cr >= 0 && cr < 5 { + switch { + case cr >= 0 && cr < 5: + log.Println("Bonus calculated for credit rating:", cr) return 2 - } else if cr >= 5 && cr < 9 { + case cr >= 5 && cr < 9: + log.Println("Bonus calculated for credit rating:", cr) return 3 - } else if cr >= 9 && cr < 14 { + case cr >= 9 && cr < 14: + log.Println("Bonus calculated for credit rating:", cr) return 4 - } else if cr >= 14 && cr < 18 { + case cr >= 14 && cr < 18: + log.Println("Bonus calculated for credit rating:", cr) return 5 - } else if cr >= 18 && cr < 21 { + case cr >= 18 && cr < 21: + log.Println("Bonus calculated for credit rating:", cr) return 6 - } else if cr >= 21 && cr < 25 { + case cr >= 21 && cr < 25: + log.Println("Bonus calculated for credit rating:", cr) return 7 - } else if cr >= 25 && cr < 28 { + case cr >= 25 && cr < 28: + log.Println("Bonus calculated for credit rating:", cr) return 8 - } else if cr >= 28 && cr < 31 { + case cr >= 28 && cr < 31: + log.Println("Bonus calculated for credit rating:", cr) return 9 - } else { + default: + log.Println("Invalid credit rating:", cr) return 0 } } +// calcAbilityScore calculates the ability score based on the given value. func calcAbilityScore(val int) int { - if val < 2 { + switch { + case val < 2: + log.Println("Ability Score: -5") return -5 - } else if val >= 2 && val < 4 { + case val < 4: + log.Println("Ability Score: -4") return -4 - } else if val >= 4 && val < 6 { + case val < 6: + log.Println("Ability Score: -3") return -3 - } else if val >= 6 && val < 8 { + case val < 8: + log.Println("Ability Score: -2") return -2 - } else if val >= 8 && val < 10 { + case val < 10: + log.Println("Ability Score: -1") return -1 - } else if val >= 10 && val < 12 { + case val < 12: + log.Println("Ability Score: 0") return 0 - } else if val >= 12 && val < 14 { + case val < 14: + log.Println("Ability Score: 1") return 1 - } else if val >= 14 && val < 16 { + case val < 16: + log.Println("Ability Score: 2") return 2 - } else if val >= 16 && val < 18 { + case val < 18: + log.Println("Ability Score: 3") return 3 - } else if val >= 18 && val < 20 { + case val < 20: + log.Println("Ability Score: 4") return 4 - } else if val >= 20 && val < 22 { + case val < 22: + log.Println("Ability Score: 5") return 5 - } else if val >= 22 && val < 24 { + case val < 24: + log.Println("Ability Score: 6") return 6 - } else if val >= 24 && val < 26 { + case val < 26: + log.Println("Ability Score: 7") return 7 - } else if val >= 26 && val < 28 { + case val < 28: + log.Println("Ability Score: 8") return 8 - } else if val >= 28 && val < 30 { + case val < 30: + log.Println("Ability Score: 9") return 9 - } else { + default: + log.Println("Ability Score: 10") return 10 } } +// parseFieldValue takes a string value and returns an integer. +// If the string value cannot be converted to an integer, it logs an error and returns 0. +// The function follows these rules: +// - No line is over 66 characters. func parseFieldValue(value string) int { + // Convert the string value to an integer using strconv.Atoi. + // If an error occurs during the conversion, log the error and return 0. val, err := strconv.Atoi(value) if err != nil { log.Printf("Error converting field value to integer: %v", err) return 0 } + // Log the converted integer value for debugging purposes. + log.Printf("Converted field value to integer: %d", val) + // Return the converted integer value. return val } diff --git a/main.go b/main.go index d163e79..5bbd46f 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,7 @@ func main() { routes.HandleFunc("/contact", handlers.ContactHandler(content)) routes.HandleFunc("/monsterTable", handlers.MonsterTableHandler(content, &Monsters)) routes.HandleFunc("/calculate-skills", handlers.SkillCalculationHandler(content)) + routes.HandleFunc("/loadFile", handlers.LoadFileHandler(&Monsters)) // Print the message indicating that 'static' has been included. log.Printf("Eingebunden is %v\n", static) diff --git a/templates/contact.html b/templates/contact.html index ce0085d..c8481f1 100644 --- a/templates/contact.html +++ b/templates/contact.html @@ -1,57 +1,58 @@ {{ define "contact" }}
-
-
-
-

Contact Us

-
-
+
+
+
+

Contact Us

+
+
-
-

Our Contact Information

-

You can reach us through the following channels:

-
    -
  • Email: example@example.com
  • -
  • Phone: +123456789
  • -
+
+

Our Contact Information

+

You can reach us through the following channels:

+
    +
  • Email: example@example.com
  • +
  • Phone: +123456789
  • +
+
+ +
+

Contact Form

+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+
+
+
- -
-

Contact Form

-
-
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
- -
-
-
-
-
-
{{ end }} diff --git a/templates/footer.html b/templates/footer.html index cf8d261..9b0881a 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -6,4 +6,4 @@

-{{ end }} +{{ end }} \ No newline at end of file diff --git a/templates/header.html b/templates/header.html index 0efea19..46c13ec 100644 --- a/templates/header.html +++ b/templates/header.html @@ -78,4 +78,4 @@ }); -{{ end }} +{{ end }} \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index ed4581f..359f1a9 100644 --- a/templates/main.html +++ b/templates/main.html @@ -1,109 +1,131 @@ {{ define "main" }}
-
-
-
-

Monster Form

+
+
+
+

Monster Form

+
+
+
+
+ +
+
+
+
-
- -
- -
-
-
-
-
- -
-
- {{ template "monsterform" . }} - - - +
+ +
+
+ +
-
+
+ {{ template "monsterform" . }} +
+
+ +
+
+ + + +
+
-
-
-
-

Existing Monsters

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{ template "monsterTable" }} -
NameSourceSizeTypeAlignmentACAC FormHP AverageHP FormulaWalkSwimBurrowClimbFlyStrDexConIntWisChaSave DexSave ConSave WisSave StrSave ConSave ChaPerceptionStealthAcrobaticsAnimalHandlingArcanaAthleticsDeceptionHistoryInsightIntimidationInvestigationMedicineNaturePerformancePersuasionSleightOfHandSurvivalReligionDamage ResistanceDamage ImmuneVulnerableCondition ImmuneSensesLanguagesCRTrait NameTrait EntryAction NameAction Entry
-
-
+
+
+
+

Existing Monsters

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ template "monsterTable" }} +
NameSourceSizeTypeAlignmentACAC FormHP AverageHP FormulaWalkSwimBurrowClimbFlyStrDexConIntWisChaSave DexSave ConSave WisSave StrSave IntSave ChaPerceptionStealthAcrobaticsAnimalHandlingArcanaAthleticsDeceptionHistoryInsightIntimidationInvestigationMedicineNaturePerformancePersuasionSleightOfHandSurvivalReligionDamage ResistanceDamage ImmuneVulnerableCondition ImmuneSensesLanguagesCRTrait NameTrait EntryAction NameAction Entry
+
+
-{{ end }} +{{ end }} \ No newline at end of file diff --git a/templates/monster.html b/templates/monster.html index d3a59d6..0053cea 100644 --- a/templates/monster.html +++ b/templates/monster.html @@ -24,7 +24,7 @@ {{.Save.Con}} {{.Save.Wis}} {{.Save.Str}} - {{.Save.Con}} + {{.Save.Int}} {{.Save.Cha}} {{.Skill.Perception}} {{.Skill.Stealth}} @@ -56,4 +56,4 @@ {{range .Actions}}{{.Name}}{{end}} {{range .Actions}}{{range .Entries}}{{.}}{{end}}{{end}} -{{ end }} +{{ end }} \ No newline at end of file diff --git a/templates/monsterForm.html b/templates/monsterForm.html index ca69873..5903e0d 100644 --- a/templates/monsterForm.html +++ b/templates/monsterForm.html @@ -87,61 +87,6 @@
-
-
-

- Speed -

-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
@@ -209,20 +154,14 @@
-
-
- -
- -
-
-
+ +
+ {{ template "skills" }}

- Save + Speed

@@ -230,61 +169,50 @@
- +
- +
- +
- +
- +
- +
-
-
-
-
- -
- +
+
+
+ +
+ +
-
-
-
- -
- -
-
-
-
-
- -
- +
+
+ +
+ +
-
- {{ template "skills" }} -
@@ -375,4 +303,4 @@
-{{end}} +{{end}} \ No newline at end of file diff --git a/templates/monsterTable.html b/templates/monsterTable.html index d5aef50..9eb1b75 100644 --- a/templates/monsterTable.html +++ b/templates/monsterTable.html @@ -4,4 +4,4 @@ {{ template "monster" . }} {{ end }} -{{ end }} +{{ end }} \ No newline at end of file diff --git a/templates/skills.html b/templates/skills.html index 9322260..acd9da9 100644 --- a/templates/skills.html +++ b/templates/skills.html @@ -1,185 +1,265 @@ {{ define "skills" }} -
-

- Skill -

-
-
-
-
-
-
- -
- +
+
+
+

+ Save +

+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
-
-
- -
- +
+
+
+ +
+ +
-
-
-
- -
- +
+
+ +
+ +
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- +
+
+ +
+ +
-{{ end }} +
+
+
+

+ Skill +

+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+{{ end }} \ No newline at end of file