454 lines
14 KiB
Go
454 lines
14 KiB
Go
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
package schema
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/apache/answer/internal/base/handler"
|
|
"github.com/apache/answer/internal/base/reason"
|
|
"github.com/apache/answer/internal/base/translator"
|
|
"github.com/apache/answer/pkg/day"
|
|
"github.com/segmentfault/pacman/errors"
|
|
|
|
"github.com/apache/answer/internal/base/constant"
|
|
"github.com/apache/answer/internal/base/validator"
|
|
"github.com/apache/answer/internal/entity"
|
|
"github.com/apache/answer/pkg/checker"
|
|
"github.com/apache/answer/pkg/converter"
|
|
"github.com/jinzhu/copier"
|
|
)
|
|
|
|
// UserVerifyEmailReq user verify email request
|
|
type UserVerifyEmailReq struct {
|
|
// code
|
|
Code string `validate:"required,gt=0,lte=500" form:"code"`
|
|
// content
|
|
Content string `json:"-"`
|
|
}
|
|
|
|
// UserLoginResp get user response
|
|
type UserLoginResp struct {
|
|
// user id
|
|
ID string `json:"id"`
|
|
// create time
|
|
CreatedAt int64 `json:"created_at"`
|
|
// last login date
|
|
LastLoginDate int64 `json:"last_login_date"`
|
|
// username
|
|
Username string `json:"username"`
|
|
// email
|
|
EMail string `json:"e_mail"`
|
|
// mail status(1 pass 2 to be verified)
|
|
MailStatus int `json:"mail_status"`
|
|
// notice status(1 on 2off)
|
|
NoticeStatus int `json:"notice_status"`
|
|
// follow count
|
|
FollowCount int `json:"follow_count"`
|
|
// answer count
|
|
AnswerCount int `json:"answer_count"`
|
|
// question count
|
|
QuestionCount int `json:"question_count"`
|
|
// rank
|
|
Rank int `json:"rank"`
|
|
// authority group
|
|
AuthorityGroup int `json:"authority_group"`
|
|
// display name
|
|
DisplayName string `json:"display_name"`
|
|
// avatar
|
|
Avatar string `json:"avatar"`
|
|
// mobile
|
|
Mobile string `json:"mobile"`
|
|
// bio markdown
|
|
Bio string `json:"bio"`
|
|
// bio html
|
|
BioHTML string `json:"bio_html"`
|
|
// website
|
|
Website string `json:"website"`
|
|
// location
|
|
Location string `json:"location"`
|
|
// language
|
|
Language string `json:"language"`
|
|
// Color scheme
|
|
ColorScheme string `json:"color_scheme"`
|
|
// access token
|
|
AccessToken string `json:"access_token"`
|
|
// role id
|
|
RoleID int `json:"role_id"`
|
|
// user status
|
|
Status string `json:"status"`
|
|
// user have password
|
|
HavePassword bool `json:"have_password"`
|
|
// visit token
|
|
VisitToken string `json:"visit_token"`
|
|
// suspended until timestamp
|
|
SuspendedUntil int64 `json:"suspended_until"`
|
|
}
|
|
|
|
func (r *UserLoginResp) ConvertFromUserEntity(userInfo *entity.User) {
|
|
_ = copier.Copy(r, userInfo)
|
|
r.CreatedAt = userInfo.CreatedAt.Unix()
|
|
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
|
r.Status = constant.ConvertUserStatus(userInfo.Status, userInfo.MailStatus)
|
|
r.HavePassword = len(userInfo.Pass) > 0
|
|
if !userInfo.SuspendedUntil.IsZero() {
|
|
r.SuspendedUntil = userInfo.SuspendedUntil.Unix()
|
|
}
|
|
}
|
|
|
|
type GetCurrentLoginUserInfoResp struct {
|
|
*UserLoginResp
|
|
Avatar *AvatarInfo `json:"avatar"`
|
|
}
|
|
|
|
func (r *GetCurrentLoginUserInfoResp) ConvertFromUserEntity(userInfo *entity.User) {
|
|
_ = copier.Copy(r, userInfo)
|
|
r.CreatedAt = userInfo.CreatedAt.Unix()
|
|
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
|
r.Status = constant.ConvertUserStatus(userInfo.Status, userInfo.MailStatus)
|
|
if len(r.ColorScheme) == 0 {
|
|
r.ColorScheme = constant.ColorSchemeDefault
|
|
}
|
|
if !userInfo.SuspendedUntil.IsZero() {
|
|
r.SuspendedUntil = userInfo.SuspendedUntil.Unix()
|
|
}
|
|
}
|
|
|
|
// GetOtherUserInfoByUsernameResp get user response
|
|
type GetOtherUserInfoByUsernameResp struct {
|
|
// user id
|
|
ID string `json:"id"`
|
|
// create time
|
|
CreatedAt int64 `json:"created_at"`
|
|
// last login date
|
|
LastLoginDate int64 `json:"last_login_date"`
|
|
// username
|
|
Username string `json:"username"`
|
|
// email
|
|
// follow count
|
|
FollowCount int `json:"follow_count"`
|
|
// answer count
|
|
AnswerCount int `json:"answer_count"`
|
|
// question count
|
|
QuestionCount int `json:"question_count"`
|
|
// rank
|
|
Rank int `json:"rank"`
|
|
// display name
|
|
DisplayName string `json:"display_name"`
|
|
// avatar
|
|
Avatar string `json:"avatar"`
|
|
// mobile
|
|
Mobile string `json:"mobile"`
|
|
// bio markdown
|
|
Bio string `json:"bio"`
|
|
// bio html
|
|
BioHTML string `json:"bio_html"`
|
|
// website
|
|
Website string `json:"website"`
|
|
// location
|
|
Location string `json:"location"`
|
|
Status string `json:"status"`
|
|
StatusMsg string `json:"status_msg,omitempty"`
|
|
// suspended until timestamp
|
|
SuspendedUntil int64 `json:"suspended_until"`
|
|
}
|
|
|
|
func (r *GetOtherUserInfoByUsernameResp) ConvertFromUserEntity(userInfo *entity.User) {
|
|
_ = copier.Copy(r, userInfo)
|
|
r.CreatedAt = userInfo.CreatedAt.Unix()
|
|
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
|
r.Status = constant.ConvertUserStatus(userInfo.Status, userInfo.MailStatus)
|
|
if !userInfo.SuspendedUntil.IsZero() {
|
|
r.SuspendedUntil = userInfo.SuspendedUntil.Unix()
|
|
}
|
|
r.StatusMsg = ""
|
|
}
|
|
|
|
func (r *GetOtherUserInfoByUsernameResp) ConvertFromUserEntityWithLang(ctx context.Context, userInfo *entity.User) {
|
|
_ = copier.Copy(r, userInfo)
|
|
r.CreatedAt = userInfo.CreatedAt.Unix()
|
|
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
|
r.Status = constant.ConvertUserStatus(userInfo.Status, userInfo.MailStatus)
|
|
|
|
lang := handler.GetLangByCtx(ctx)
|
|
if userInfo.MailStatus == entity.EmailStatusToBeVerified {
|
|
r.StatusMsg = translator.Tr(lang, reason.UserStatusInactive)
|
|
}
|
|
switch userInfo.Status {
|
|
case entity.UserStatusSuspended:
|
|
if userInfo.SuspendedUntil.IsZero() || userInfo.SuspendedUntil.Year() >= 2099 {
|
|
r.StatusMsg = translator.Tr(lang, reason.UserStatusSuspendedForever)
|
|
} else {
|
|
r.SuspendedUntil = userInfo.SuspendedUntil.Unix()
|
|
trans := translator.GlobalTrans.Tr(lang, "ui.dates.long_date_with_time")
|
|
suspendedUntilFormatted := day.Format(userInfo.SuspendedUntil.Unix(), trans, "UTC")
|
|
r.StatusMsg = translator.TrWithData(lang, reason.UserStatusSuspendedUntil, map[string]any{
|
|
"SuspendedUntil": suspendedUntilFormatted,
|
|
})
|
|
}
|
|
case entity.UserStatusDeleted:
|
|
r.StatusMsg = translator.Tr(lang, reason.UserStatusDeleted)
|
|
}
|
|
}
|
|
|
|
// UserEmailLoginReq user email login request
|
|
type UserEmailLoginReq struct {
|
|
Email string `validate:"required,email,gt=0,lte=500" json:"e_mail"`
|
|
Pass string `validate:"required,gte=8,lte=32" json:"pass"`
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaCode string `json:"captcha_code"`
|
|
}
|
|
|
|
// UserRegisterReq user register request
|
|
type UserRegisterReq struct {
|
|
Name string `validate:"required,gte=2,lte=30" json:"name"`
|
|
Email string `validate:"required,email,gt=0,lte=500" json:"e_mail" `
|
|
Pass string `validate:"required,gte=8,lte=32" json:"pass"`
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaCode string `json:"captcha_code"`
|
|
IP string `json:"-" `
|
|
RequireEmailVerification bool `json:"-"`
|
|
}
|
|
|
|
func (u *UserRegisterReq) Check() (errFields []*validator.FormErrorField, err error) {
|
|
if err = checker.CheckPassword(u.Pass); err != nil {
|
|
errFields = append(errFields, &validator.FormErrorField{
|
|
ErrorField: "pass",
|
|
ErrorMsg: err.Error(),
|
|
})
|
|
return errFields, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
type UserModifyPasswordReq struct {
|
|
OldPass string `validate:"omitempty,gte=8,lte=32" json:"old_pass"`
|
|
Pass string `validate:"required,gte=8,lte=32" json:"pass"`
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaCode string `json:"captcha_code"`
|
|
UserID string `json:"-"`
|
|
AccessToken string `json:"-"`
|
|
}
|
|
|
|
func (u *UserModifyPasswordReq) Check() (errFields []*validator.FormErrorField, err error) {
|
|
if err = checker.CheckPassword(u.Pass); err != nil {
|
|
errFields = append(errFields, &validator.FormErrorField{
|
|
ErrorField: "pass",
|
|
ErrorMsg: err.Error(),
|
|
})
|
|
return errFields, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
type UpdateInfoRequest struct {
|
|
DisplayName string `validate:"omitempty,gte=2,lte=30" json:"display_name"`
|
|
Username string `validate:"omitempty,gte=2,lte=30" json:"username"`
|
|
Avatar AvatarInfo `json:"avatar"`
|
|
Bio string `validate:"omitempty,gt=0,lte=4096" json:"bio"`
|
|
BioHTML string `json:"-"`
|
|
Website string `validate:"omitempty,gt=0,lte=500" json:"website"`
|
|
Location string `validate:"omitempty,gt=0,lte=100" json:"location"`
|
|
UserID string `json:"-"`
|
|
IsAdmin bool `json:"-"`
|
|
}
|
|
|
|
type AvatarInfo struct {
|
|
Type string `validate:"omitempty,gt=0,lte=100" json:"type"`
|
|
Gravatar string `validate:"omitempty,gt=0,lte=200" json:"gravatar"`
|
|
Custom string `validate:"omitempty,gt=0,lte=200" json:"custom"`
|
|
}
|
|
|
|
func (a *AvatarInfo) ToJsonString() string {
|
|
data, _ := json.Marshal(a)
|
|
return string(data)
|
|
}
|
|
|
|
func (a *AvatarInfo) GetURL() string {
|
|
switch a.Type {
|
|
case constant.AvatarTypeGravatar:
|
|
return a.Gravatar
|
|
case constant.AvatarTypeCustom:
|
|
return a.Custom
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func CustomAvatar(url string) *AvatarInfo {
|
|
return &AvatarInfo{
|
|
Type: constant.AvatarTypeCustom,
|
|
Custom: url,
|
|
}
|
|
}
|
|
|
|
func (req *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err error) {
|
|
req.BioHTML = converter.Markdown2BasicHTML(req.Bio)
|
|
if len(req.Website) > 0 && !checker.IsURL(req.Website) {
|
|
return append(errFields, &validator.FormErrorField{
|
|
ErrorField: "website",
|
|
ErrorMsg: reason.InvalidURLError,
|
|
}), errors.BadRequest(reason.InvalidURLError)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// UpdateUserInterfaceRequest update user interface request
|
|
type UpdateUserInterfaceRequest struct {
|
|
// language
|
|
Language string `validate:"required,gt=1,lte=100" json:"language"`
|
|
// Color scheme
|
|
ColorScheme string `validate:"required,gt=1,lte=100" json:"color_scheme"`
|
|
// user id
|
|
UserId string `json:"-"`
|
|
}
|
|
|
|
func (req *UpdateUserInterfaceRequest) Check() (errFields []*validator.FormErrorField, err error) {
|
|
if !translator.CheckLanguageIsValid(req.Language) {
|
|
return nil, errors.BadRequest(reason.LangNotFound)
|
|
}
|
|
if req.ColorScheme != constant.ColorSchemeDefault &&
|
|
req.ColorScheme != constant.ColorSchemeLight &&
|
|
req.ColorScheme != constant.ColorSchemeDark &&
|
|
req.ColorScheme != constant.ColorSchemeSystem {
|
|
req.ColorScheme = constant.ColorSchemeDefault
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
type UserRetrievePassWordRequest struct {
|
|
Email string `validate:"required,email,gt=0,lte=500" json:"e_mail"`
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaCode string `json:"captcha_code"`
|
|
}
|
|
|
|
type UserRePassWordRequest struct {
|
|
Code string `validate:"required,gt=0,lte=100" json:"code"`
|
|
Pass string `validate:"required,gt=0,lte=32" json:"pass"`
|
|
Content string `json:"-"`
|
|
}
|
|
|
|
func (u *UserRePassWordRequest) Check() (errFields []*validator.FormErrorField, err error) {
|
|
if err = checker.CheckPassword(u.Pass); err != nil {
|
|
errFields = append(errFields, &validator.FormErrorField{
|
|
ErrorField: "pass",
|
|
ErrorMsg: err.Error(),
|
|
})
|
|
return errFields, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
type ActionRecordReq struct {
|
|
Action string `validate:"required,oneof=email password edit_userinfo question answer comment edit invitation_answer search report delete vote" form:"action"`
|
|
IP string `json:"-"`
|
|
UserID string `json:"-"`
|
|
}
|
|
|
|
type ActionRecordResp struct {
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaImg string `json:"captcha_img"`
|
|
Verify bool `json:"verify"`
|
|
}
|
|
|
|
type UserBasicInfo struct {
|
|
ID string `json:"id"`
|
|
Username string `json:"username"`
|
|
Rank int `json:"rank"`
|
|
DisplayName string `json:"display_name"`
|
|
Avatar string `json:"avatar"`
|
|
Website string `json:"website"`
|
|
Location string `json:"location"`
|
|
Language string `json:"language"`
|
|
Status string `json:"status"`
|
|
SuspendedUntil int64 `json:"suspended_until"`
|
|
}
|
|
|
|
type GetOtherUserInfoByUsernameReq struct {
|
|
Username string `validate:"required,gt=0,lte=500" form:"username"`
|
|
UserID string `json:"-"`
|
|
IsAdmin bool `json:"-"`
|
|
}
|
|
|
|
type GetOtherUserInfoResp struct {
|
|
Info *GetOtherUserInfoByUsernameResp `json:"info"`
|
|
}
|
|
|
|
type UserChangeEmailSendCodeReq struct {
|
|
UserVerifyEmailSendReq
|
|
Email string `validate:"required,email,gt=0,lte=500" json:"e_mail"`
|
|
Pass string `validate:"omitempty,gte=8,lte=32" json:"pass"`
|
|
UserID string `json:"-"`
|
|
}
|
|
|
|
type UserChangeEmailVerifyReq struct {
|
|
Code string `validate:"required,gt=0,lte=500" json:"code"`
|
|
Content string `json:"-"`
|
|
}
|
|
|
|
type UserVerifyEmailSendReq struct {
|
|
CaptchaID string `json:"captcha_id"`
|
|
CaptchaCode string `json:"captcha_code"`
|
|
}
|
|
|
|
// UserRankingResp user ranking response
|
|
type UserRankingResp struct {
|
|
UsersWithTheMostReputation []*UserRankingSimpleInfo `json:"users_with_the_most_reputation"`
|
|
UsersWithTheMostVote []*UserRankingSimpleInfo `json:"users_with_the_most_vote"`
|
|
Staffs []*UserRankingSimpleInfo `json:"staffs"`
|
|
}
|
|
|
|
// UserRankingSimpleInfo user ranking simple info
|
|
type UserRankingSimpleInfo struct {
|
|
// username
|
|
Username string `json:"username"`
|
|
// rank
|
|
Rank int `json:"rank"`
|
|
// vote
|
|
VoteCount int `json:"vote_count"`
|
|
// display name
|
|
DisplayName string `json:"display_name"`
|
|
// avatar
|
|
Avatar string `json:"avatar"`
|
|
}
|
|
|
|
// UserUnsubscribeNotificationReq user unsubscribe email notification request
|
|
type UserUnsubscribeNotificationReq struct {
|
|
Code string `validate:"required,gt=0,lte=500" json:"code"`
|
|
Content string `json:"-"`
|
|
}
|
|
|
|
// GetUserStaffReq get user staff request
|
|
type GetUserStaffReq struct {
|
|
Username string `validate:"omitempty,gt=0,lte=500" form:"username"`
|
|
PageSize int `validate:"omitempty,min=1" form:"page_size"`
|
|
}
|
|
|
|
// GetUserStaffResp get user staff response
|
|
type GetUserStaffResp struct {
|
|
// username
|
|
Username string `json:"username"`
|
|
// display name
|
|
DisplayName string `json:"display_name"`
|
|
// avatar
|
|
Avatar string `json:"avatar"`
|
|
}
|