Compare commits

...

41 Commits

Author SHA1 Message Date
b36e0ea503 Merge branch 'devel' 2024-10-04 16:06:57 +02:00
863581f590 Show error messages in UI if something goes wrong 2024-10-04 16:06:33 +02:00
aec829ad85 Fixed a bug that returned the wrong filename for an uploaded image 2024-10-04 12:10:12 +02:00
298ea458ca Fixed login bug 2024-10-04 11:51:24 +02:00
533053aef0 Fixed a bug that prevented {{.Action}} from being acessible in editor.html 2024-10-04 11:50:51 +02:00
bc4d8fa37e Merge branch 'devel' 2024-09-28 13:59:34 +02:00
d2b21e7405 Merge branch 'devel' 2024-09-28 12:36:46 +02:00
e3c192359f Merge branch 'devel' 2024-09-11 18:15:31 +02:00
46532e4c85 Merge branch 'devel' 2024-09-11 18:15:07 +02:00
c722135a56 Merge branch 'devel' 2024-09-11 17:18:42 +02:00
887fa863bc Merge branch 'devel' 2024-09-10 19:43:22 +02:00
74d71cfb6a Merge branch 'devel' 2024-09-09 22:03:43 +02:00
ca7e7cddd3 Merge branch 'devel' 2024-09-08 16:22:59 +02:00
94431a2aa9 Merge branch 'devel' 2024-09-08 16:21:38 +02:00
5b1f20c5bc Merge branch 'devel' 2024-09-08 13:36:22 +02:00
d0c566f8df Merge branch 'devel' 2024-09-01 21:14:05 +02:00
5e586aa49a Merge branch 'devel' 2024-09-01 18:51:33 +02:00
66b2743d3d Merge branch 'devel' 2024-09-01 18:48:26 +02:00
3723b2b5e6 Merge branch 'devel' 2024-09-01 18:18:18 +02:00
ce788bfd50 Merge branch 'devel' 2024-09-01 12:54:12 +02:00
230a6278cc Merge branch 'devel' 2024-09-01 12:49:30 +02:00
42d6e0c198 Merge branch 'devel' 2024-08-31 12:17:41 +02:00
e1af2979af Merge branch 'devel' 2024-08-31 11:27:15 +02:00
f6dedc6f10 Merge branch 'devel' 2024-08-31 01:43:53 +02:00
cdf0a49550 Merge branch 'devel' 2024-08-31 01:38:28 +02:00
c3c0650210 Merge branch 'devel' 2024-08-31 01:00:55 +02:00
d077f700d8 Merge branch 'devel' 2024-08-31 00:36:48 +02:00
ec752b1c66 Merge branch 'devel' 2024-08-30 23:43:12 +02:00
46aef4f12f Merge branch 'devel' 2024-08-25 10:51:35 +02:00
1b29e328cf Merge branch 'devel' 2024-08-25 06:38:55 +02:00
e50cb819f3 Merge branch 'devel' 2024-08-23 21:45:30 +02:00
c32e38ca10 Merge branch 'devel' 2024-08-23 20:57:11 +02:00
d7c8c7a43a Merge branch 'devel' 2024-08-18 17:31:00 +02:00
1cd3edc90c Merge branch 'devel' 2024-08-18 12:06:29 +02:00
0e768c9f61 Merge branch 'devel' 2024-08-08 21:27:07 +02:00
1fcd775cc5 Merge branch 'devel' 2024-08-08 21:14:24 +02:00
203a1ed147 Implemented EasyMDE 2024-08-08 21:13:25 +02:00
ef1914ee5c Implemented article preview 2024-08-08 21:13:25 +02:00
084b101e31 Register f.ArticlePreviewHtmlData in init() 2024-08-08 21:13:25 +02:00
b2db128aa9 Shorten lines by referencing frontend as f and backend as b 2024-08-08 21:13:25 +02:00
081e880fb6 Change structure of code tor frontend and backend one 2024-08-08 21:13:25 +02:00
12 changed files with 216 additions and 277 deletions

View File

