161 lines
5.6 KiB
Go
161 lines
5.6 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
accountsvc "git.118im.com/im_team/olons_server/internal/accounts"
|
|
"git.118im.com/im_team/olons_server/internal/auth"
|
|
"git.118im.com/im_team/olons_server/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)
|
|
}
|
|
}
|