mirror of
https://github.com/sigmasternchen/threadule
synced 2025-03-15 08:09:01 +00:00
feat: added endpoints to get and update self
This commit is contained in:
parent
51aa1712fd
commit
035207f012
10 changed files with 150 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
74
backend/internal/logic/user.go
Normal file
74
backend/internal/logic/user.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
36
backend/internal/presentation/user.go
Normal file
36
backend/internal/presentation/user.go
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue