WIP: Full restruct, seprate service and api

Signed-off-by: Asai Neko <sugar@sne.moe>
This commit is contained in:
2026-01-24 11:42:35 +08:00
parent dfd5532b20
commit 8e11ba4631
31 changed files with 830 additions and 248 deletions

8
service/common.go Normal file
View File

@@ -0,0 +1,8 @@
package service
import "nixcn-cms/internal/exception"
type CommonResult struct {
HttpCode int
Exception *exception.Builder
}

465
service/user.go Normal file
View File

@@ -0,0 +1,465 @@
package service
import (
"context"
"net/url"
"nixcn-cms/data"
"nixcn-cms/internal/cryptography"
"nixcn-cms/internal/exception"
"strconv"
"unicode/utf8"
"github.com/google/uuid"
)
type UserService interface {
GetUserInfo(*UserInfoPayload) *UserInfoResult
UpdateUserInfo(*UserInfoPayload) *UserInfoResult
ListUsers(*UserListPayload) *UserListResult
GetUserFullTable(*UserTablePayload) *UserTableResult
CreateUser()
}
type UserServiceImpl struct{}
func NewUserService() UserService {
return &UserServiceImpl{}
}
type UserInfoData struct {
UserId uuid.UUID `json:"user_id"`
Email string `json:"email"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Subtitle string `json:"subtitle"`
Avatar string `json:"avatar"`
Bio string `json:"bio"`
PermissionLevel uint `json:"permission_level"`
AllowPublic bool `json:"allow_public"`
}
type UserInfoPayload struct {
Context *context.Context
UserId *uuid.UUID
Data *UserInfoData
}
type UserInfoResult struct {
*CommonResult
Data *UserInfoData
}
// GetUserInfo
func (self *UserServiceImpl) GetUserInfo(payload *UserInfoPayload) (result *UserInfoResult) {
var err error
userData, err := new(data.User).
GetByUserId(
payload.Context,
payload.UserId,
)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorUserNotFound).
SetError(err).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 404,
Exception: exception,
},
Data: nil,
}
return
}
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
SetError(nil).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 200,
Exception: exception,
},
Data: &UserInfoData{
UserId: userData.UserId,
Email: userData.Email,
Username: userData.Username,
Nickname: userData.Nickname,
Subtitle: userData.Subtitle,
Avatar: userData.Avatar,
Bio: userData.Bio,
PermissionLevel: userData.PermissionLevel,
AllowPublic: userData.AllowPublic,
},
}
return
}
// UpdateUserInfo
func (self *UserServiceImpl) UpdateUserInfo(payload *UserInfoPayload) (result *UserInfoResult) {
var err error
userData := new(data.User).
SetNickname(payload.Data.Nickname).
SetSubtitle(payload.Data.Subtitle).
SetAvatar(payload.Data.Avatar).
SetBio(payload.Data.Bio).
SetAllowPublic(payload.Data.AllowPublic)
if payload.Data.Username != "" {
if len(payload.Data.Username) < 5 || len(payload.Data.Username) >= 255 {
execption := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: execption,
},
}
return
}
userData.SetUsername(payload.Data.Username)
}
if payload.Data.Nickname != "" {
if utf8.RuneCountInString(payload.Data.Nickname) > 24 {
execption := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: execption,
},
}
return
}
userData.SetNickname(payload.Data.Nickname)
}
if payload.Data.Subtitle != "" {
if utf8.RuneCountInString(payload.Data.Subtitle) > 32 {
execption := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(nil).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: execption,
},
}
return
}
userData.SetSubtitle(payload.Data.Subtitle)
}
if payload.Data.Avatar != "" {
_, err := url.ParseRequestURI(payload.Data.Avatar)
if err != nil {
execption := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(err).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: execption,
},
}
return
}
userData.SetAvatar(payload.Data.Avatar)
}
if payload.Data.Bio != "" {
if !cryptography.IsBase64Std(payload.Data.Bio) {
execption := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(nil).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: execption,
},
}
return
}
userData.Bio = payload.Data.Bio
}
err = userData.UpdateByUserID(payload.Context, payload.UserId)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorDatabase).
SetError(err).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 500,
Exception: exception,
},
}
return
}
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
SetError(nil).
Throw(payload.Context)
result = &UserInfoResult{
CommonResult: &CommonResult{
HttpCode: 200,
Exception: exception,
},
Data: nil,
}
return
}
type UserListPayload struct {
Context *context.Context
Limit *string
LimitStatus *bool
Offset *string
OffsetStatus *bool
}
type UserListResult struct {
*CommonResult
UserList *[]data.UserSearchDoc `json:"user_list"`
}
// ListUsers
func (self *UserServiceImpl) ListUsers(payload *UserListPayload) (result *UserListResult) {
var limit string
if !*payload.LimitStatus || *payload.Limit == "" {
limit = "0"
}
var offset string
if !*payload.OffsetStatus || *payload.Offset == "" {
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceList).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(nil).
Throw(payload.Context)
result = &UserListResult{
CommonResult: &CommonResult{
HttpCode: 500,
Exception: exception,
},
UserList: nil,
}
return
} else {
offset = *payload.Offset
}
// Parse string to int64
limitNum, err := strconv.ParseInt(limit, 10, 64)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceList).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(err).
Throw(payload.Context)
result = &UserListResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: exception,
},
UserList: nil,
}
return
}
offsetNum, err := strconv.ParseInt(offset, 10, 64)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceList).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(err).
Throw(payload.Context)
result = &UserListResult{
CommonResult: &CommonResult{
HttpCode: 400,
Exception: exception,
},
UserList: nil,
}
return
}
// Get user list from search engine
userList, err := new(data.User).
FastListUsers(payload.Context, &limitNum, &offsetNum)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceList).
SetType(exception.TypeSpecific).
SetOriginal(exception.UserListMeilisearchFailed).
SetError(err).
Throw(payload.Context)
result = &UserListResult{
CommonResult: &CommonResult{
HttpCode: 500,
Exception: exception,
},
UserList: nil,
}
}
exception := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceList).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
SetError(nil).
Throw(payload.Context)
result = &UserListResult{
CommonResult: &CommonResult{
HttpCode: 200,
Exception: exception,
},
UserList: userList,
}
return
}
type UserTablePayload struct {
Context *context.Context
}
type UserTableResult struct {
*CommonResult
UserTable *[]data.User `json:"user_table"`
}
// ListUserFullTable
func (self *UserServiceImpl) GetUserFullTable(payload *UserTablePayload) (result *UserTableResult) {
var err error
userFullTable, err := new(data.User).
GetFullTable(payload.Context)
if err != nil {
exception := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceFull).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorDatabase).
SetError(err).
Throw(payload.Context)
result = &UserTableResult{
CommonResult: &CommonResult{
HttpCode: 500,
Exception: exception,
},
UserTable: nil,
}
return
}
exception := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceFull).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
SetError(nil).
Throw(payload.Context)
result = &UserTableResult{
CommonResult: &CommonResult{
HttpCode: 200,
Exception: exception,
},
UserTable: userFullTable,
}
return
}
// CreateUser
func (self *UserServiceImpl) CreateUser() {}

View File

@@ -1,7 +0,0 @@
package user
import "github.com/gin-gonic/gin"
func Create(c *gin.Context) {
}

View File

@@ -1,15 +1,18 @@
package user
import (
"context"
"nixcn-cms/data"
"nixcn-cms/internal/exception"
"nixcn-cms/utils"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func Full(c *gin.Context) {
type ServiceFullResponse struct {
}
func ServiceFull(ctx context.Context, userId uuid.UUID) (data *[]data.User, httpCode int, errorCode string) {
userIdOrig, ok := c.Get("user_id")
if !ok {
errorCode := new(exception.Builder).

View File

@@ -1,16 +0,0 @@
package user
import (
"nixcn-cms/middleware"
"github.com/gin-gonic/gin"
)
func Handler(r *gin.RouterGroup) {
r.Use(middleware.JWTAuth(), middleware.Permission(5))
r.GET("/info", Info)
r.PATCH("/update", Update)
r.GET("/list", middleware.Permission(20), List)
r.POST("/full", middleware.Permission(40), Full)
r.POST("/create", middleware.Permission(50), Create)
}

View File

@@ -1,74 +1,51 @@
package user
import (
"nixcn-cms/data"
"nixcn-cms/internal/exception"
"nixcn-cms/utils"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func Info(c *gin.Context) {
userData := new(data.User)
userIdOrig, ok := c.Get("user_id")
if !ok {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorMissingUserId).
Build(c)
utils.HttpResponse(c, 403, errorCode)
return
}
userId, err := uuid.Parse(userIdOrig.(string))
if err != nil {
errorCode := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorUuidParseFailed).
SetError(err).
Build(c)
utils.HttpResponse(c, 500, errorCode)
return
}
// userData := new(data.User)
// userIdOrig, ok := c.Get("user_id")
// if !ok {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceInfo).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorMissingUserId).
// Build(c)
// utils.HttpResponse(c, 403, errorCode)
// return
// }
// userId, err := uuid.Parse(userIdOrig.(string))
// if err != nil {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusServer).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceInfo).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorUuidParseFailed).
// SetError(err).
// Build(c)
// utils.HttpResponse(c, 500, errorCode)
// return
// }
// Get user from database
user, err := userData.GetByUserId(c, userId)
if err != nil {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorUserNotFound).
SetError(err).
Build(c)
utils.HttpResponse(c, 404, errorCode)
return
}
// user, err := userData.GetByUserId(c, userId)
// if err != nil {
// utils.HttpResponse(c, 404, errorCode)
// return
// }
userInfoResp := struct {
UserId uuid.UUID `json:"user_id"`
Email string `json:"email"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Subtitle string `json:"subtitle"`
Avatar string `json:"avatar"`
Bio string `json:"bio"`
PermissionLevel uint `json:"permission_level"`
}{user.UserId, user.Email, user.Username, user.Nickname, user.Subtitle, user.Avatar, user.Bio, user.PermissionLevel}
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceInfo).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
Build(c)
utils.HttpResponse(c, 200, errorCode, userInfoResp)
}

