forked from mirrors/homebox
Initial commit
This commit is contained in:
commit
29f583e936
135 changed files with 18463 additions and 0 deletions
29
backend/app/api/v1/controller.go
Normal file
29
backend/app/api/v1/controller.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"github.com/hay-kot/git-web-template/backend/internal/services"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/logger"
|
||||
)
|
||||
|
||||
type V1Controller struct {
|
||||
log *logger.Logger
|
||||
svc *services.AllServices
|
||||
}
|
||||
|
||||
func BaseUrlFunc(prefix string) func(s string) string {
|
||||
v1Base := prefix + "/v1"
|
||||
prefixFunc := func(s string) string {
|
||||
return v1Base + s
|
||||
}
|
||||
|
||||
return prefixFunc
|
||||
}
|
||||
|
||||
func NewControllerV1(log *logger.Logger, svc *services.AllServices) *V1Controller {
|
||||
ctrl := &V1Controller{
|
||||
log: log,
|
||||
svc: svc,
|
||||
}
|
||||
|
||||
return ctrl
|
||||
}
|
20
backend/app/api/v1/controller_test.go
Normal file
20
backend/app/api/v1/controller_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_NewHandlerV1(t *testing.T) {
|
||||
|
||||
v1Base := BaseUrlFunc("/testing/v1")
|
||||
ctrl := NewControllerV1(mockHandler.log, mockHandler.svc)
|
||||
|
||||
assert.NotNil(t, ctrl)
|
||||
|
||||
assert.Equal(t, ctrl.log, mockHandler.log)
|
||||
|
||||
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
|
||||
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
|
||||
}
|
51
backend/app/api/v1/main_test.go
Normal file
51
backend/app/api/v1/main_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hay-kot/git-web-template/backend/internal/mocks"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/mocks/factories"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/types"
|
||||
)
|
||||
|
||||
var mockHandler = &V1Controller{}
|
||||
var users = []types.UserOut{}
|
||||
|
||||
func userPool() func() {
|
||||
create := []types.UserCreate{
|
||||
factories.UserFactory(),
|
||||
factories.UserFactory(),
|
||||
factories.UserFactory(),
|
||||
factories.UserFactory(),
|
||||
}
|
||||
|
||||
userOut := []types.UserOut{}
|
||||
|
||||
for _, user := range create {
|
||||
usrOut, _ := mockHandler.svc.Admin.Create(context.Background(), user)
|
||||
userOut = append(userOut, usrOut)
|
||||
}
|
||||
|
||||
users = userOut
|
||||
|
||||
purge := func() {
|
||||
mockHandler.svc.Admin.DeleteAll(context.Background())
|
||||
}
|
||||
|
||||
return purge
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// Set Handler Vars
|
||||
mockHandler.log = mocks.GetStructLogger()
|
||||
repos, closeDb := mocks.GetEntRepos()
|
||||
mockHandler.svc = mocks.GetMockServices(repos)
|
||||
|
||||
defer closeDb()
|
||||
|
||||
purge := userPool()
|
||||
defer purge()
|
||||
|
||||
m.Run()
|
||||
}
|
207
backend/app/api/v1/v1_ctrl_admin.go
Normal file
207
backend/app/api/v1/v1_ctrl_admin.go
Normal file
|
@ -0,0 +1,207 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/services"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/types"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/hasher"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/logger"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/server"
|
||||
)
|
||||
|
||||
// HandleAdminUserGetAll godoc
|
||||
// @Summary Gets all users from the database
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=[]types.UserOut}
|
||||
// @Router /v1/admin/users [get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserGetAll() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
users, err := ctrl.svc.Admin.GetAll(r.Context())
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusOK, server.Wrap(users))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserGet godoc
|
||||
// @Summary Get a user from the database
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Param id path string true "User ID"
|
||||
// @Success 200 {object} server.Result{item=types.UserOut}
|
||||
// @Router /v1/admin/users/{id} [get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserGet() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := ctrl.svc.Admin.GetByID(r.Context(), uid)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
server.Respond(w, http.StatusOK, server.Wrap(user))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserCreate godoc
|
||||
// @Summary Create a new user
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Param payload body types.UserCreate true "User Data"
|
||||
// @Success 200 {object} server.Result{item=types.UserOut}
|
||||
// @Router /v1/admin/users [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserCreate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
createData := types.UserCreate{}
|
||||
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to decode user create data",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := createData.Validate()
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusUnprocessableEntity, err)
|
||||
return
|
||||
}
|
||||
|
||||
hashedPw, err := hasher.HashPassword(createData.Password)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to hash password",
|
||||
})
|
||||
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
createData.Password = hashedPw
|
||||
userOut, err := ctrl.svc.Admin.Create(r.Context(), createData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to create user",
|
||||
})
|
||||
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusCreated, server.Wrap(userOut))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserUpdate godoc
|
||||
// @Summary Update a User
|
||||
// @Tags Admin: Users
|
||||
// @Param id path string true "User ID"
|
||||
// @Param payload body types.UserUpdate true "User Data"
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=types.UserOut}
|
||||
// @Router /v1/admin/users/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserUpdate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
}
|
||||
|
||||
updateData := types.UserUpdate{}
|
||||
|
||||
if err := server.Decode(r, &updateData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to decode user update data",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
newData, err := ctrl.svc.Admin.UpdateProperties(r.Context(), uid, updateData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to update user",
|
||||
})
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusOK, server.Wrap(newData))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserDelete godoc
|
||||
// @Summary Delete a User
|
||||
// @Tags Admin: Users
|
||||
// @Param id path string true "User ID"
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/admin/users/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserDelete() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
}
|
||||
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
|
||||
if actor.ID == uid {
|
||||
server.RespondError(w, http.StatusBadRequest, errors.New("cannot delete yourself"))
|
||||
return
|
||||
}
|
||||
|
||||
err = ctrl.svc.Admin.Delete(r.Context(), uid)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to delete user",
|
||||
})
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
109
backend/app/api/v1/v1_ctrl_admin_test.go
Normal file
109
backend/app/api/v1/v1_ctrl_admin_test.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/hay-kot/git-web-template/backend/internal/mocks/chimocker"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/mocks/factories"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/types"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
UrlUser = "/api/v1/admin/users"
|
||||
UrlUserId = "/api/v1/admin/users/%v"
|
||||
UrlUserIdChi = "/api/v1/admin/users/{id}"
|
||||
)
|
||||
|
||||
type usersResponse struct {
|
||||
Users []types.UserOut `json:"item"`
|
||||
}
|
||||
|
||||
type userResponse struct {
|
||||
User types.UserOut `json:"item"`
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserGetAll_Success(t *testing.T) {
|
||||
r := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, UrlUser, nil)
|
||||
|
||||
mockHandler.HandleAdminUserGetAll()(r, req)
|
||||
|
||||
response := usersResponse{
|
||||
Users: []types.UserOut{},
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(r.Body.Bytes(), &response)
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
assert.Equal(t, len(users), len(response.Users))
|
||||
|
||||
knowEmail := []string{
|
||||
users[0].Email,
|
||||
users[1].Email,
|
||||
users[2].Email,
|
||||
users[3].Email,
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
assert.Contains(t, knowEmail, user.Email)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserGet_Success(t *testing.T) {
|
||||
targetUser := users[2]
|
||||
res := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf(UrlUserId, targetUser.ID), nil)
|
||||
|
||||
req = chimocker.WithUrlParam(req, "id", fmt.Sprintf("%v", targetUser.ID))
|
||||
|
||||
mockHandler.HandleAdminUserGet()(res, req)
|
||||
assert.Equal(t, http.StatusOK, res.Code)
|
||||
|
||||
response := userResponse{
|
||||
User: types.UserOut{},
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(res.Body.Bytes(), &response)
|
||||
assert.Equal(t, targetUser.ID, response.User.ID)
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserCreate_Success(t *testing.T) {
|
||||
payload := factories.UserFactory()
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, UrlUser, bytes.NewBuffer(body))
|
||||
req.Header.Set(server.ContentType, server.ContentJSON)
|
||||
|
||||
mockHandler.HandleAdminUserCreate()(r, req)
|
||||
|
||||
assert.Equal(t, http.StatusCreated, r.Code)
|
||||
|
||||
usr, err := mockHandler.svc.Admin.GetByEmail(context.Background(), payload.Email)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, payload.Email, usr.Email)
|
||||
assert.Equal(t, payload.Name, usr.Name)
|
||||
assert.NotEqual(t, payload.Password, usr.Password) // smoke test - check password is hashed
|
||||
|
||||
_ = mockHandler.svc.Admin.Delete(context.Background(), usr.ID)
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserUpdate_Success(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserUpdate_Delete(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
136
backend/app/api/v1/v1_ctrl_auth.go
Normal file
136
backend/app/api/v1/v1_ctrl_auth.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/git-web-template/backend/internal/services"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/types"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/logger"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/server"
|
||||
)
|
||||
|
||||
var (
|
||||
HeaderFormData = "application/x-www-form-urlencoded"
|
||||
HeaderJSON = "application/json"
|
||||
)
|
||||
|
||||
// HandleAuthLogin godoc
|
||||
// @Summary User Login
|
||||
// @Tags Authentication
|
||||
// @Accept x-www-form-urlencoded
|
||||
// @Accept application/json
|
||||
// @Param username formData string false "string" example(admin@admin.com)
|
||||
// @Param password formData string false "string" example(admin)
|
||||
// @Produce json
|
||||
// @Success 200 {object} types.TokenResponse
|
||||
// @Router /v1/users/login [POST]
|
||||
func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
loginForm := &types.LoginForm{}
|
||||
|
||||
if r.Header.Get("Content-Type") == HeaderFormData {
|
||||
err := r.ParseForm()
|
||||
|
||||
if err != nil {
|
||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
loginForm.Username = r.PostFormValue("username")
|
||||
loginForm.Password = r.PostFormValue("password")
|
||||
} else if r.Header.Get("Content-Type") == HeaderJSON {
|
||||
err := server.Decode(r, loginForm)
|
||||
|
||||
if err != nil {
|
||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
server.Respond(w, http.StatusBadRequest, errors.New("invalid content type"))
|
||||
return
|
||||
}
|
||||
|
||||
if loginForm.Username == "" || loginForm.Password == "" {
|
||||
server.RespondError(w, http.StatusBadRequest, errors.New("username and password are required"))
|
||||
return
|
||||
}
|
||||
|
||||
newToken, err := ctrl.svc.User.Login(r.Context(), loginForm.Username, loginForm.Password)
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = server.Respond(w, http.StatusOK, types.TokenResponse{
|
||||
BearerToken: "Bearer " + newToken.Raw,
|
||||
ExpiresAt: newToken.ExpiresAt,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"user": loginForm.Username,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAuthLogout godoc
|
||||
// @Summary User Logout
|
||||
// @Tags Authentication
|
||||
// @Success 204
|
||||
// @Router /v1/users/logout [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
|
||||
if token == "" {
|
||||
server.RespondError(w, http.StatusUnauthorized, errors.New("no token within request context"))
|
||||
return
|
||||
}
|
||||
|
||||
err := ctrl.svc.User.Logout(r.Context(), token)
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = server.Respond(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAuthLogout godoc
|
||||
// @Summary User Token Refresh
|
||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||
// @Description This does not validate that the user still exists within the database.
|
||||
// @Tags Authentication
|
||||
// @Success 200
|
||||
// @Router /v1/users/refresh [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthRefresh() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
requestToken := services.UseTokenCtx(r.Context())
|
||||
|
||||
if requestToken == "" {
|
||||
server.RespondError(w, http.StatusUnauthorized, errors.New("no user token found"))
|
||||
return
|
||||
}
|
||||
|
||||
newToken, err := ctrl.svc.User.RenewToken(r.Context(), requestToken)
|
||||
|
||||
if err != nil {
|
||||
server.RespondUnauthorized(w)
|
||||
return
|
||||
}
|
||||
|
||||
err = server.Respond(w, http.StatusOK, newToken)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
80
backend/app/api/v1/v1_ctrl_user.go
Normal file
80
backend/app/api/v1/v1_ctrl_user.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/git-web-template/backend/internal/services"
|
||||
"github.com/hay-kot/git-web-template/backend/internal/types"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/logger"
|
||||
"github.com/hay-kot/git-web-template/backend/pkgs/server"
|
||||
)
|
||||
|
||||
// HandleUserSelf godoc
|
||||
// @Summary Get the current user
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=types.UserOut}
|
||||
// @Router /v1/users/self [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
||||
if usr.IsNull() || err != nil {
|
||||
ctrl.log.Error(errors.New("no user within request context"), nil)
|
||||
server.RespondInternalServerError(w)
|
||||
return
|
||||
}
|
||||
|
||||
_ = server.Respond(w, http.StatusOK, server.Wrap(usr))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUserUpdate godoc
|
||||
// @Summary Update the current user
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body types.UserUpdate true "User Data"
|
||||
// @Success 200 {object} server.Result{item=types.UserUpdate}
|
||||
// @Router /v1/users/self [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserUpdate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateData := types.UserUpdate{}
|
||||
if err := server.Decode(r, &updateData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "user",
|
||||
"details": "failed to decode user update data",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "user",
|
||||
"details": "failed to update user",
|
||||
})
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
_ = server.Respond(w, http.StatusOK, server.Wrap(newData))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUserUpdatePassword godoc
|
||||
// @Summary Update the current user's password // TODO:
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/users/self/password [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserUpdatePassword() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue