feat: added endpoints to get and update self

This commit is contained in:
overflowerror 2021-08-22 18:31:50 +02:00
parent 51aa1712fd
commit 035207f012
10 changed files with 150 additions and 16 deletions

View file

@ -10,6 +10,8 @@ type Data interface {
CountUsers() (int64, error)
AddUser(user *models.User) error
UpdateUser(user *models.User) error
GetUser(id uuid.UUID) (*models.User, error)
GetUserByUsername(username string) (*models.User, error)
AddUserToGroup(user *models.User, group *models.Group) error
DeleteUserFromGroup(user *models.User, group *models.Group) error

View file

@ -7,6 +7,8 @@ import (
)
type Logic interface {
UpdateUser(userToUpdate *models.User, currentUser *models.User) error
AuthenticateSession(token string) (*models.User, error)
Login(username, password string) (string, error)

View file

@ -5,7 +5,7 @@ type User struct {
Groups []*Group `gorm:"many2many:user_groups;"`
Username string `json:"username"`
Password string `json:"-"`
Password string `json:"password"`
}
func GetDefaultAdminUser() *User {

View file

@ -1,6 +1,7 @@
package data
import (
uuid "github.com/satori/go.uuid"
"gorm.io/gorm/clause"
"threadule/backend/internal/data/models"
)
@ -21,6 +22,26 @@ func (d *Data) AddUser(user *models.User) error {
Error
}
func (d *Data) UpdateUser(user *models.User) error {
return d.db.
Omit(clause.Associations).
Save(user).
Error
}
func (d *Data) GetUser(id uuid.UUID) (*models.User, error) {
var user models.User
err := d.db.
Preload("Groups").
First(&user, id).
Error
if err != nil {
return nil, err
} else {
return &user, nil
}
}
func (d *Data) GetUserByUsername(username string) (*models.User, error) {
var user models.User
err := d.db.

View file

@ -3,9 +3,11 @@ package logic
import "errors"
var (
ErrLoginFailed = errors.New("login failed")
ErrInvalidSession = errors.New("invalid session")
ErrInternalError = errors.New("something went wrong")
ErrInvalidParameter = errors.New("invalid parameter")
ErrNotFound = errors.New("resource not found")
ErrLoginFailed = errors.New("login failed")
ErrInvalidSession = errors.New("invalid session")
ErrInternalError = errors.New("something went wrong")
ErrInvalidParameter = errors.New("invalid parameter")
ErrNotFound = errors.New("resource not found")
ErrInsufficientPrivilege = errors.New("insufficient privilege")
ErrConflict = errors.New("there was a conflict")
)

View file

@ -0,0 +1,74 @@
package logic
import (
"threadule/backend/internal/data/models"
)
func (l *Logic) checkPrivilege(originalUser *models.User, currentUser *models.User) error {
if originalUser.ID == currentUser.ID {
// own user can always be modified
return nil
}
ok := false
needsAdmin := false
for _, group := range originalUser.Groups {
if group.AdminGroup {
needsAdmin = true
break
}
}
for _, group := range currentUser.Groups {
if group.AdminGroup {
// reset needs admin flag
needsAdmin = false
}
if group.ManageUsers {
ok = true
}
}
if !ok || needsAdmin {
return ErrInsufficientPrivilege
} else {
return nil
}
}
func (l *Logic) UpdateUser(userToUpdate *models.User, currentUser *models.User) error {
originalUser, err := l.ctx.Data.GetUser(userToUpdate.ID)
if err != nil {
return ErrNotFound
}
err = l.checkPrivilege(originalUser, currentUser)
if err != nil {
return err
}
if originalUser.Username != userToUpdate.Username {
_, err = l.ctx.Data.GetUserByUsername(userToUpdate.Username)
if err == nil {
// if no error there exists already a user with that name
return ErrConflict
}
}
if userToUpdate.Password != "" {
userToUpdate.Password, err = l.hashPassword(userToUpdate.Password)
if err != nil {
return err
}
}
userToUpdate.Groups = nil
userToUpdate.CreatedAt = originalUser.CreatedAt
err = l.ctx.Data.UpdateUser(userToUpdate)
userToUpdate.Groups = originalUser.Groups
userToUpdate.Password = ""
return err
}

View file

@ -1,7 +1,6 @@
package presentation
import (
"fmt"
"net/http"
"threadule/backend/internal/presentation/dto"
"threadule/backend/internal/web"
@ -28,11 +27,3 @@ func Login(ctx *web.Context) {
ErrorResponse(ctx, err)
}
}
func GetAuthenticationData(ctx *web.Context) {
fmt.Println(ctx.Session.User)
err := ctx.WriteJSON(ctx.Session.User)
if err != nil {
ErrorResponse(ctx, err)
}
}

View file

@ -28,8 +28,12 @@ func ErrorResponse(ctx *web.Context, err error) {
StatusResponse(ctx, http.StatusNotFound, err.Error())
case logic.ErrInvalidParameter:
StatusResponse(ctx, http.StatusBadRequest, err.Error())
case logic.ErrInsufficientPrivilege:
StatusResponse(ctx, http.StatusForbidden, err.Error())
case logic.ErrLoginFailed:
StatusResponse(ctx, http.StatusForbidden, err.Error())
case logic.ErrConflict:
StatusResponse(ctx, http.StatusConflict, err.Error())
case logic.ErrInvalidSession:
StatusResponse(ctx, http.StatusUnauthorized, err.Error())
case logic.ErrInternalError:

View file

@ -0,0 +1,36 @@
package presentation
import (
"threadule/backend/internal/data/models"
"threadule/backend/internal/web"
)
func UpdateSelf(ctx *web.Context) {
var user models.User
err := ctx.ReadJSON(&user)
if err != nil {
ErrorResponse(ctx, err)
return
}
user.ID = ctx.Session.User.ID
err = ctx.AppCtx.Logic.UpdateUser(&user, ctx.Session.User)
if err != nil {
ErrorResponse(ctx, err)
return
}
err = ctx.WriteJSON(&user)
if err != nil {
ErrorResponse(ctx, err)
return
}
}
func GetSelf(ctx *web.Context) {
err := ctx.WriteJSON(ctx.Session.User)
if err != nil {
ErrorResponse(ctx, err)
}
}

View file

@ -21,7 +21,6 @@ func Setup(ctx *app.Context) http.Handler {
})
router.POST("/authentication", Login)
router.GET("/authentication", authenticated(GetAuthenticationData))
router.GET("/account/", authenticated(GetAccounts))
router.POST("/account/", authenticated(AddAccount))
@ -32,5 +31,8 @@ func Setup(ctx *app.Context) http.Handler {
router.PUT("/thread/:id", authenticated(UpdateThread))
router.DELETE("/thread/:id", authenticated(DeleteThread))
router.GET("/self/", authenticated(GetSelf))
router.PUT("/self/", authenticated(UpdateSelf))
return router
}