uni/WEB43-diary/internal/routes/user.go

291 lines
7.6 KiB
Go

package routes
import (
"io"
"net/http"
"strconv"
"gitea.zokki.net/zokki/uni/web43-diary/context"
"gitea.zokki.net/zokki/uni/web43-diary/internal/database"
"gitea.zokki.net/zokki/uni/web43-diary/internal/models"
"gitea.zokki.net/zokki/uni/web43-diary/internal/session"
)
func createUser(writer http.ResponseWriter, req *http.Request) {
user := models.User{
Username: req.FormValue("username"),
FirstName: req.FormValue("firstName"),
LastName: req.FormValue("lastName"),
Password: req.FormValue("password"),
}
if user.Username == "" || user.FirstName == "" || user.LastName == "" || user.Password == "" {
errorJson(writer, &models.HTTPError{
Message: "Es müssen alle Felder gefüllt sein",
Code: http.StatusBadRequest,
})
return
}
if user.Password != req.FormValue("passwordRepeat") {
errorJson(writer, &models.HTTPError{
Message: "Passwörter müssen übereinstimmen",
Code: http.StatusBadRequest,
})
return
}
var httpErr *models.HTTPError
user.Password, user.Salt, httpErr = hashPassword(user.Password, "")
if httpErr != nil {
errorJson(writer, httpErr)
return
}
_, err := database.GetOne(req.Context().(*context.Context), &models.User{Username: user.Username})
if err == nil {
errorJson(writer, &models.HTTPError{
Message: "Benutzername bereits vergeben",
Code: http.StatusBadRequest,
})
return
}
userId, err := database.InsertInto(req.Context().(*context.Context), &user)
if err != nil {
errorJson(writer, &models.HTTPError{
Message: "User konnte nicht in die Datenbank gespeichert werden",
Code: http.StatusInternalServerError,
Data: err,
})
return
}
if userId == 1 {
// set first user as admin
user.Role = models.AdminUser
if err := database.Update(req.Context().(*context.Context), &models.User{ID: uint32(userId)}, &user); err != nil {
errorJson(writer, &models.HTTPError{
Message: "Fehler beim Aktualisieren des Benutzers",
Code: http.StatusInternalServerError,
Data: err,
})
return
}
}
}
func updateTheme(writer http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(io.LimitReader(req.Body, 8))
if err != nil {
http.Error(writer, "Unable to read request body", http.StatusBadRequest)
return
}
defer req.Body.Close()
theme := models.WebThemeFromString(string(body))
session.GetSession(req).SetTheme(theme)
}
func loginUser(writer http.ResponseWriter, req *http.Request) {
username := req.FormValue("username")
password := req.FormValue("password")
if username == "" || password == "" {
errorJson(writer, &models.HTTPError{
Message: "Es müssen alle Felder gefüllt sein",
Code: http.StatusBadRequest,
})
return
}
user, err := database.GetOne(req.Context().(*context.Context), &models.User{Username: username})
if err != nil {
errorJson(writer, &models.HTTPError{
Message: "Benutzername oder Passwort ist falsch",
Code: http.StatusUnauthorized,
})
return
}
hashedPassword, _, httpErr := hashPassword(password, user.Salt)
if httpErr != nil {
errorJson(writer, httpErr)
return
}
if hashedPassword != user.Password {
errorJson(writer, &models.HTTPError{
Message: "Benutzername oder Passwort ist falsch",
Code: http.StatusUnauthorized,
})
return
}
session.GetSession(req).SetUser(user)
}
func logoutUser(writer http.ResponseWriter, req *http.Request) {
session.GetSession(req).Destroy(writer, req)
http.Redirect(writer, req, "/", http.StatusSeeOther)
}
func updateUser(writer http.ResponseWriter, req *http.Request) {
idToUpdate, err := strconv.ParseUint(req.PathValue(UserIDValue), 10, 32)
if err != nil || idToUpdate == 0 {
errorJson(writer, &models.HTTPError{
Message: "Malformed user ID",
Code: http.StatusBadRequest,
})
return
}
updateID := uint32(idToUpdate)
user := models.User{}
if username := req.FormValue("username"); username != "" {
user.Username = username
}
if firstName := req.FormValue("firstName"); firstName != "" {
user.FirstName = firstName
}
if lastName := req.FormValue("lastName"); lastName != "" {
user.LastName = lastName
}
if user.Username != "" || user.FirstName != "" || user.LastName != "" {
sess := session.GetSession(req)
currentUser := sess.GetUser()
if currentUser.ID != updateID && !currentUser.Role.IsAdminUser() {
errorJson(writer, &models.HTTPError{
Message: "Sie haben keine Berechtigung, diesen Benutzer zu bearbeiten",
Code: http.StatusForbidden,
})
return
}
_, err := database.GetOne(req.Context().(*context.Context), &models.User{Username: user.Username})
if err == nil {
errorJson(writer, &models.HTTPError{
Message: "Benutzername bereits vergeben",
Code: http.StatusBadRequest,
})
return
}
// Update user in the database
if err := database.Update(req.Context().(*context.Context), &models.User{ID: updateID}, &user); err != nil {
errorJson(writer, &models.HTTPError{
Message: "Fehler beim Aktualisieren des Benutzers",
Code: http.StatusInternalServerError,
Data: err,
})
return
}
// Update user in the session
currentUser.Username = user.Username
currentUser.FirstName = user.FirstName
currentUser.LastName = user.LastName
sess.SetUser(currentUser)
writer.WriteHeader(http.StatusNoContent)
}
}
func updateUserPassword(writer http.ResponseWriter, req *http.Request) {
currentPassword := req.FormValue("currentPassword")
newPassword := req.FormValue("newPassword")
repeatPassword := req.FormValue("passwordRepeat")
if currentPassword == "" || newPassword == "" || repeatPassword == "" {
errorJson(writer, &models.HTTPError{
Message: "Es müssen alle Felder gefüllt sein",
Code: http.StatusBadRequest,
})
return
}
if newPassword != repeatPassword {
errorJson(writer, &models.HTTPError{
Message: "Passwörter müssen übereinstimmen",
Code: http.StatusBadRequest,
})
return
}
sess := session.GetSession(req)
user := sess.GetUser()
hashedCurrentPassword, _, err := hashPassword(currentPassword, user.Salt)
if err != nil {
errorJson(writer, err)
return
}
if hashedCurrentPassword != user.Password {
errorJson(writer, &models.HTTPError{
Message: "Aktuelles Passwort ist falsch",
Code: http.StatusUnauthorized,
})
return
}
hashedNewPassword, salt, httpErr := hashPassword(newPassword, "")
if httpErr != nil {
errorJson(writer, httpErr)
return
}
newPasswordUser := &models.User{
Password: hashedNewPassword,
Salt: salt,
}
if err := database.Update(req.Context().(*context.Context), &models.User{ID: user.ID}, newPasswordUser); err != nil {
errorJson(writer, &models.HTTPError{
Message: "Fehler beim Aktualisieren des Passworts",
Code: http.StatusInternalServerError,
Data: err,
})
return
}
sess.SetUser(user)
writer.WriteHeader(http.StatusNoContent)
}
func deleteUser(writer http.ResponseWriter, req *http.Request) {
idToDelete, err := strconv.ParseUint(req.PathValue(UserIDValue), 10, 32)
if err != nil || idToDelete == 0 {
errorJson(writer, &models.HTTPError{
Message: "Malformed user ID",
Code: http.StatusBadRequest,
})
return
}
deleteID := uint32(idToDelete)
sess := session.GetSession(req)
user := sess.GetUser()
if user.ID != deleteID && !user.Role.IsAdminUser() {
errorJson(writer, &models.HTTPError{
Message: "Sie haben keine Berechtigung, diesen Benutzer zu löschen",
Code: http.StatusForbidden,
})
return
}
if err := database.Delete(req.Context().(*context.Context), &models.User{ID: deleteID}); err != nil {
errorJson(writer, &models.HTTPError{
Message: "Fehler beim Löschen des Benutzers",
Code: http.StatusInternalServerError,
Data: err,
})
return
}
if user.ID == deleteID {
sess.Destroy(writer, req)
}
}