forked from jason/cpolis
		
	Show error messages in UI if something goes wrong
This commit is contained in:
		@@ -2,6 +2,7 @@ package backend
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"image"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
@@ -10,9 +11,14 @@ import (
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var ErrUnsupportedFormat error = image.ErrFormat // used internally by imaging
 | 
			
		||||
 | 
			
		||||
func SaveImage(c *Config, src io.Reader) (string, error) {
 | 
			
		||||
	img, err := imaging.Decode(src, imaging.AutoOrientation(true))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == ErrUnsupportedFormat {
 | 
			
		||||
			return "", ErrUnsupportedFormat
 | 
			
		||||
		}
 | 
			
		||||
		return "", fmt.Errorf("error decoding image: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func (db *DB) AddUser(u *User, pass string) (int64, error) {
 | 
			
		||||
	return id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *DB) GetID(userName string) (int64, bool) {
 | 
			
		||||
func (db *DB) GetID(userName string) int64 {
 | 
			
		||||
	var id int64
 | 
			
		||||
 | 
			
		||||
	query := `
 | 
			
		||||
@@ -56,11 +56,11 @@ func (db *DB) GetID(userName string) (int64, bool) {
 | 
			
		||||
    WHERE username = ?
 | 
			
		||||
    `
 | 
			
		||||
	row := db.QueryRow(query, userName)
 | 
			
		||||
	if err := row.Scan(&id); err != nil {
 | 
			
		||||
		return 0, false
 | 
			
		||||
	if err := row.Scan(&id); err != nil { // seems like the only possible error is ErrNoRows
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return id, true
 | 
			
		||||
	return id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *DB) CheckPassword(id int64, pass string) error {
 | 
			
		||||
@@ -146,7 +146,7 @@ func (db *DB) GetUser(id int64) (*User, error) {
 | 
			
		||||
	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
 | 
			
		||||
	if len(newPass) > 0 || len(newPass2) > 0 {
 | 
			
		||||
		if newPass != newPass2 {
 | 
			
		||||
@@ -228,7 +228,7 @@ func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
 | 
			
		||||
				if err = tx.Commit(); err != nil {
 | 
			
		||||
					return 0, fmt.Errorf("error committing transaction: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
				return 2, nil
 | 
			
		||||
				return -1, nil
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,15 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
@@ -94,8 +103,14 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			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")
 | 
			
		||||
		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)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
@@ -152,8 +167,22 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		title := r.PostFormValue("article-title")
 | 
			
		||||
		if len(title) == 0 {
 | 
			
		||||
			http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		description := r.PostFormValue("article-description")
 | 
			
		||||
		if len(description) == 0 {
 | 
			
		||||
			http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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")
 | 
			
		||||
		if err = os.WriteFile(link, []byte(content), 0644); err != nil {
 | 
			
		||||
@@ -509,6 +538,10 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
 | 
			
		||||
		filename, err := b.SaveImage(c, file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == b.ErrUnsupportedFormat {
 | 
			
		||||
				http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -31,21 +31,18 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
 | 
			
		||||
 | 
			
		||||
		title := r.PostFormValue("issue-title")
 | 
			
		||||
		if len(title) == 0 {
 | 
			
		||||
			err = fmt.Errorf("error: no title for issue specified")
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if session.Values["issue-image"] == nil {
 | 
			
		||||
			err := "error: Image required"
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err, http.StatusBadRequest)
 | 
			
		||||
			http.Error(w, "Bitte ein Bild einfügen.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imgFileName := session.Values["issue-image"].(string)
 | 
			
		||||
		imgAbsName := fmt.Sprint(c.PicsDir, "/", imgFileName)
 | 
			
		||||
		fmt.Println(imgFileName)
 | 
			
		||||
		imgAbsName := c.PicsDir + "/" + imgFileName
 | 
			
		||||
 | 
			
		||||
		imgFile, err := os.Open(imgAbsName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -81,8 +78,14 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
 | 
			
		||||
			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")
 | 
			
		||||
		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)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
@@ -167,6 +170,10 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
 | 
			
		||||
		filename, err := b.SaveImage(c, file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == b.ErrUnsupportedFormat {
 | 
			
		||||
				http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,24 @@ func UploadPDF(c *b.Config, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
		}
 | 
			
		||||
		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")
 | 
			
		||||
		absFilepath, err := filepath.Abs(fmt.Sprint(c.PDFDir, "/", filename))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -99,8 +99,8 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
		userName := r.PostFormValue("username")
 | 
			
		||||
		password := r.PostFormValue("password")
 | 
			
		||||
 | 
			
		||||
		id, ok := db.GetID(userName)
 | 
			
		||||
		if !ok {
 | 
			
		||||
		id := db.GetID(userName)
 | 
			
		||||
		if id == 0 {
 | 
			
		||||
			http.Error(w, fmt.Sprintf("no such user: %v", userName), http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,12 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			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 = template.Must(tmpl, err)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,6 @@ import (
 | 
			
		||||
	b "streifling.com/jason/cpolis/cmd/backend"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserData struct {
 | 
			
		||||
	*b.User
 | 
			
		||||
	Msg string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkUserStrings(user *b.User) (string, int, bool) {
 | 
			
		||||
	userLen := 15
 | 
			
		||||
	nameLen := 50
 | 
			
		||||
@@ -56,71 +51,50 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			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 {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		htmlData := UserData{
 | 
			
		||||
			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)
 | 
			
		||||
		_, err = db.AddUser(user, pass)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
@@ -171,75 +145,42 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		userData := UserData{
 | 
			
		||||
			User: &b.User{
 | 
			
		||||
				ID:        session.Values["id"].(int64),
 | 
			
		||||
				UserName:  r.PostFormValue("username"),
 | 
			
		||||
				FirstName: r.PostFormValue("first-name"),
 | 
			
		||||
				LastName:  r.PostFormValue("last-name"),
 | 
			
		||||
			},
 | 
			
		||||
		user := &b.User{
 | 
			
		||||
			ID:        session.Values["id"].(int64),
 | 
			
		||||
			UserName:  r.PostFormValue("username"),
 | 
			
		||||
			FirstName: r.PostFormValue("first-name"),
 | 
			
		||||
			LastName:  r.PostFormValue("last-name"),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		oldPass := r.PostFormValue("old-password")
 | 
			
		||||
		newPass := r.PostFormValue("password")
 | 
			
		||||
		newPass2 := r.PostFormValue("password2")
 | 
			
		||||
 | 
			
		||||
		if len(userData.UserName) == 0 || len(userData.FirstName) == 0 ||
 | 
			
		||||
			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
 | 
			
		||||
			}
 | 
			
		||||
		if len(user.UserName) == 0 {
 | 
			
		||||
			http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
 | 
			
		||||
			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 {
 | 
			
		||||
			userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
			http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if id, ok := db.GetID(userData.UserName); ok {
 | 
			
		||||
			if id != userData.ID {
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
		if id := db.GetID(user.UserName); id != 0 && id != user.ID {
 | 
			
		||||
			http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = db.UpdateOwnAttributes(
 | 
			
		||||
			userData.ID,
 | 
			
		||||
			userData.UserName,
 | 
			
		||||
			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
 | 
			
		||||
			}
 | 
			
		||||
		if err = db.UpdateOwnUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, oldPass, newPass, newPass2); err != nil {
 | 
			
		||||
			log.Println("error: user:", user.ID, err)
 | 
			
		||||
			http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
 | 
			
		||||
@@ -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 {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		var err error
 | 
			
		||||
		htmlData := UserData{
 | 
			
		||||
			User: &b.User{
 | 
			
		||||
				UserName:  r.PostFormValue("username"),
 | 
			
		||||
				FirstName: r.PostFormValue("first-name"),
 | 
			
		||||
				LastName:  r.PostFormValue("last-name"),
 | 
			
		||||
				Role:      b.Admin,
 | 
			
		||||
			},
 | 
			
		||||
		user := &b.User{
 | 
			
		||||
			UserName:  r.PostFormValue("username"),
 | 
			
		||||
			FirstName: r.PostFormValue("first-name"),
 | 
			
		||||
			LastName:  r.PostFormValue("last-name"),
 | 
			
		||||
			Role:      b.Admin,
 | 
			
		||||
		}
 | 
			
		||||
		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
 | 
			
		||||
			}
 | 
			
		||||
		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
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if htmlData.ID > 1 {
 | 
			
		||||
			errString := "error: there is already a first user"
 | 
			
		||||
			log.Println(errString)
 | 
			
		||||
			http.Error(w, errString, http.StatusInternalServerError)
 | 
			
		||||
		if user.ID == -1 {
 | 
			
		||||
			http.Error(w, "Bitte ein Benutzerkonto von einem Administrator anlegen lassen.", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := saveSession(w, r, s, htmlData.User); err != nil {
 | 
			
		||||
		if err := saveSession(w, r, s, user); err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
@@ -418,93 +326,55 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
 | 
			
		||||
			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 {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		role, err := strconv.Atoi(r.PostFormValue("role"))
 | 
			
		||||
		user.Role, err = strconv.Atoi(r.PostFormValue("role"))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		userData := UserData{
 | 
			
		||||
			User: &b.User{
 | 
			
		||||
				ID:        id,
 | 
			
		||||
				UserName:  r.PostFormValue("username"),
 | 
			
		||||
				FirstName: r.PostFormValue("first-name"),
 | 
			
		||||
				LastName:  r.PostFormValue("last-name"),
 | 
			
		||||
				Role:      role,
 | 
			
		||||
			},
 | 
			
		||||
		user.UserName = r.PostFormValue("username")
 | 
			
		||||
		if len(user.UserName) == 0 {
 | 
			
		||||
			http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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")
 | 
			
		||||
		newPass2 := r.PostFormValue("password2")
 | 
			
		||||
 | 
			
		||||
		if len(userData.UserName) == 0 || len(userData.FirstName) == 0 ||
 | 
			
		||||
			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)
 | 
			
		||||
		userString, stringLen, ok := checkUserStrings(user)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
			http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if id, ok := db.GetID(userData.UserName); ok {
 | 
			
		||||
			if id != userData.ID {
 | 
			
		||||
				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
 | 
			
		||||
			}
 | 
			
		||||
		if id := db.GetID(user.UserName); id != 0 && id != user.ID {
 | 
			
		||||
			http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = db.UpdateUserAttributes(
 | 
			
		||||
			userData.ID,
 | 
			
		||||
			userData.UserName,
 | 
			
		||||
			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
 | 
			
		||||
			}
 | 
			
		||||
		if err = db.UpdateUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, newPass, newPass2, user.Role); err != nil {
 | 
			
		||||
			log.Println("error: user:", user.ID, err)
 | 
			
		||||
			http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
 | 
			
		||||
		tmpl = template.Must(tmpl, err)
 | 
			
		||||
		tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
 | 
			
		||||
		if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
 
 | 
			
		||||
@@ -49,11 +49,4 @@
 | 
			
		||||
        <button class="btn" hx-get="/hub" hx-target="#page-content">Abbrechen</button>
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    var msg = "{{.Msg}}";
 | 
			
		||||
    if (msg != "") {
 | 
			
		||||
        alert(msg);
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
{{end}}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@
 | 
			
		||||
                    onSuccess(data);
 | 
			
		||||
                })
 | 
			
		||||
                .catch(error => {
 | 
			
		||||
                    htmx.trigger(htmx.find('#notification'), 'htmx:responseError', {xhr: {responseText: error.message}});
 | 
			
		||||
                    onError(error);
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -29,11 +29,4 @@
 | 
			
		||||
        <input class="action-btn" type="submit" value="Anlegen" hx-post="/user/add-first" hx-target="#page-content" />
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    var msg = "{{.Msg}}";
 | 
			
		||||
    if (msg != "") {
 | 
			
		||||
        alert(msg);
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
{{end}}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,10 @@
 | 
			
		||||
    </header>
 | 
			
		||||
 | 
			
		||||
    <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">
 | 
			
		||||
            {{template "page-content" .}}
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -35,7 +39,7 @@
 | 
			
		||||
 | 
			
		||||
    <footer class="text-center text-gray-500 my-8">
 | 
			
		||||
        <p>© 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>
 | 
			
		||||
 | 
			
		||||
    <script src="https://unpkg.com/htmx.org@2.0.2"></script>
 | 
			
		||||
@@ -66,6 +70,16 @@
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    </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>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user