feat: migrate workbench services
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
accountsvc "git.118im.com/im_team/im_workbench/internal/accounts"
|
||||
"git.118im.com/im_team/im_workbench/internal/auth"
|
||||
"git.118im.com/im_team/im_workbench/internal/store"
|
||||
)
|
||||
|
||||
type avatarRequest struct {
|
||||
AttachmentID int64 `json:"attachment_id"`
|
||||
}
|
||||
|
||||
type passwordRequest struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
|
||||
type tradePasswordRequest struct {
|
||||
LoginPassword string `json:"login_password"`
|
||||
OldTradePassword string `json:"old_trade_password,omitempty"`
|
||||
NewTradePassword string `json:"new_trade_password"`
|
||||
}
|
||||
|
||||
func (a *API) memberProfile(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
methodNotAllowed(w, r, http.MethodGet)
|
||||
return
|
||||
}
|
||||
principal, ok := a.authenticateMember(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
profile, err := a.accounts.Profile(r.Context(), principal.TenantID, principal.MemberID)
|
||||
if err != nil {
|
||||
writeProfileError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(w, r, profile)
|
||||
}
|
||||
|
||||
func (a *API) memberAvatar(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
methodNotAllowed(w, r, http.MethodPatch)
|
||||
return
|
||||
}
|
||||
principal, ok := a.authenticateMember(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var body avatarRequest
|
||||
if !decodeBody(w, r, &body) {
|
||||
return
|
||||
}
|
||||
avatar, err := a.accounts.ChangeAvatar(r.Context(), principal.TenantID, principal.MemberID, body.AttachmentID)
|
||||
if err != nil {
|
||||
writeProfileError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(w, r, avatar)
|
||||
}
|
||||
|
||||
func (a *API) memberPassword(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPut {
|
||||
methodNotAllowed(w, r, http.MethodPut)
|
||||
return
|
||||
}
|
||||
principal, ok := a.authenticateMember(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var body passwordRequest
|
||||
if !decodeBody(w, r, &body) {
|
||||
return
|
||||
}
|
||||
err := a.accounts.ChangePassword(r.Context(), principal.TenantID, principal.MemberID, accountsvc.ChangePasswordInput{
|
||||
OldPassword: body.OldPassword, NewPassword: body.NewPassword,
|
||||
})
|
||||
if err != nil {
|
||||
writeProfileError(w, r, err)
|
||||
return
|
||||
}
|
||||
if err := a.auth.RevokeMemberSessions(r.Context(), principal.TenantID, principal.MemberID); err != nil {
|
||||
writeProfileError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(w, r, nil)
|
||||
}
|
||||
|
||||
func (a *API) memberTradePassword(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPut {
|
||||
methodNotAllowed(w, r, http.MethodPut)
|
||||
return
|
||||
}
|
||||
principal, ok := a.authenticateMember(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var body tradePasswordRequest
|
||||
if !decodeBody(w, r, &body) {
|
||||
return
|
||||
}
|
||||
err := a.accounts.ChangeTradePassword(r.Context(), principal.TenantID, principal.MemberID, accountsvc.ChangeTradePasswordInput{
|
||||
LoginPassword: body.LoginPassword, OldTradePassword: body.OldTradePassword,
|
||||
NewTradePassword: body.NewTradePassword,
|
||||
})
|
||||
if err != nil {
|
||||
writeProfileError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(w, r, nil)
|
||||
}
|
||||
|
||||
func (a *API) authenticateMember(w http.ResponseWriter, r *http.Request) (*auth.Principal, bool) {
|
||||
if a.auth == nil || a.accounts == nil {
|
||||
writeError(w, r, http.StatusServiceUnavailable, 90001, "SERVICE_UNAVAILABLE", "service unavailable", nil)
|
||||
return nil, false
|
||||
}
|
||||
principal, err := a.auth.Authenticate(r)
|
||||
if err == nil {
|
||||
return principal, true
|
||||
}
|
||||
if errors.Is(err, auth.ErrForbidden) {
|
||||
writeError(w, r, http.StatusForbidden, 30003, reasonForbidden, "forbidden", nil)
|
||||
} else if errors.Is(err, auth.ErrAuthRequired) {
|
||||
writeError(w, r, http.StatusUnauthorized, 30041, "AUTH_REQUIRED", "authentication required", nil)
|
||||
} else {
|
||||
writeError(w, r, http.StatusInternalServerError, 90000, reasonInternal, "internal error", nil)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func writeProfileError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
switch {
|
||||
case errors.Is(err, accountsvc.ErrAttachmentInvalid), errors.Is(err, store.ErrAttachmentInvalid):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "AVATAR_ATTACHMENT_INVALID", "validation failed", map[string]any{"field": "attachment_id"})
|
||||
case errors.Is(err, accountsvc.ErrCurrentPassword):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "CURRENT_PASSWORD_INVALID", "current password is invalid", map[string]any{"field": "old_password"})
|
||||
case errors.Is(err, accountsvc.ErrLoginPassword):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "LOGIN_PASSWORD_INVALID", "login password is invalid", map[string]any{"field": "login_password"})
|
||||
case errors.Is(err, accountsvc.ErrPasswordInvalid):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "NEW_PASSWORD_INVALID", "validation failed", map[string]any{"field": "new_password"})
|
||||
case errors.Is(err, accountsvc.ErrOldTradePasswordUnset):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "OLD_TRADE_PASSWORD_REQUIRED", "old trade password is required", map[string]any{"field": "old_trade_password"})
|
||||
case errors.Is(err, accountsvc.ErrOldTradePassword):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "OLD_TRADE_PASSWORD_INVALID", "old trade password is invalid", map[string]any{"field": "old_trade_password"})
|
||||
case errors.Is(err, accountsvc.ErrTradePassword):
|
||||
writeError(w, r, http.StatusBadRequest, 30000, "TRADE_PASSWORD_INVALID", "trade password is invalid", map[string]any{"field": "new_trade_password"})
|
||||
case errors.Is(err, store.ErrAccountNotFound):
|
||||
writeError(w, r, http.StatusNotFound, 30044, "ACCOUNT_NOT_FOUND", "account not found", nil)
|
||||
case errors.Is(err, store.ErrConcurrentUpdate):
|
||||
writeError(w, r, http.StatusConflict, 30040, "ACCOUNT_CHANGED", "account changed, retry the operation", nil)
|
||||
case errors.Is(err, accountsvc.ErrUnavailable):
|
||||
writeError(w, r, http.StatusServiceUnavailable, 90001, "SERVICE_UNAVAILABLE", "service unavailable", nil)
|
||||
default:
|
||||
writeError(w, r, http.StatusInternalServerError, 90000, reasonInternal, "internal error", nil)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user