View File

@@ -1,44 +1,40 @@
package user
import (
"net/url"
"nixcn-cms/data"
"nixcn-cms/internal/cryptography"
"nixcn-cms/internal/exception"
"nixcn-cms/utils"
"unicode/utf8"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func Update(c *gin.Context) {
// New user model
userIdOrig, ok := c.Get("user_id")
if !ok {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorMissingUserId).
Build(c)
utils.HttpResponse(c, 403, errorCode)
return
}
userId, err := uuid.Parse(userIdOrig.(string))
if err != nil {
errorCode := new(exception.Builder).
SetStatus(exception.StatusServer).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorUuidParseFailed).
SetError(err).
Build(c)
utils.HttpResponse(c, 500, errorCode)
return
}
// userIdOrig, ok := c.Get("user_id")
// if !ok {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorMissingUserId).
// Build(c)
// utils.HttpResponse(c, 403, errorCode)
// return
// }
// userId, err := uuid.Parse(userIdOrig.(string))
// if err != nil {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusServer).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorUuidParseFailed).
// SetError(err).
// Build(c)
// utils.HttpResponse(c, 500, errorCode)
// return
// }
var ReqInfo data.User
err = c.ShouldBindJSON(&ReqInfo)
@@ -79,92 +75,87 @@ func Update(c *gin.Context) {
// utils.HttpResponse(c, 400, "", "invilad user name")
// return
if ReqInfo.Username != "" {
if len(ReqInfo.Username) < 5 || len(ReqInfo.Username) >= 255 {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
Build(c)
utils.HttpResponse(c, 400, errorCode)
return
}
userData.Username = ReqInfo.Username
}
// if ReqInfo.Username != "" {
// if len(ReqInfo.Username) < 5 || len(ReqInfo.Username) >= 255 {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorInvalidInput).
// Build(c)
// utils.HttpResponse(c, 400, errorCode)
// return
// }
// userData.Username = ReqInfo.Username
// }
if ReqInfo.Nickname != "" {
if utf8.RuneCountInString(ReqInfo.Nickname) > 24 {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
Build(c)
utils.HttpResponse(c, 400, errorCode)
return
}
userData.Nickname = ReqInfo.Nickname
}
// if ReqInfo.Nickname != "" {
// if utf8.RuneCountInString(ReqInfo.Nickname) > 24 {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorInvalidInput).
// Build(c)
// utils.HttpResponse(c, 400, errorCode)
// return
// }
// userData.Nickname = ReqInfo.Nickname
// }
if ReqInfo.Subtitle != "" {
if utf8.RuneCountInString(ReqInfo.Subtitle) > 32 {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
Build(c)
utils.HttpResponse(c, 400, errorCode)
return
}
userData.Subtitle = ReqInfo.Subtitle
}
// if ReqInfo.Subtitle != "" {
// if utf8.RuneCountInString(ReqInfo.Subtitle) > 32 {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorInvalidInput).
// Build(c)
// utils.HttpResponse(c, 400, errorCode)
// return
// }
// userData.Subtitle = ReqInfo.Subtitle
// }
if ReqInfo.Avatar != "" {
_, err := url.ParseRequestURI(ReqInfo.Avatar)
if err != nil {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
SetError(err).
Build(c)
utils.HttpResponse(c, 400, errorCode)
return
}
userData.Avatar = ReqInfo.Avatar
}
// if ReqInfo.Avatar != "" {
// _, err := url.ParseRequestURI(ReqInfo.Avatar)
// if err != nil {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorInvalidInput).
// SetError(err).
// Build(c)
// utils.HttpResponse(c, 400, errorCode)
// return
// }
// userData.Avatar = ReqInfo.Avatar
// }
if ReqInfo.Bio != "" {
if !cryptography.IsBase64Std(ReqInfo.Bio) {
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonErrorInvalidInput).
Build(c)
utils.HttpResponse(c, 400, errorCode)
return
}
userData.Bio = ReqInfo.Bio
}
// if ReqInfo.Bio != "" {
// if !cryptography.IsBase64Std(ReqInfo.Bio) {
// errorCode := new(exception.Builder).
// SetStatus(exception.StatusUser).
// SetService(exception.ServiceUser).
// SetEndpoint(exception.EndpointUserServiceUpdate).
// SetType(exception.TypeCommon).
// SetOriginal(exception.CommonErrorInvalidInput).
// Build(c)
// utils.HttpResponse(c, 400, errorCode)
// return
// }
// userData.Bio = ReqInfo.Bio
// }
// Update user info
userData.UpdateByUserID(c, userId)
errorCode := new(exception.Builder).
SetStatus(exception.StatusUser).
SetService(exception.ServiceUser).
SetEndpoint(exception.EndpointUserServiceUpdate).
SetType(exception.TypeCommon).
SetOriginal(exception.CommonSuccess).
errorCode :=
Build(c)
utils.HttpResponse(c, 200, errorCode)
}