package frontend import ( "fmt" "html/template" "log" "net/http" "sort" "strconv" b "streifling.com/jason/cpolis/cmd/backend" ) type UserHTMLData struct { *b.User Title string ButtonText string URL string Image string } func checkUserStrings(user *b.User) (string, int, bool) { userLen := 63 // max value for utf-8 at 255 bytes nameLen := 56 // max value when aes encrypting utf-8 at up to 255 bytes if len(user.UserName) > userLen { return "Benutzername", userLen, false } else if len(user.FirstName) > nameLen { return "Vorname", nameLen, false } else if len(user.LastName) > nameLen { return "Nachname", nameLen, false } else { return "", 0, true } } func sortUsersByName(users []*b.User) { sort.SliceStable(users, func(i, j int) bool { if users[i].LastName == users[j].LastName { return users[i].FirstName < users[j].FirstName } return users[i].LastName < users[j].LastName }) } func CreateUser(c *b.Config, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := ManageSession(w, r, c, s); err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } data := &UserHTMLData{ User: &b.User{Role: b.Author}, Title: "Neuer Benutzer", ButtonText: "Anlegen", URL: "/user/add", } tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func AddUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } user := &b.User{ UserName: r.PostFormValue("username"), FirstName: r.PostFormValue("first-name"), LastName: r.PostFormValue("last-name"), Email: r.PostFormValue("email"), ProfilePicLink: r.PostFormValue("profile-pic-url"), } pass := r.PostFormValue("password") pass2 := r.PostFormValue("password2") email2 := r.PostFormValue("email2") if len(user.UserName) == 0 || len(user.FirstName) == 0 || len(user.LastName) == 0 || len(user.Email) == 0 || len(email2) == 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 user.Email != email2 { http.Error(w, "Die Emailadressen stimmen nicht überein.", 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 } _, err = db.AddUser(c, user, pass) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } data := new(struct{ Role int }) data.Role = session.User.Role tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func EditSelf(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } user, err := db.GetUser(c, session.User.ID) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } data := &UserHTMLData{ User: user, Title: "Mein Profil bearbeiten", ButtonText: "Übernehmen", URL: "/user/update/self", Image: user.ProfilePicLink, } tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func UpdateSelf(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } user := &b.User{ ID: session.User.ID, UserName: r.PostFormValue("username"), FirstName: r.PostFormValue("first-name"), LastName: r.PostFormValue("last-name"), Email: r.PostFormValue("email"), ProfilePicLink: r.PostFormValue("profile-pic-url"), } oldPass := r.PostFormValue("old-password") newPass := r.PostFormValue("password") newPass2 := r.PostFormValue("password2") email2 := r.PostFormValue("email2") if len(user.UserName) == 0 { http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest) return } if len(user.FirstName) == 0 || len(user.LastName) == 0 { http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusBadRequest) return } if len(user.Email) == 0 || len(email2) == 0 { http.Error(w, "Bitte die Emailadresse ausfüllen.", http.StatusBadRequest) return } if user.Email != email2 { http.Error(w, "Die Emailadressen stimmen nicht überein", http.StatusBadRequest) return } if newPass != newPass2 { http.Error(w, "Die Passwörter stimmen nicht überein", 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 && id != user.ID { http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest) return } if err = db.UpdateOwnUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, user.ProfilePicLink, oldPass, newPass); err != nil { log.Println("error: user:", user.ID, err) http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError) return } data := new(struct{ Role int }) data.Role = session.User.Role tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func AddFirstUser(c *b.Config, db *b.DB, s map[string]*Session, sessionExpiryChan chan string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var err error user := &b.User{ UserName: r.PostFormValue("username"), FirstName: r.PostFormValue("first-name"), LastName: r.PostFormValue("last-name"), Email: r.PostFormValue("email"), ProfilePicLink: r.PostFormValue("profile-pic-url"), Role: b.Admin, } pass := r.PostFormValue("password") pass2 := r.PostFormValue("password2") email2 := r.PostFormValue("email2") if len(user.UserName) == 0 || len(user.FirstName) == 0 || len(user.LastName) == 0 || len(user.Email) == 0 || len(email2) == 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 user.Email != email2 { http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest) return } if pass != pass2 { http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest) return } user.ID, err = db.AddFirstUser(c, user, pass) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if user.ID == -1 { http.Error(w, "Bitte ein Benutzerkonto von einem Administrator anlegen lassen.", http.StatusInternalServerError) return } if _, err := db.AddIssue(); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } session := newSession(w, c, sessionExpiryChan, user) s[session.cookie.Value] = session http.SetCookie(w, session.cookie) data := new(struct{ Role int }) data.Role = user.Role tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func ShowAllUsers(c *b.Config, db *b.DB, s map[string]*Session, action string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } data := new(struct { Users map[int64]*b.User Action string }) data.Action = action data.Users, err = db.GetAllUsersMap(c) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } delete(data.Users, session.User.ID) tmpl, err := template.ParseFiles(c.WebDir + "/templates/show-all-users.html") if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func EditUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := ManageSession(w, r, c, s); err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } user, err := db.GetUser(c, id) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } data := &UserHTMLData{ User: user, Title: "Profil von " + user.FirstName + " " + user.LastName + " bearbeiten", ButtonText: "Übernehmen", URL: fmt.Sprint("/user/update/", user.ID), Image: user.ProfilePicLink, } tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func UpdateUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } 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 } user.Role, err = strconv.Atoi(r.PostFormValue("role")) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } user.UserName = r.PostFormValue("username") if len(user.UserName) == 0 { http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest) 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.StatusBadRequest) return } user.Email = r.PostFormValue("email") email2 := r.PostFormValue("email2") if len(user.Email) == 0 || len(email2) == 0 { http.Error(w, "Bitte die Emailadresse ausfüllen.", http.StatusBadRequest) return } if user.Email != email2 { http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest) return } user.ProfilePicLink = r.PostFormValue("profile-pic-url") newPass := r.PostFormValue("password") newPass2 := r.PostFormValue("password2") if newPass != newPass2 { http.Error(w, "Die Passwörter stimmen nicht überein.", 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 && id != user.ID { http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest) return } if err = db.UpdateUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, user.ProfilePicLink, newPass, user.Role); err != nil { log.Println("error: user:", user.ID, err) http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError) return } data := new(struct{ Role int }) data.Role = session.User.Role tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html")) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func DeleteUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := ManageSession(w, r, c, s) if err != nil { http.Error(w, "Die Session ist abgelaufen. Bitte erneut anmelden.", http.StatusUnauthorized) return } id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if err = db.DeleteUser(id); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } data := new(struct{ Role int }) data.Role = session.User.Role tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } }