From 89e7f1a41ac8233ddaf72dce1e6851638a66a6ed Mon Sep 17 00:00:00 2001 From: Asai Neko Date: Wed, 28 Jan 2026 18:19:24 +0800 Subject: [PATCH] WIP: Restructing auth api and service Signed-off-by: Asai Neko --- api/auth/exchange.go | 0 api/auth/magic.go | 0 api/auth/redirect.go | 0 api/auth/refresh.go | 0 api/auth/token.go | 0 api/user/full.go | 4 +- api/user/handler.go | 6 +- api/user/info.go | 4 +- api/user/list.go | 4 +- api/user/update.go | 4 +- service/auth/exchange.go | 124 ----- service/auth/handler.go | 15 - service/auth/redirect.go | 170 ------- service/auth/refresh.go | 75 --- service/auth/token.go | 94 ---- service/event/checkin.go | 207 -------- service/event/create.go | 1 - service/event/handler.go | 15 - service/event/info.go | 71 --- service/event/list.go | 1 - service/event/update.go | 1 - service/service_auth/exchange.go | 129 +++++ service/{auth => service_auth}/magic.go | 147 ++++-- service/service_auth/redirect.go | 27 ++ service/service_auth/service.go | 12 + service/service_user/create_user.go | 3 + service/service_user/get_user_info.go | 94 ++++ service/service_user/list_user_full_table.go | 65 +++ service/service_user/list_users.go | 138 ++++++ service/service_user/service.go | 15 + service/service_user/update_user_info.go | 177 +++++++ service/{ => shared}/common.go | 2 +- service/user.go | 469 ------------------- 33 files changed, 773 insertions(+), 1301 deletions(-) create mode 100644 api/auth/exchange.go create mode 100644 api/auth/magic.go create mode 100644 api/auth/redirect.go create mode 100644 api/auth/refresh.go create mode 100644 api/auth/token.go delete mode 100644 service/auth/exchange.go delete mode 100644 service/auth/handler.go delete mode 100644 service/auth/redirect.go delete mode 100644 service/auth/refresh.go delete mode 100644 service/auth/token.go delete mode 100644 service/event/checkin.go delete mode 100644 service/event/create.go delete mode 100644 service/event/handler.go delete mode 100644 service/event/info.go delete mode 100644 service/event/list.go delete mode 100644 service/event/update.go create mode 100644 service/service_auth/exchange.go rename service/{auth => service_auth}/magic.go (52%) create mode 100644 service/service_auth/redirect.go create mode 100644 service/service_auth/service.go create mode 100644 service/service_user/create_user.go create mode 100644 service/service_user/get_user_info.go create mode 100644 service/service_user/list_user_full_table.go create mode 100644 service/service_user/list_users.go create mode 100644 service/service_user/service.go create mode 100644 service/service_user/update_user_info.go rename service/{ => shared}/common.go (87%) delete mode 100644 service/user.go diff --git a/api/auth/exchange.go b/api/auth/exchange.go new file mode 100644 index 0000000..e69de29 diff --git a/api/auth/magic.go b/api/auth/magic.go new file mode 100644 index 0000000..e69de29 diff --git a/api/auth/redirect.go b/api/auth/redirect.go new file mode 100644 index 0000000..e69de29 diff --git a/api/auth/refresh.go b/api/auth/refresh.go new file mode 100644 index 0000000..e69de29 diff --git a/api/auth/token.go b/api/auth/token.go new file mode 100644 index 0000000..e69de29 diff --git a/api/user/full.go b/api/user/full.go index 5c434af..a89c6cc 100644 --- a/api/user/full.go +++ b/api/user/full.go @@ -2,14 +2,14 @@ package user import ( "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "nixcn-cms/utils" "github.com/gin-gonic/gin" ) func (self *UserHandler) Full(c *gin.Context) { - userTablePayload := &service.UserTablePayload{ + userTablePayload := &service_user.UserTablePayload{ Context: c, } diff --git a/api/user/handler.go b/api/user/handler.go index 1d2ac0f..0ccd3e5 100644 --- a/api/user/handler.go +++ b/api/user/handler.go @@ -2,17 +2,17 @@ package user import ( "nixcn-cms/middleware" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "github.com/gin-gonic/gin" ) type UserHandler struct { - svc service.UserService + svc service_user.UserService } func ApiHandler(r *gin.RouterGroup) { - userSvc := service.NewUserService() + userSvc := service_user.NewUserService() userHandler := &UserHandler{userSvc} r.Use(middleware.ApiVersionCheck(), middleware.JWTAuth(), middleware.Permission(5)) diff --git a/api/user/info.go b/api/user/info.go index 2e506e8..bb8cc0a 100644 --- a/api/user/info.go +++ b/api/user/info.go @@ -2,7 +2,7 @@ package user import ( "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "nixcn-cms/utils" "github.com/gin-gonic/gin" @@ -39,7 +39,7 @@ func (self *UserHandler) Info(c *gin.Context) { return } - UserInfoPayload := &service.UserInfoPayload{ + UserInfoPayload := &service_user.UserInfoPayload{ Context: c, UserId: userId, Data: nil, diff --git a/api/user/list.go b/api/user/list.go index 0c4eeee..f4fce52 100644 --- a/api/user/list.go +++ b/api/user/list.go @@ -2,7 +2,7 @@ package user import ( "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "nixcn-cms/utils" "github.com/gin-gonic/gin" @@ -29,7 +29,7 @@ func (self *UserHandler) List(c *gin.Context) { return } - userListPayload := &service.UserListPayload{ + userListPayload := &service_user.UserListPayload{ Context: c, Limit: query.Limit, Offset: query.Offset, diff --git a/api/user/update.go b/api/user/update.go index 18ab94a..9382774 100644 --- a/api/user/update.go +++ b/api/user/update.go @@ -2,7 +2,7 @@ package user import ( "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "nixcn-cms/utils" "github.com/gin-gonic/gin" @@ -38,7 +38,7 @@ func (self *UserHandler) Update(c *gin.Context) { return } - userInfoPayload := &service.UserInfoPayload{ + userInfoPayload := &service_user.UserInfoPayload{ Context: c, UserId: userId, } diff --git a/service/auth/exchange.go b/service/auth/exchange.go deleted file mode 100644 index 89fe02e..0000000 --- a/service/auth/exchange.go +++ /dev/null @@ -1,124 +0,0 @@ -package auth - -import ( - "fmt" - "net/url" - "nixcn-cms/data" - "nixcn-cms/internal/exception" - "nixcn-cms/pkgs/authcode" - "nixcn-cms/utils" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" -) - -const () - -func Exchange(c *gin.Context) { - var exchangeReq struct { - ClientId string `json:"client_id"` - RedirectUri string `json:"redirect_uri"` - State string `json:"state"` - } - - err := c.ShouldBindJSON(&exchangeReq) - if err != nil { - fmt.Println(err) - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - userIdOrig, ok := c.Get("user_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUnauthorized). - Build(c) - utils.HttpResponse(c, 401, errorCode) - return - } - - userId, err := uuid.Parse(userIdOrig.(string)) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - userData := new(data.User) - user, err := userData.GetByUserId(c, userId) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthExchangeGetUserIdFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - code, err := authcode.NewAuthCode(c, exchangeReq.ClientId, user.Email) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthExchangeCodeGenFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - url, err := url.Parse(exchangeReq.RedirectUri) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthExchangeInvalidRedirectUri). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - query := url.Query() - query.Set("code", code) - url.RawQuery = query.Encode() - - exchangeResp := struct { - RedirectUri string `json:"redirect_uri"` - }{url.String()} - - errorCode := new(exception.Builder). - SetStatus(exception.StatusSuccess). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceExchange). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode, exchangeResp) -} diff --git a/service/auth/handler.go b/service/auth/handler.go deleted file mode 100644 index a421d6d..0000000 --- a/service/auth/handler.go +++ /dev/null @@ -1,15 +0,0 @@ -package auth - -import ( - "nixcn-cms/middleware" - - "github.com/gin-gonic/gin" -) - -func Handler(r *gin.RouterGroup) { - r.GET("/redirect", Redirect) - r.POST("/magic", middleware.ApiVersionCheck(), Magic) - r.POST("/token", middleware.ApiVersionCheck(), Token) - r.POST("/refresh", middleware.ApiVersionCheck(), Refresh) - r.POST("/exchange", middleware.ApiVersionCheck(), middleware.JWTAuth(), Exchange) -} diff --git a/service/auth/redirect.go b/service/auth/redirect.go deleted file mode 100644 index 67a5e33..0000000 --- a/service/auth/redirect.go +++ /dev/null @@ -1,170 +0,0 @@ -package auth - -import ( - "net/url" - "nixcn-cms/data" - "nixcn-cms/internal/exception" - "nixcn-cms/pkgs/authcode" - "nixcn-cms/utils" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "gorm.io/gorm" -) - -func Redirect(c *gin.Context) { - clientId := c.Query("client_id") - if clientId == "" { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - redirectUri := c.Query("redirect_uri") - if redirectUri == "" { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - state := c.Query("state") - if state == "" { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - code := c.Query("code") - - // Verify email token - authCode, ok := authcode.VerifyAuthCode(c, code) - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRedirectTokenInvalid). - Build(c) - utils.HttpResponse(c, 403, errorCode) - return - } - - // Verify if user exists - userData := new(data.User) - user, err := userData.GetByEmail(c, authCode.Email) - - if err != nil { - if err == gorm.ErrRecordNotFound { - // Create user - user.UUID = uuid.New() - user.UserId = uuid.New() - user.Email = authCode.Email - user.Username = user.UserId.String() - user.PermissionLevel = 10 - if err := user.Create(c); err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInternal). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - } else { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInternal). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - } - - clientData := new(data.Client) - client, err := clientData.GetClientByClientId(c, clientId) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRedirectClientNotFound). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - err = client.ValidateRedirectURI(redirectUri) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRedirectUriMismatch). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - newCode, err := authcode.NewAuthCode(c, clientId, authCode.Email) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInternal). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - url, err := url.Parse(redirectUri) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRedirect). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRedirectInvalidUri). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - query := url.Query() - query.Set("code", newCode) - url.RawQuery = query.Encode() - - c.Redirect(302, url.String()) -} diff --git a/service/auth/refresh.go b/service/auth/refresh.go deleted file mode 100644 index 248fd05..0000000 --- a/service/auth/refresh.go +++ /dev/null @@ -1,75 +0,0 @@ -package auth - -import ( - "nixcn-cms/internal/exception" - "nixcn-cms/pkgs/authtoken" - "nixcn-cms/utils" - - "github.com/gin-gonic/gin" - "github.com/spf13/viper" -) - -func Refresh(c *gin.Context) { - var req struct { - RefreshToken string `json:"refresh_token"` - } - - if err := c.ShouldBindJSON(&req); err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRefresh). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - JwtTool := authtoken.Token{ - Application: viper.GetString("server.application"), - } - - accessToken, err := JwtTool.RefreshAccessToken(c, req.RefreshToken) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRefresh). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRefreshInvalidToken). - SetError(err). - Build(c) - utils.HttpResponse(c, 401, errorCode) - return - } - - refreshToken, err := JwtTool.RenewRefreshToken(c, req.RefreshToken) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRefresh). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthRefreshRenewFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - tokenResp := struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - }{accessToken, refreshToken} - - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceRefresh). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode, tokenResp) -} diff --git a/service/auth/token.go b/service/auth/token.go deleted file mode 100644 index a050496..0000000 --- a/service/auth/token.go +++ /dev/null @@ -1,94 +0,0 @@ -package auth - -import ( - "nixcn-cms/data" - "nixcn-cms/internal/exception" - "nixcn-cms/pkgs/authcode" - "nixcn-cms/pkgs/authtoken" - "nixcn-cms/utils" - - "github.com/gin-gonic/gin" - "github.com/spf13/viper" -) - -type TokenRequest struct { - Code string `json:"code"` -} - -func Token(c *gin.Context) { - var req TokenRequest - - err := c.ShouldBindJSON(&req) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceToken). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - authCode, ok := authcode.VerifyAuthCode(c, req.Code) - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceToken). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthTokenInvalidToken). - Build(c) - utils.HttpResponse(c, 403, errorCode) - return - } - - userData := new(data.User) - user, err := userData.GetByEmail(c, authCode.Email) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceToken). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInternal). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - // Generate jwt - JwtTool := authtoken.Token{ - Application: viper.GetString("server.application"), - } - accessToken, refreshToken, err := JwtTool.IssueTokens(c, authCode.ClientId, user.UserId) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceToken). - SetType(exception.TypeSpecific). - SetOriginal(exception.AuthTokenGenFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - tokenResp := struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - }{accessToken, refreshToken} - - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceToken). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode, tokenResp) -} diff --git a/service/event/checkin.go b/service/event/checkin.go deleted file mode 100644 index 5205c62..0000000 --- a/service/event/checkin.go +++ /dev/null @@ -1,207 +0,0 @@ -package event - -import ( - "nixcn-cms/data" - "nixcn-cms/internal/exception" - "nixcn-cms/utils" - "time" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" -) - -func Checkin(c *gin.Context) { - data := new(data.Attendance) - userIdOrig, ok := c.Get("user_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckin). - 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.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckin). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - } - - // Get event id from query - eventIdOrig, ok := c.GetQuery("event_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckin). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - // Parse event id to uuid - eventId, err := uuid.Parse(eventIdOrig) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckin). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - data.UserId = userId - code, err := data.GenCheckinCode(c, eventId) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckin). - SetType(exception.TypeSpecific). - SetOriginal(exception.EventCheckinGenCodeFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - checkinCodeResp := struct { - CheckinCode *string `json:"checkin_code"` - }{code} - utils.HttpResponse(c, 200, "", "success", checkinCodeResp) -} - -func CheckinSubmit(c *gin.Context) { - var req struct { - ChekinCode string `json:"checkin_code"` - } - c.ShouldBindJSON(&req) - - attendanceData := new(data.Attendance) - err := attendanceData.VerifyCheckinCode(c, req.ChekinCode) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinSubmit). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - utils.HttpResponse(c, 200, "", "success") -} - -func CheckinQuery(c *gin.Context) { - userIdOrig, ok := c.Get("user_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorMissingUserId). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - userId, err := uuid.Parse(userIdOrig.(string)) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - eventIdOrig, ok := c.GetQuery("event_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - eventId, err := uuid.Parse(eventIdOrig) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - attendanceData := new(data.Attendance) - attendance, err := attendanceData.GetAttendance(c, userId, eventId) - - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorDatabase). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } else if attendance == nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeSpecific). - SetOriginal(exception.EventCheckinQueryRecordNotFound). - Build(c) - utils.HttpResponse(c, 404, errorCode) - return - } else if attendance.CheckinAt.IsZero() { - utils.HttpResponse(c, 200, "", "success", gin.H{"checkin_at": nil}) - return - } - - checkInAtResp := struct { - CheckinAt time.Time `json:"checkin_at"` - }{attendance.CheckinAt} - - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceCheckinQuery). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode, checkInAtResp) -} diff --git a/service/event/create.go b/service/event/create.go deleted file mode 100644 index 0e4b82e..0000000 --- a/service/event/create.go +++ /dev/null @@ -1 +0,0 @@ -package event diff --git a/service/event/handler.go b/service/event/handler.go deleted file mode 100644 index 875c9f3..0000000 --- a/service/event/handler.go +++ /dev/null @@ -1,15 +0,0 @@ -package event - -import ( - "nixcn-cms/middleware" - - "github.com/gin-gonic/gin" -) - -func Handler(r *gin.RouterGroup) { - r.Use(middleware.JWTAuth(), middleware.Permission(10)) - r.GET("/info", Info) - r.GET("/checkin", Checkin) - r.GET("/checkin/query", CheckinQuery) - r.POST("/checkin/submit", middleware.Permission(20), CheckinSubmit) -} diff --git a/service/event/info.go b/service/event/info.go deleted file mode 100644 index 351de99..0000000 --- a/service/event/info.go +++ /dev/null @@ -1,71 +0,0 @@ -package event - -import ( - "nixcn-cms/data" - "nixcn-cms/internal/exception" - "nixcn-cms/utils" - "time" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" -) - -func Info(c *gin.Context) { - eventData := new(data.Event) - eventIdOrig, ok := c.GetQuery("event_id") - if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceInfo). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } - - // Parse event id - eventId, err := uuid.Parse(eventIdOrig) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceInfo). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) - return - } - - event, err := eventData.GetEventById(c, eventId) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceInfo). - SetType(exception.TypeSpecific). - SetOriginal(exception.EventInfoNotFound). - SetError(err). - Build(c) - utils.HttpResponse(c, 404, errorCode) - return - } - - eventInfoResp := struct { - Name string `json:"name"` - StartTime time.Time `json:"start_time"` - EndTime time.Time `json:"end_time"` - }{event.Name, event.StartTime, event.EndTime} - - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceEvent). - SetEndpoint(exception.EndpointEventServiceInfo). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode, eventInfoResp) -} diff --git a/service/event/list.go b/service/event/list.go deleted file mode 100644 index 0e4b82e..0000000 --- a/service/event/list.go +++ /dev/null @@ -1 +0,0 @@ -package event diff --git a/service/event/update.go b/service/event/update.go deleted file mode 100644 index 0e4b82e..0000000 --- a/service/event/update.go +++ /dev/null @@ -1 +0,0 @@ -package event diff --git a/service/service_auth/exchange.go b/service/service_auth/exchange.go new file mode 100644 index 0000000..b4396ee --- /dev/null +++ b/service/service_auth/exchange.go @@ -0,0 +1,129 @@ +package service_auth + +import ( + "context" + "net/url" + "nixcn-cms/data" + "nixcn-cms/internal/authcode" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + + "github.com/google/uuid" +) + +type ExchangeData struct { + ClientId string `json:"client_id"` + RedirectUri string `json:"redirect_uri"` + State string `json:"state"` +} + +type ExchangePayload struct { + Context context.Context + UserId uuid.UUID + Data *ExchangeData +} + +type ExchangeResult struct { + Common shared.CommonResult + Data *struct { + RedirectUri string `json:"redirect_uri"` + } +} + +func (self *AuthServiceImpl) Exchange(payload *ExchangePayload) (result *ExchangeResult) { + var err error + + userData, err := new(data.User). + GetByUserId(payload.Context, &payload.UserId) + if err != nil { + exception := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceAuth). + SetEndpoint(exception.EndpointAuthServiceExchange). + SetType(exception.TypeSpecific). + SetOriginal(exception.AuthExchangeGetUserIdFailed). + SetError(err). + Throw(payload.Context) + + result = &ExchangeResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + + return + } + + code, err := authcode.NewAuthCode(payload.Context, payload.Data.ClientId, userData.Email) + if err != nil { + exception := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceAuth). + SetEndpoint(exception.EndpointAuthServiceExchange). + SetType(exception.TypeSpecific). + SetOriginal(exception.AuthExchangeCodeGenFailed). + SetError(err). + Throw(payload.Context) + + result = &ExchangeResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + + return + } + + url, err := url.Parse(payload.Data.RedirectUri) + if err != nil { + exception := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceAuth). + SetEndpoint(exception.EndpointAuthServiceExchange). + SetType(exception.TypeSpecific). + SetOriginal(exception.AuthExchangeInvalidRedirectUri). + SetError(err). + Throw(payload.Context) + + result = &ExchangeResult{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: exception, + }, + Data: nil, + } + + return + } + + query := url.Query() + query.Set("code", code) + url.RawQuery = query.Encode() + + exception := new(exception.Builder). + SetStatus(exception.StatusSuccess). + SetService(exception.ServiceAuth). + SetEndpoint(exception.EndpointAuthServiceExchange). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonSuccess). + SetError(nil). + Throw(payload.Context) + + resultData := struct { + RedirectUri string `json:"redirect_uri"` + }{url.String()} + + result = &ExchangeResult{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: &resultData, + } + + return +} diff --git a/service/auth/magic.go b/service/service_auth/magic.go similarity index 52% rename from service/auth/magic.go rename to service/service_auth/magic.go index a5a7568..15a6e2c 100644 --- a/service/auth/magic.go +++ b/service/service_auth/magic.go @@ -1,91 +1,112 @@ -package auth +package service_auth import ( + "context" "net/url" + "nixcn-cms/internal/authcode" + "nixcn-cms/internal/email" "nixcn-cms/internal/exception" - "nixcn-cms/pkgs/authcode" - "nixcn-cms/pkgs/email" - "nixcn-cms/pkgs/turnstile" - "nixcn-cms/utils" + "nixcn-cms/internal/turnstile" + "nixcn-cms/service/shared" - "github.com/gin-gonic/gin" "github.com/spf13/viper" ) -type MagicRequest struct { +type MagicData struct { ClientId string `json:"client_id"` RedirectUri string `json:"redirect_uri"` State string `json:"state"` Email string `json:"email"` TurnstileToken string `json:"turnstile_token"` + ClientIP string `json:"client_ip"` } -func Magic(c *gin.Context) { - // Parse request - var req MagicRequest - if err := c.ShouldBindJSON(&req); err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceAuth). - SetEndpoint(exception.EndpointAuthServiceMagic). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Build(c) - utils.HttpResponse(c, 400, errorCode) - return - } +type MagicPayload struct { + Context context.Context + Data *MagicData +} - // Cloudflare turnstile - ok, err := turnstile.VerifyTurnstile(req.TurnstileToken, c.ClientIP()) +type MagicResult struct { + Common shared.CommonResult + Data any +} + +func (self *AuthServiceImpl) Magic(payload *MagicPayload) (result *MagicResult) { + var err error + + ok, err := turnstile.VerifyTurnstile(payload.Data.TurnstileToken, payload.Data.ClientIP) if err != nil || !ok { - errorCode := new(exception.Builder). + exception := new(exception.Builder). SetStatus(exception.StatusUser). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicTurnstileFailed). SetError(err). - Build(c) - utils.HttpResponse(c, 403, errorCode) + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 403, + Exception: exception, + }, + Data: nil, + } + return } - code, err := authcode.NewAuthCode(c, req.ClientId, req.Email) + code, err := authcode.NewAuthCode(payload.Context, payload.Data.ClientId, payload.Data.Email) if err != nil { - errorCode := new(exception.Builder). + exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicCodeGenFailed). SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + return } externalUrl := viper.GetString("server.external_url") url, err := url.Parse(externalUrl) if err != nil { - errorCode := new(exception.Builder). + exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicInvalidExternalUrl). SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + return } url.Path = "/api/v1/auth/redirect" query := url.Query() query.Set("code", code) - query.Set("redirect_uri", req.RedirectUri) - query.Set("state", req.State) - query.Set("client_id", req.ClientId) + query.Set("redirect_uri", payload.Data.RedirectUri) + query.Set("state", payload.Data.State) + query.Set("client_id", payload.Data.ClientId) url.RawQuery = query.Encode() debugMode := viper.GetBool("server.debug_mode") @@ -93,37 +114,71 @@ func Magic(c *gin.Context) { uriData := struct { Uri string `json:"uri"` }{url.String()} - utils.HttpResponse(c, 200, "", "magiclink sent", uriData) + + exception := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceAuth). + SetEndpoint(exception.EndpointAuthServiceMagic). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonSuccess). + SetError(nil). + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: uriData, + } + return } else { - // Send email using resend emailClient, err := new(email.Client).NewSMTPClient() if err != nil { - errorCode := new(exception.Builder). + exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicInvalidEmailConfig). SetError(err). - Build(c) - utils.HttpResponse(c, 500, errorCode) + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + return } emailClient.Send( "NixCN CMS ", - req.Email, + payload.Data.Email, "NixCN CMS Email Verify", "

Click the link below to verify your email. This link will expire in 10 minutes.

"+url.String()+"", ) } - errorCode := new(exception.Builder). + exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeCommon). SetOriginal(exception.CommonSuccess). - Build(c) - utils.HttpResponse(c, 200, errorCode) + SetError(nil). + Throw(payload.Context) + + result = &MagicResult{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: nil, + } + + return } diff --git a/service/service_auth/redirect.go b/service/service_auth/redirect.go new file mode 100644 index 0000000..4b612fb --- /dev/null +++ b/service/service_auth/redirect.go @@ -0,0 +1,27 @@ +package service_auth + +import ( + "context" + "nixcn-cms/service/shared" +) + +type RedirectData struct { + ClientId string `json:"client_id"` + RedirectUri string `json:"redirect_uri"` + State string `json:"state"` + Code string `json:"code"` +} + +type RedirectPayload struct { + Context context.Context + Data *RedirectData +} + +type RedirectResult struct { + Common shared.CommonResult + Data string +} + +func (self *AuthServiceImpl) Redirect(payload *RedirectPayload) (result *RedirectResult) { + +} diff --git a/service/service_auth/service.go b/service/service_auth/service.go new file mode 100644 index 0000000..423aa86 --- /dev/null +++ b/service/service_auth/service.go @@ -0,0 +1,12 @@ +package service_auth + +type AuthService interface { + Exchange(*ExchangePayload) *ExchangeResult + Magic(*MagicPayload) *MagicResult +} + +type AuthServiceImpl struct{} + +func NewAuthService() AuthService { + return &AuthServiceImpl{} +} diff --git a/service/service_user/create_user.go b/service/service_user/create_user.go new file mode 100644 index 0000000..3da2552 --- /dev/null +++ b/service/service_user/create_user.go @@ -0,0 +1,3 @@ +package service_user + +func (self *UserServiceImpl) CreateUser() {} diff --git a/service/service_user/get_user_info.go b/service/service_user/get_user_info.go new file mode 100644 index 0000000..c60e3d4 --- /dev/null +++ b/service/service_user/get_user_info.go @@ -0,0 +1,94 @@ +package service_user + +import ( + "context" + "nixcn-cms/data" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + + "github.com/google/uuid" +) + +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 { + Common shared.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{ + Common: shared.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{ + Common: shared.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 +} diff --git a/service/service_user/list_user_full_table.go b/service/service_user/list_user_full_table.go new file mode 100644 index 0000000..f27bd65 --- /dev/null +++ b/service/service_user/list_user_full_table.go @@ -0,0 +1,65 @@ +package service_user + +import ( + "context" + "nixcn-cms/data" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" +) + +type UserTablePayload struct { + Context context.Context +} + +type UserTableResult struct { + Common shared.CommonResult + Data *[]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{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: 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{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: userFullTable, + } + + return +} diff --git a/service/service_user/list_users.go b/service/service_user/list_users.go new file mode 100644 index 0000000..4001cf4 --- /dev/null +++ b/service/service_user/list_users.go @@ -0,0 +1,138 @@ +package service_user + +import ( + "context" + "nixcn-cms/data" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + "strconv" +) + +type UserListPayload struct { + Context context.Context + Limit *string + Offset *string +} + +type UserListResult struct { + Common shared.CommonResult + Data *[]data.UserSearchDoc `json:"user_list"` +} + +func (self *UserServiceImpl) ListUsers(payload *UserListPayload) (result *UserListResult) { + var limit string + if payload.Limit == nil || *payload.Limit == "" { + limit = "0" + } + + var offset string + if payload.Offset == nil || *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{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: exception, + }, + Data: 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: exception, + }, + Data: 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{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: 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{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: userList, + } + + return + +} diff --git a/service/service_user/service.go b/service/service_user/service.go new file mode 100644 index 0000000..5b39ed3 --- /dev/null +++ b/service/service_user/service.go @@ -0,0 +1,15 @@ +package service_user + +type UserService interface { + GetUserInfo(*UserInfoPayload) *UserInfoResult + UpdateUserInfo(*UserInfoPayload) *UserInfoResult + ListUsers(*UserListPayload) *UserListResult + GetUserFullTable(*UserTablePayload) *UserTableResult + CreateUser() +} + +type UserServiceImpl struct{} + +func NewUserService() UserService { + return &UserServiceImpl{} +} diff --git a/service/service_user/update_user_info.go b/service/service_user/update_user_info.go new file mode 100644 index 0000000..25b7bc0 --- /dev/null +++ b/service/service_user/update_user_info.go @@ -0,0 +1,177 @@ +package service_user + +import ( + "net/url" + "nixcn-cms/data" + "nixcn-cms/internal/cryptography" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + "unicode/utf8" +) + +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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: execption, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: execption, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: execption, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: execption, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: execption, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + + 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{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: exception, + }, + Data: nil, + } + + return +} diff --git a/service/common.go b/service/shared/common.go similarity index 87% rename from service/common.go rename to service/shared/common.go index cb41d95..2dc0c5c 100644 --- a/service/common.go +++ b/service/shared/common.go @@ -1,4 +1,4 @@ -package service +package shared import "nixcn-cms/internal/exception" diff --git a/service/user.go b/service/user.go deleted file mode 100644 index 626881c..0000000 --- a/service/user.go +++ /dev/null @@ -1,469 +0,0 @@ -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 { - Common 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{ - Common: 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{ - Common: 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: execption, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: execption, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: execption, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: execption, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: execption, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 500, - Exception: exception, - }, - Data: nil, - } - - 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{ - Common: CommonResult{ - HttpCode: 200, - Exception: exception, - }, - Data: nil, - } - - return -} - -type UserListPayload struct { - Context context.Context - Limit *string - Offset *string -} - -type UserListResult struct { - Common CommonResult - Data *[]data.UserSearchDoc `json:"user_list"` -} - -// ListUsers -func (self *UserServiceImpl) ListUsers(payload *UserListPayload) (result *UserListResult) { - var limit string - if payload.Limit == nil || *payload.Limit == "" { - limit = "0" - } - - var offset string - if payload.Offset == nil || *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{ - Common: CommonResult{ - HttpCode: 500, - Exception: exception, - }, - Data: 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: exception, - }, - Data: 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{ - Common: CommonResult{ - HttpCode: 400, - Exception: exception, - }, - Data: 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{ - Common: CommonResult{ - HttpCode: 500, - Exception: exception, - }, - Data: 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{ - Common: CommonResult{ - HttpCode: 200, - Exception: exception, - }, - Data: userList, - } - - return - -} - -type UserTablePayload struct { - Context context.Context -} - -type UserTableResult struct { - Common CommonResult - Data *[]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{ - Common: CommonResult{ - HttpCode: 500, - Exception: exception, - }, - Data: 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{ - Common: CommonResult{ - HttpCode: 200, - Exception: exception, - }, - Data: userFullTable, - } - - return -} - -// CreateUser -func (self *UserServiceImpl) CreateUser() {}