@ -2,6 +2,7 @@ package backend
import ( import (
"fmt" "fmt"
"image"
"io" "io"
"os" "os"
@ -10,9 +11,14 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
var ErrUnsupportedFormat error = image.ErrFormat // used internally by imaging
func SaveImage(c *Config, src io.Reader) (string, error) { func SaveImage(c *Config, src io.Reader) (string, error) {
img, err := imaging.Decode(src, imaging.AutoOrientation(true)) img, err := imaging.Decode(src, imaging.AutoOrientation(true))
if err != nil { if err != nil {
if err == ErrUnsupportedFormat {
return "", ErrUnsupportedFormat
}
return "", fmt.Errorf("error decoding image: %v", err) return "", fmt.Errorf("error decoding image: %v", err)
} }
@ -23,8 +29,8 @@ func SaveImage(c *Config, src io.Reader) (string, error) {
img = imaging.Resize(img, c.MaxImgWidth, 0, imaging.Lanczos) img = imaging.Resize(img, c.MaxImgWidth, 0, imaging.Lanczos)
} }
filename := fmt.Sprint(c.PicsDir, "/", uuid.New(), ".webp") filename := fmt.Sprint(uuid.New(), ".webp")
file, err := os.Create(filename) file, err := os.Create(c.PicsDir + "/" + filename)
if err != nil { if err != nil {
return "", fmt.Errorf("error creating new image file: %v", err) return "", fmt.Errorf("error creating new image file: %v", err)
} }

View File

@ -47,7 +47,7 @@ func (db *DB) AddUser(u *User, pass string) (int64, error) {
return id, nil return id, nil
} }
func (db *DB) GetID(userName string) (int64, bool) { func (db *DB) GetID(userName string) int64 {
var id int64 var id int64
query := ` query := `
@ -56,11 +56,11 @@ func (db *DB) GetID(userName string) (int64, bool) {
WHERE username = ? WHERE username = ?
` `
row := db.QueryRow(query, userName) row := db.QueryRow(query, userName)
if err := row.Scan(&id); err != nil { if err := row.Scan(&id); err != nil { // seems like the only possible error is ErrNoRows
return 0, false return 0
} }
return id, true return id
} }
func (db *DB) CheckPassword(id int64, pass string) error { func (db *DB) CheckPassword(id int64, pass string) error {
@ -146,7 +146,7 @@ func (db *DB) GetUser(id int64) (*User, error) {
return user, nil return user, nil
} }
func (db *DB) UpdateOwnAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error { func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error {
passwordEmpty := true passwordEmpty := true
if len(newPass) > 0 || len(newPass2) > 0 { if len(newPass) > 0 || len(newPass2) > 0 {
if newPass != newPass2 { if newPass != newPass2 {
@ -228,7 +228,7 @@ func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
if err = tx.Commit(); err != nil { if err = tx.Commit(); err != nil {
return 0, fmt.Errorf("error committing transaction: %v", err) return 0, fmt.Errorf("error committing transaction: %v", err)
} }
return 2, nil return -1, nil
} }
hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost) hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)

View File

@ -38,10 +38,9 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
data := &EditorHTMLData{Action: "submit"} var data *EditorHTMLData
if session.Values["article"] == nil { if session.Values["article"] == nil {
data = &EditorHTMLData{Article: new(b.Article)} data = &EditorHTMLData{Action: "submit", Article: new(b.Article)}
} else { } else {
data = session.Values["article"].(*EditorHTMLData) data = session.Values["article"].(*EditorHTMLData)
} }
@ -88,6 +87,15 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
AutoGenerated: false, AutoGenerated: false,
} }
if len(article.Title) == 0 {
http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
return
}
if len(article.Description) == 0 {
http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest)
return
}
article.ID, err = db.AddArticle(article) article.ID, err = db.AddArticle(article)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
@ -95,8 +103,14 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
content := []byte(r.PostFormValue("article-content"))
if len(content) == 0 {
http.Error(w, "Bitte den Artikel eingeben.", http.StatusBadRequest)
return
}
articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md")
if err = os.WriteFile(articleAbsName, []byte(r.PostFormValue("article-content")), 0644); err != nil { if err = os.WriteFile(articleAbsName, content, 0644); err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -153,8 +167,22 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
} }
title := r.PostFormValue("article-title") title := r.PostFormValue("article-title")
if len(title) == 0 {
http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
return
}
description := r.PostFormValue("article-description") description := r.PostFormValue("article-description")
if len(description) == 0 {
http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest)
return
}
content := r.PostFormValue("article-content") content := r.PostFormValue("article-content")
if len(content) == 0 {
http.Error(w, "Bitte den Artikel eingeben.", http.StatusBadRequest)
return
}
link := fmt.Sprint(c.ArticleDir, "/", id, ".md") link := fmt.Sprint(c.ArticleDir, "/", id, ".md")
if err = os.WriteFile(link, []byte(content), 0644); err != nil { if err = os.WriteFile(link, []byte(content), 0644); err != nil {
@ -510,6 +538,10 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
filename, err := b.SaveImage(c, file) filename, err := b.SaveImage(c, file)
if err != nil { if err != nil {
if err == b.ErrUnsupportedFormat {
http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
return
}
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View File

@ -31,21 +31,18 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
title := r.PostFormValue("issue-title") title := r.PostFormValue("issue-title")
if len(title) == 0 { if len(title) == 0 {
err = fmt.Errorf("error: no title for issue specified") http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
if session.Values["issue-image"] == nil { if session.Values["issue-image"] == nil {
err := "error: Image required" http.Error(w, "Bitte ein Bild einfügen.", http.StatusBadRequest)
log.Println(err)
http.Error(w, err, http.StatusBadRequest)
return return
} }
imgFileName := session.Values["issue-image"].(string) imgFileName := session.Values["issue-image"].(string)
imgAbsName := fmt.Sprint(c.PicsDir, "/", imgFileName) fmt.Println(imgFileName)
imgAbsName := c.PicsDir + "/" + imgFileName
imgFile, err := os.Open(imgAbsName) imgFile, err := os.Open(imgAbsName)
if err != nil { if err != nil {
@ -81,8 +78,14 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
return return
} }
content := []byte(r.PostFormValue("issue-content"))
if len(content) == 0 {
http.Error(w, "Bitte eine Beschreibung eingeben.", http.StatusBadRequest)
return
}
articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md")
if err = os.WriteFile(articleAbsName, []byte(r.PostFormValue("article-content")), 0644); err != nil { if err = os.WriteFile(articleAbsName, content, 0644); err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -167,6 +170,10 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
filename, err := b.SaveImage(c, file) filename, err := b.SaveImage(c, file)
if err != nil { if err != nil {
if err == b.ErrUnsupportedFormat {
http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
return
}
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View File

@ -34,6 +34,24 @@ func UploadPDF(c *b.Config, s *b.CookieStore) http.HandlerFunc {
} }
defer file.Close() defer file.Close()
buffer := make([]byte, 512) // Should be enough for mime type
if _, err := file.Read(buffer); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if _, err := file.Seek(0, 0); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if http.DetectContentType(buffer) != "application/pdf" {
http.Error(w, "Die Datei ist kein PDF.", http.StatusInternalServerError)
return
}
filename := fmt.Sprint(uuid.New(), ".pdf") filename := fmt.Sprint(uuid.New(), ".pdf")
absFilepath, err := filepath.Abs(fmt.Sprint(c.PDFDir, "/", filename)) absFilepath, err := filepath.Abs(fmt.Sprint(c.PDFDir, "/", filename))
if err != nil { if err != nil {

View File

@ -67,7 +67,7 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
} else { } else {
session, err := getSession(w, r, c, s) session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -99,8 +99,8 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
userName := r.PostFormValue("username") userName := r.PostFormValue("username")
password := r.PostFormValue("password") password := r.PostFormValue("password")
id, ok := db.GetID(userName) id := db.GetID(userName)
if !ok { if id == 0 {
http.Error(w, fmt.Sprintf("no such user: %v", userName), http.StatusBadRequest) http.Error(w, fmt.Sprintf("no such user: %v", userName), http.StatusBadRequest)
return return
} }

View File

@ -34,7 +34,12 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
db.AddTag(r.PostFormValue("tag")) tag := r.PostFormValue("tag")
if len(tag) == 0 {
http.Error(w, "Bitte einen Tag eingeben.", http.StatusBadRequest)
return
}
db.AddTag(tag)
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)

View File

@ -10,11 +10,6 @@ import (
b "streifling.com/jason/cpolis/cmd/backend" b "streifling.com/jason/cpolis/cmd/backend"
) )
type UserData struct {
*b.User
Msg string
}
func checkUserStrings(user *b.User) (string, int, bool) { func checkUserStrings(user *b.User) (string, int, bool) {
userLen := 15 userLen := 15
nameLen := 50 nameLen := 50
@ -56,71 +51,50 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
role, err := strconv.Atoi(r.PostFormValue("role")) user := &b.User{
UserName: r.PostFormValue("username"),
FirstName: r.PostFormValue("first-name"),
LastName: r.PostFormValue("last-name"),
}
pass := r.PostFormValue("password")
pass2 := r.PostFormValue("password2")
if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
return
}
userString, stringLen, ok := checkUserStrings(user)
if !ok {
http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
return
}
if id := db.GetID(user.UserName); id != 0 {
http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest)
return
}
if pass != pass2 {
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
return
}
roleString := r.PostFormValue("role")
if len(roleString) == 0 {
http.Error(w, "Bitte eine Aufgabe vergeben.", http.StatusBadRequest)
return
}
user.Role, err = strconv.Atoi(roleString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
htmlData := UserData{ _, err = db.AddUser(user, pass)
User: &b.User{
UserName: r.PostFormValue("username"),
FirstName: r.PostFormValue("first-name"),
LastName: r.PostFormValue("last-name"),
Role: role,
},
}
pass := r.PostFormValue("password")
pass2 := r.PostFormValue("password2")
if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 ||
len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
htmlData.Msg = "Alle Felder müssen ausgefüllt werden."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
userString, stringLen, ok := checkUserStrings(htmlData.User)
if !ok {
htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
id, _ := db.GetID(htmlData.UserName)
if id != 0 {
htmlData.Msg = fmt.Sprint(htmlData.UserName,
" ist bereits vergeben. Bitte anderen Benutzernamen wählen.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
if pass != pass2 {
htmlData.Msg = "Die Passwörter stimmen nicht überein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
_, err = db.AddUser(htmlData.User, pass)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -171,76 +145,43 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
userData := UserData{ user := &b.User{
User: &b.User{
ID: session.Values["id"].(int64), ID: session.Values["id"].(int64),
UserName: r.PostFormValue("username"), UserName: r.PostFormValue("username"),
FirstName: r.PostFormValue("first-name"), FirstName: r.PostFormValue("first-name"),
LastName: r.PostFormValue("last-name"), LastName: r.PostFormValue("last-name"),
},
} }
oldPass := r.PostFormValue("old-password") oldPass := r.PostFormValue("old-password")
newPass := r.PostFormValue("password") newPass := r.PostFormValue("password")
newPass2 := r.PostFormValue("password2") newPass2 := r.PostFormValue("password2")
if len(userData.UserName) == 0 || len(userData.FirstName) == 0 || if len(user.UserName) == 0 {
len(userData.LastName) == 0 { http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
userData.Msg = "Alle Felder mit * müssen ausgefüllt sein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return return
} }
userString, stringLen, ok := checkUserStrings(userData.User) if len(user.FirstName) == 0 || len(user.LastName) == 0 {
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusBadRequest)
return
}
userString, stringLen, ok := checkUserStrings(user)
if !ok { if !ok {
userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return return
} }
if id, ok := db.GetID(userData.UserName); ok { if id := db.GetID(user.UserName); id != 0 && id != user.ID {
if id != userData.ID { http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest)
userData.Msg = "Benutzername bereits vergeben."
userData.UserName = ""
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
return
}
}
if err = db.UpdateOwnAttributes( if err = db.UpdateOwnUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, oldPass, newPass, newPass2); err != nil {
userData.ID, log.Println("error: user:", user.ID, err)
userData.UserName, http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
userData.FirstName,
userData.LastName,
oldPass,
newPass,
newPass2); err != nil {
userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
@ -255,77 +196,44 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var err error var err error
htmlData := UserData{ user := &b.User{
User: &b.User{
UserName: r.PostFormValue("username"), UserName: r.PostFormValue("username"),
FirstName: r.PostFormValue("first-name"), FirstName: r.PostFormValue("first-name"),
LastName: r.PostFormValue("last-name"), LastName: r.PostFormValue("last-name"),
Role: b.Admin, Role: b.Admin,
},
} }
pass := r.PostFormValue("password") pass := r.PostFormValue("password")
pass2 := r.PostFormValue("password2") pass2 := r.PostFormValue("password2")
if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 || if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
htmlData.Msg = "Alle Felder müssen ausgefüllt werden." http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
userString, stringLen, ok := checkUserStrings(htmlData.User)
if !ok {
htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
id, _ := db.GetID(htmlData.UserName)
if id != 0 {
htmlData.Msg = fmt.Sprint(htmlData.UserName,
" ist bereits vergeben. Bitte anderen Benutzernamen wählen.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
if pass != pass2 {
htmlData.Msg = "Die Passwörter stimmen nicht überein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return return
} }
htmlData.ID, err = db.AddFirstUser(htmlData.User, pass) userString, stringLen, ok := checkUserStrings(user)
if !ok {
http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
return
}
if pass != pass2 {
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
return
}
user.ID, err = db.AddFirstUser(user, pass)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
if htmlData.ID > 1 { if user.ID == -1 {
errString := "error: there is already a first user" http.Error(w, "Bitte ein Benutzerkonto von einem Administrator anlegen lassen.", http.StatusInternalServerError)
log.Println(errString)
http.Error(w, errString, http.StatusInternalServerError)
return return
} }
if err := saveSession(w, r, s, htmlData.User); err != nil { if err := saveSession(w, r, s, user); err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -418,93 +326,55 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
return return
} }
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) user := new(b.User)
user.ID, err = strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
role, err := strconv.Atoi(r.PostFormValue("role")) user.Role, err = strconv.Atoi(r.PostFormValue("role"))
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
userData := UserData{ user.UserName = r.PostFormValue("username")
User: &b.User{ if len(user.UserName) == 0 {
ID: id, http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusInternalServerError)
UserName: r.PostFormValue("username"), return
FirstName: r.PostFormValue("first-name"),
LastName: r.PostFormValue("last-name"),
Role: role,
},
} }
user.FirstName = r.PostFormValue("first-name")
user.LastName = r.PostFormValue("last-name")
if len(user.FirstName) == 0 || len(user.LastName) == 0 {
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusInternalServerError)
return
}
newPass := r.PostFormValue("password") newPass := r.PostFormValue("password")
newPass2 := r.PostFormValue("password2") newPass2 := r.PostFormValue("password2")
if len(userData.UserName) == 0 || len(userData.FirstName) == 0 || userString, stringLen, ok := checkUserStrings(user)
len(userData.LastName) == 0 {
userData.Msg = "Alle Felder mit * müssen ausgefüllt sein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
userString, stringLen, ok := checkUserStrings(userData.User)
if !ok { if !ok {
userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return return
} }
if id, ok := db.GetID(userData.UserName); ok { if id := db.GetID(user.UserName); id != 0 && id != user.ID {
if id != userData.ID { http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest)
userData.Msg = "Benutzername bereits vergeben."
userData.UserName = ""
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
return
}
}
if err = db.UpdateUserAttributes( if err = db.UpdateUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, newPass, newPass2, user.Role); err != nil {
userData.ID, log.Println("error: user:", user.ID, err)
userData.UserName, http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
userData.FirstName,
userData.LastName,
newPass,
newPass2,
userData.Role); err != nil {
userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html")
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
tmpl = template.Must(tmpl, err)
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

View File

@ -49,11 +49,4 @@
<button class="btn" hx-get="/hub" hx-target="#page-content">Abbrechen</button> <button class="btn" hx-get="/hub" hx-target="#page-content">Abbrechen</button>
</div> </div>
</form> </form>
<script>
var msg = "{{.Msg}}";
if (msg != "") {
alert(msg);
}
</script>
{{end}} {{end}}

View File

@ -64,6 +64,7 @@
onSuccess(data); onSuccess(data);
}) })
.catch(error => { .catch(error => {
htmx.trigger(htmx.find('#notification'), 'htmx:responseError', {xhr: {responseText: error.message}});
onError(error); onError(error);
}); });
}, },

View File

@ -29,11 +29,4 @@
<input class="action-btn" type="submit" value="Anlegen" hx-post="/user/add-first" hx-target="#page-content" /> <input class="action-btn" type="submit" value="Anlegen" hx-post="/user/add-first" hx-target="#page-content" />
</div> </div>
</form> </form>
<script>
var msg = "{{.Msg}}";
if (msg != "") {
alert(msg);
}
</script>
{{end}} {{end}}

View File

@ -28,6 +28,10 @@
</header> </header>
<main class="mx-4"> <main class="mx-4">
<div class="hidden bg-slate-950 dark:bg-slate-50 fixed font-bold p-4 right-8 rounded-lg shadow-lg text-slate-100 dark:text-slate-900 top-8 z-50"
id="notification">
</div>
<div id="page-content"> <div id="page-content">
{{template "page-content" .}} {{template "page-content" .}}
</div> </div>
@ -35,7 +39,7 @@
<footer class="text-center text-gray-500 my-8"> <footer class="text-center text-gray-500 my-8">
<p>&copy; 2024 Jason Streifling. Alle Rechte vorbehalten.</p> <p>&copy; 2024 Jason Streifling. Alle Rechte vorbehalten.</p>
<p>v0.11.1 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p> <p>v0.12.0 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p>
</footer> </footer>
<script src="https://unpkg.com/htmx.org@2.0.2"></script> <script src="https://unpkg.com/htmx.org@2.0.2"></script>
@ -66,6 +70,16 @@
}); });
}); });
</script> </script>
<script>
htmx.on('htmx:responseError', function (event) {
var notification = document.getElementById('notification');
notification.innerText = event.detail.xhr.responseText;
notification.classList.remove('hidden');
setTimeout(function () {
notification.classList.add('hidden');
}, 5000);
});
</script>
</body> </body>
</html> </html>