diff --git a/experiment/app/command/workspace.go b/experiment_module/app/command/workspace.go similarity index 92% rename from experiment/app/command/workspace.go rename to experiment_module/app/command/workspace.go index dea594a66324f661a88714f0185345be3fe5aace..8bb926235402085c36a3429ad88c108331ed855d 100644 --- a/experiment/app/command/workspace.go +++ b/experiment_module/app/command/workspace.go @@ -1,8 +1,8 @@ package command import ( - "octopus/experiment/dto" - "octopus/experiment/model/service" + "octopus/experiment_module/dto" + "octopus/experiment_module/model/service" "octopus/hextech/message" "github.com/gin-gonic/gin" diff --git a/experiment/conf/dev.yml b/experiment_module/conf/dev.yml similarity index 100% rename from experiment/conf/dev.yml rename to experiment_module/conf/dev.yml diff --git a/experiment/dto/workspace.go b/experiment_module/dto/workspace.go similarity index 100% rename from experiment/dto/workspace.go rename to experiment_module/dto/workspace.go diff --git a/experiment/infra/acl/convert/wokspace.go b/experiment_module/infra/acl/convert/wokspace.go similarity index 78% rename from experiment/infra/acl/convert/wokspace.go rename to experiment_module/infra/acl/convert/wokspace.go index 10b18b2977bbef4ce9c0a7c633057493c228ceb0..fdc37babe010476f0ede8cee0eceed1eea948243 100644 --- a/experiment/infra/acl/convert/wokspace.go +++ b/experiment_module/infra/acl/convert/wokspace.go @@ -2,9 +2,9 @@ package convert import ( "context" - "octopus/experiment/dto" - "octopus/experiment/infra/po" - "octopus/experiment/model/domain/workspace" + "octopus/experiment_module/dto" + "octopus/experiment_module/infra/po" + "octopus/experiment_module/model/domain/workspace" ) func WsCreateReqToWorkspace(ctx context.Context, req *dto.WorkSpaceCreateRequest) *workspace.WorkSpace { diff --git a/experiment/infra/db/workspace.sql b/experiment_module/infra/db/workspace.sql similarity index 100% rename from experiment/infra/db/workspace.sql rename to experiment_module/infra/db/workspace.sql diff --git a/experiment/infra/po/base.go b/experiment_module/infra/po/base.go similarity index 100% rename from experiment/infra/po/base.go rename to experiment_module/infra/po/base.go diff --git a/experiment/infra/po/workspace.go b/experiment_module/infra/po/workspace.go similarity index 100% rename from experiment/infra/po/workspace.go rename to experiment_module/infra/po/workspace.go diff --git a/experiment/infra/query/store.go b/experiment_module/infra/query/store.go similarity index 100% rename from experiment/infra/query/store.go rename to experiment_module/infra/query/store.go diff --git a/experiment/infra/query/workspace.go b/experiment_module/infra/query/workspace.go similarity index 91% rename from experiment/infra/query/workspace.go rename to experiment_module/infra/query/workspace.go index 78413256a55aeca7a24c84df11a91010badd54a7..3b082ee6dc257f55e10a0d1bd5e64e1c520aeb98 100644 --- a/experiment/infra/query/workspace.go +++ b/experiment_module/infra/query/workspace.go @@ -3,7 +3,7 @@ package query import ( "errors" - "octopus/experiment/infra/po" + "octopus/experiment_module/infra/po" "gorm.io/gorm" ) diff --git a/experiment/infra/repository/workspace.go b/experiment_module/infra/repository/workspace.go similarity index 89% rename from experiment/infra/repository/workspace.go rename to experiment_module/infra/repository/workspace.go index 0844743442dc0d706238400a812b771dde82930f..738caf679c90773daf0da0cdc2b5c652330b5b7c 100644 --- a/experiment/infra/repository/workspace.go +++ b/experiment_module/infra/repository/workspace.go @@ -2,9 +2,9 @@ package repository import ( "context" - "octopus/experiment/infra/acl/convert" - "octopus/experiment/infra/po" - "octopus/experiment/model/domain/workspace" + "octopus/experiment_module/infra/acl/convert" + "octopus/experiment_module/infra/po" + "octopus/experiment_module/model/domain/workspace" "octopus/hextech/server" "time" diff --git a/experiment_module/main.go b/experiment_module/main.go new file mode 100644 index 0000000000000000000000000000000000000000..7fe04cb8a3a2ba0f03d72932514fdba6c9a30b03 --- /dev/null +++ b/experiment_module/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "octopus/experiment_module/router" + "octopus/hextech/server" +) + +const LocalConfigFile = "dev.yml" +const LocalConfigPath = "conf" + +func main() { + server.New(LocalConfigFile, LocalConfigPath).SetHttpRouter(router.HTTP).Run() +} diff --git a/experiment/model/domain/base/aggregate_root.go b/experiment_module/model/domain/base/aggregate_root.go similarity index 100% rename from experiment/model/domain/base/aggregate_root.go rename to experiment_module/model/domain/base/aggregate_root.go diff --git a/experiment/model/domain/base/entity.go b/experiment_module/model/domain/base/entity.go similarity index 100% rename from experiment/model/domain/base/entity.go rename to experiment_module/model/domain/base/entity.go diff --git a/experiment/model/domain/base/role.go b/experiment_module/model/domain/base/role.go similarity index 100% rename from experiment/model/domain/base/role.go rename to experiment_module/model/domain/base/role.go diff --git a/experiment/model/domain/base/value_object.go b/experiment_module/model/domain/base/value_object.go similarity index 100% rename from experiment/model/domain/base/value_object.go rename to experiment_module/model/domain/base/value_object.go diff --git a/experiment/model/domain/workspace/desc.go b/experiment_module/model/domain/workspace/desc.go similarity index 100% rename from experiment/model/domain/workspace/desc.go rename to experiment_module/model/domain/workspace/desc.go diff --git a/experiment/model/domain/workspace/member.go b/experiment_module/model/domain/workspace/member.go similarity index 63% rename from experiment/model/domain/workspace/member.go rename to experiment_module/model/domain/workspace/member.go index 2205be07369eddecc03dce268390cd0a052d4fbc..b914a5b4918700c06c7c8800d59077445ab85f9e 100644 --- a/experiment/model/domain/workspace/member.go +++ b/experiment_module/model/domain/workspace/member.go @@ -1,6 +1,6 @@ package workspace -import "octopus/experiment/model/domain/base" +import "octopus/experiment_module/model/domain/base" type Member struct { base.AggregateRoot diff --git a/experiment/model/domain/workspace/workspace.go b/experiment_module/model/domain/workspace/workspace.go similarity index 95% rename from experiment/model/domain/workspace/workspace.go rename to experiment_module/model/domain/workspace/workspace.go index 5e9124c699e87a5f9db76a4e290c92217d33173f..aea764837548c7f27f3ae51b9986aa41b0138ed8 100644 --- a/experiment/model/domain/workspace/workspace.go +++ b/experiment_module/model/domain/workspace/workspace.go @@ -2,7 +2,7 @@ package workspace import ( "context" - "octopus/experiment/model/domain/base" + "octopus/experiment_module/model/domain/base" ) type WorkSpace struct { diff --git a/experiment/model/domain/workspace/workspace_repo.go b/experiment_module/model/domain/workspace/workspace_repo.go similarity index 100% rename from experiment/model/domain/workspace/workspace_repo.go rename to experiment_module/model/domain/workspace/workspace_repo.go diff --git a/experiment/model/service/workspace.go b/experiment_module/model/service/workspace.go similarity index 81% rename from experiment/model/service/workspace.go rename to experiment_module/model/service/workspace.go index a7e15c42901a43ce2b5b1b8bb4d289eb4c638708..0ca49286f681e13047d06e098cc1e664f2a3f7c2 100644 --- a/experiment/model/service/workspace.go +++ b/experiment_module/model/service/workspace.go @@ -3,11 +3,11 @@ package service import ( "context" "errors" - "octopus/experiment/dto" - "octopus/experiment/infra/acl/convert" - "octopus/experiment/infra/query" - "octopus/experiment/infra/repository" - "octopus/experiment/model/domain/workspace" + "octopus/experiment_module/dto" + "octopus/experiment_module/infra/acl/convert" + "octopus/experiment_module/infra/query" + "octopus/experiment_module/infra/repository" + "octopus/experiment_module/model/domain/workspace" ) type WorkSpaceService struct { diff --git a/experiment/router/http.go b/experiment_module/router/http.go similarity index 90% rename from experiment/router/http.go rename to experiment_module/router/http.go index 9bad435220bb5d408b8b6468ae79ff2d56b57914..115ad71136698b46edad16a82b2b3f209c02061d 100644 --- a/experiment/router/http.go +++ b/experiment_module/router/http.go @@ -1,7 +1,7 @@ package router import ( - "octopus/experiment/app/command" + "octopus/experiment_module/app/command" "github.com/gin-gonic/gin" ) diff --git a/hextech/config/options.go b/hextech/config/options.go index dfcc69932867a11a7a0851f3890f7ace877d9ab4..c97cfa375302ad6cb348d85a1a1b81127eb46fe4 100644 --- a/hextech/config/options.go +++ b/hextech/config/options.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "octopus/hextech/minio" "time" "octopus/hextech/captcha" @@ -21,6 +22,7 @@ type Options struct { RpcXServer *core.RpcXServer Db *gorm.DB Redis *redis.Client + Minio *minio.Client } func NewOptions(configName string, configPath string) (*Options, error) { @@ -82,6 +84,12 @@ func (o *Options) registerBasic() error { fmt.Printf("[REGISTER] register redis failed, err: %v\n", err.Error()) return err } + + // 注册minio + if err := o.registerMinio(); err != nil { + fmt.Printf("[REGISTER] register minio failed, err: %v\n", err.Error()) + return err + } return nil } @@ -179,6 +187,9 @@ func (o *Options) registerLogger() error { func (o *Options) registerDatabase() (err error) { dbConf := o.ComponentConfig.Mysql + if dbConf.Addr == "" { + return nil + } dbOptions := &db.MySQLOptions{ Host: dbConf.Addr, Username: dbConf.User, @@ -220,6 +231,9 @@ func (o *Options) registerWebServer() error { func (o *Options) registerRedis() error { redisConf := o.ComponentConfig.Redis + if redisConf.Addr == "" { + return nil + } redisOpt := &cache.Options{ Addr: redisConf.Addr, Port: redisConf.Port, @@ -294,5 +308,21 @@ func (o *Options) registerCaptcha() error { Rds: o.Redis, } captcha.Init(opt) + fmt.Println("[REGISTER] register captcha successful") + return nil +} + +func (o *Options) registerMinio() error { + conf := o.ComponentConfig.Minio + if conf.Host == "" { + return nil + } + o.Minio = &minio.Client{ + Host: conf.Host, + AccessKey: conf.AccessKey, + Secret: conf.Secret, + Bucket: "", // // 注册时无值,SetBucket进去 + } + fmt.Println("[REGISTER] register minio successful") return nil } diff --git a/hextech/core/rpcxserver.go b/hextech/core/rpcxserver.go index 64e486a94f0d6c5e23aa0ea035469542241eda2c..c5246cfb06fcd7cb3f8bd9ae1c5175ef09142e32 100644 --- a/hextech/core/rpcxserver.go +++ b/hextech/core/rpcxserver.go @@ -107,7 +107,7 @@ func NewRpcXServer(config *RpcXServerConfig) (*RpcXServer, error) { if opt == nil { opt = new(RpcXServerOptionsConfig) } - cert, _ := tls.LoadX509KeyPair("server.pem", "server.key") + cert, _ := tls.LoadX509KeyPair(base.CertFile, base.KeyFile) opt.tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} } var opts []server.OptionFn diff --git a/hextech/errors/my_errors.go b/hextech/errors/my_errors.go index 0c332a5bab47e27cd9d6f39230f69fc7ed1455a4..24b0e707b68e5731442d2a8fe610b058472eabec 100644 --- a/hextech/errors/my_errors.go +++ b/hextech/errors/my_errors.go @@ -3,7 +3,9 @@ package errors import "net/http" const ( - ErrSystemErrorCode int = iota + 1000 + Err400Code int = iota + 1000 + Err404Code + ErrSystemErrorCode ErrInvalidParamCode ErrUnauthorizedCode ErrVerifyCaptchaFailedCode @@ -11,6 +13,8 @@ const ( ) var ( + Err400 = WithCode(Err400Code, "") + Err404 = WithCode(Err404Code, "") ErrSystemError = WithCode(ErrSystemErrorCode, "") ErrInvalidParam = WithCode(ErrInvalidParamCode, "") ErrUnauthorized = WithCode(ErrUnauthorizedCode, "") @@ -19,9 +23,11 @@ var ( ) func init() { - Register(defaultCoder{ErrSystemErrorCode, http.StatusInternalServerError, "System inner error", ""}) - Register(defaultCoder{ErrInvalidParamCode, http.StatusBadRequest, "Invalid param", ""}) - Register(defaultCoder{ErrUnauthorizedCode, http.StatusUnauthorized, "Unauthorized", ""}) - Register(defaultCoder{ErrVerifyCaptchaFailedCode, http.StatusBadRequest, "Captcha verification failed", ""}) - Register(defaultCoder{ErrLoginFailedCode, http.StatusBadRequest, "Incorrect username or password", ""}) + Register(defaultCoder{Err400Code, http.StatusBadRequest, "400", ""}) + Register(defaultCoder{Err404Code, http.StatusNotFound, "404", ""}) + Register(defaultCoder{ErrSystemErrorCode, http.StatusInternalServerError, "system inner error", ""}) + Register(defaultCoder{ErrInvalidParamCode, http.StatusBadRequest, "invalid param", ""}) + Register(defaultCoder{ErrUnauthorizedCode, http.StatusUnauthorized, "unauthorized", ""}) + Register(defaultCoder{ErrVerifyCaptchaFailedCode, http.StatusBadRequest, "captcha verification failed", ""}) + Register(defaultCoder{ErrLoginFailedCode, http.StatusBadRequest, "incorrect username or password", ""}) } diff --git a/user/middleware/http/jwt.go b/hextech/middleware/http/jwt.go similarity index 89% rename from user/middleware/http/jwt.go rename to hextech/middleware/http/jwt.go index dfe4a00d3beeaf3a03afab8eada091e3ec9ca12f..1eed26660fa3abd5203fad87d76a3d5e6c65fb38 100644 --- a/user/middleware/http/jwt.go +++ b/hextech/middleware/http/jwt.go @@ -48,7 +48,7 @@ func verifyJWT(ctx *gin.Context) (userID int64, newToken string, err error) { // 判断tokenID是否相等 if !claims.EqTokenID(tokenID) { - err = errors.New("Token has expired") + err = errors.New("token has expired") return } @@ -74,9 +74,12 @@ func LoginAfterRefreshJWT(ctx *gin.Context) { defer utils.SetContextValue(ctx, constant.CtxUserLoginFlag, 0) err := jwt.New().WithCtx(ctx).MakeClaims(loginUserID).MakeToken().SaveTokenID(server.APP.GetRedis()) if err != nil { - message.FailedWithMsg(ctx, "Login failed", errors.ErrLoginFailed) + message.FailedWithMsg(ctx, "login failed", errors.ErrLoginFailed) ctx.Abort() } - message.Success(ctx, struct{}{}) + type LoginResponse struct { + ID int64 `json:"id"` + } + message.Success(ctx, LoginResponse{ID: loginUserID}) return } diff --git a/hextech/minio/client.go b/hextech/minio/client.go index 1ce3180d2200899c56333e91a9fab8e874688ff6..e7184dcfcea339e7d476196aa7aaeab6ac4be769 100644 --- a/hextech/minio/client.go +++ b/hextech/minio/client.go @@ -12,6 +12,11 @@ type Client struct { Bucket string // 桶名称 } +func (store *Client) SetBucket(bucket string) *Client { + store.Bucket = bucket + return store +} + func newMinioClient(store *Client) (*minio.Client, error) { minioClient, err := minio.New(store.Host, &minio.Options{ Creds: credentials.NewStaticV4(store.AccessKey, store.Secret, ""), diff --git a/hextech/server/server.go b/hextech/server/server.go index 7629b961af35afb3c3da1087c4915c2ed0e11e2a..f6f970b85ae839f179877604d5da8992b9ab3ea6 100644 --- a/hextech/server/server.go +++ b/hextech/server/server.go @@ -2,6 +2,7 @@ package server import ( "context" + "octopus/hextech/minio" "os" "os/signal" "syscall" @@ -105,3 +106,7 @@ func (d *Server) GetDB() *gorm.DB { func (d *Server) GetRedis() *redis.Client { return d.options.Redis } + +func (d *Server) GetMinio() *minio.Client { + return d.options.Minio +} diff --git a/hextech/utils/string.go b/hextech/utils/string.go index 53bcfed3de3118bd0f9274657efc876622bda77a..8dabf08e80d7cec08f74ad82415469eb050c6e28 100755 --- a/hextech/utils/string.go +++ b/hextech/utils/string.go @@ -122,3 +122,12 @@ func UnmarshalJson(jsonVal []byte, objVal interface{}) error { err := decoder.Decode(objVal) return err } + +func IsStringNotEmpty(str ...string) bool { + for _, v := range str { + if v == "" { + return false + } + } + return true +} diff --git a/storage_module/app/command/storage.go b/storage_module/app/command/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..79ecc51105301977ce10e097d7298cb09f5dae4a --- /dev/null +++ b/storage_module/app/command/storage.go @@ -0,0 +1,50 @@ +package command + +import ( + "github.com/gin-gonic/gin" + "octopus/hextech/errors" + "octopus/hextech/message" + "octopus/storage_module/constant" + "octopus/storage_module/dto" + "octopus/storage_module/model/service" + "strings" +) + +func UploadStorage(ctx *gin.Context) { + bucket := strings.TrimSpace(ctx.Param("bucket")) + if bucket == "" { + message.Failed(ctx, errors.ErrInvalidParam) + return + } + // 从文件流中获取文件信息 + multiForm, err := ctx.MultipartForm() + if err != nil { + message.FailedWithMsg(ctx, err.Error(), errors.ErrInvalidParam) + return + } + defer func() { + _ = multiForm.RemoveAll() + }() + + f, fh, err := ctx.Request.FormFile(constant.UploadFileKey) + if err != nil { + message.FailedWithMsg(ctx, err.Error(), errors.ErrInvalidParam) + return + } + defer func() { + _ = f.Close() + }() + args := &dto.UploadStorageRequest{ + BucketName: bucket, + Stream: f, + Filename: fh.Filename, + Filesize: fh.Size, + } + resp, err := service.NewStorageService(ctx).Upload(args) + if err != nil { + message.FailedWithMsg(ctx, err.Error(), errors.Err400) + return + } + message.Success(ctx, resp) + return +} diff --git a/storage_module/app/query/storage.go b/storage_module/app/query/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..f414ba0e047bbb8ad259c6de38e7b7abbac76ef1 --- /dev/null +++ b/storage_module/app/query/storage.go @@ -0,0 +1,63 @@ +package query + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/minio/minio-go/v7" + "net/http" + "net/url" + "octopus/hextech/errors" + "octopus/hextech/message" + "octopus/hextech/utils" + "octopus/storage_module/constant" + "octopus/storage_module/dto" + "octopus/storage_module/infra/query" + "runtime" +) + +// GetStorage 前端调用下载资源 +func GetStorage(ctx *gin.Context) { + args := &dto.GetStorageRequest{} + if err := ctx.ShouldBindUri(&args); err != nil { + message.Failed(ctx, errors.ErrInvalidParam) + return + } + if !utils.IsStringNotEmpty(args.BucketName, args.ObjectName) { + message.Failed(ctx, errors.ErrInvalidParam) + return + } + object, err := query.NewStore(ctx).GetObject(args.BucketName, args.ObjectName) + if err != nil { + message.FailedWithMsg(ctx, err.Error(), errors.ErrInvalidParam) + return + } + RenderStorageObject(ctx, object) + return +} + +// RenderStorageObject 下载资源 +func RenderStorageObject(ctx *gin.Context, object *minio.Object) { + if object == nil { + message.FailedWithMsg(ctx, "file not found", errors.Err404) + return + } + store := query.NewStore(ctx) + objectInfo, err := store.GetObjectInfo(object) + if err != nil { + message.FailedWithMsg(ctx, err.Error(), errors.ErrInvalidParam) + return + } + + headers := make(map[string]string) + rawFileName := store.GetObjectInfoFilename(objectInfo) + if rawFileName != "" { + headers["Content-Disposition"] = fmt.Sprintf("attachment; filename=%s", url.QueryEscape(rawFileName)) + } + + // 文件大小超过 OverSizeRunGC 时,手动GC + if objectInfo.Size > constant.OverSizeRunGC { + defer runtime.GC() + } + + ctx.DataFromReader(http.StatusOK, objectInfo.Size, objectInfo.ContentType, object, headers) +} diff --git a/storage_module/conf/dev.yml b/storage_module/conf/dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..fa41e00807204f4a4b52ee69614fe0e89d82285c --- /dev/null +++ b/storage_module/conf/dev.yml @@ -0,0 +1,23 @@ +app: + name: "base" + version: "1.0.0" + env: "dev" # dev, test, prod + +log: + # 日志级别, 支持 debug info warn error panic fatal ,默认info + level: debug + # 是否输出到终端,仅在开发环境有效 + stdout: true + logRate: false + logRateConf: + maxAge: 30 + maxBackups: 0 + +httpServer: + port: 8102 + address: "0.0.0.0" + +minio: + host: "127.0.0.1:9000" + accessKey: "7VU3JXE0HRB3PP6ZOZCI" + secret: "LdUMGhlWRl3EPeDEEndcZ1Bwnh6TWeYVn4Wc+v9F" \ No newline at end of file diff --git a/storage_module/constant/bucket.go b/storage_module/constant/bucket.go new file mode 100644 index 0000000000000000000000000000000000000000..40141a00ab09f135663fdddb8b8bf6f1e889af66 --- /dev/null +++ b/storage_module/constant/bucket.go @@ -0,0 +1,10 @@ +package constant + +const ( + RouterBucketAvatar = "avatar" // 用户头像路由bucket +) + +// RouterBucketMap 路由bucket和Minio真实存储bucket映射关系 +var RouterBucketMap = map[string]string{ + RouterBucketAvatar: "image/avatar", +} diff --git a/storage_module/constant/constant.go b/storage_module/constant/constant.go new file mode 100644 index 0000000000000000000000000000000000000000..35f885ec268b8c551932c1f651b2c2165aa473d5 --- /dev/null +++ b/storage_module/constant/constant.go @@ -0,0 +1,11 @@ +package constant + +const RawFileName = "Filename" // 原始文件名 + +const OverSizeRunGC int64 = 64 * 1024 + +const UploadFileKey = "file" + +const UploadMaxSize = 512 * 1024 * 1024 // 512M + +const StorageRouterPrefix = "/storage" diff --git a/storage_module/dto/storage.go b/storage_module/dto/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..1fed3dcc9b57889f32baa3b08208f86f46d77219 --- /dev/null +++ b/storage_module/dto/storage.go @@ -0,0 +1,19 @@ +package dto + +import "io" + +type GetStorageRequest struct { + BucketName string `uri:"bucket" binding:"required,min=2,max=64"` + ObjectName string `uri:"object" binding:"required,min=5"` +} + +type UploadStorageRequest struct { + BucketName string + Stream io.Reader + Filename string + Filesize int64 +} + +type UploadStorageResponse struct { + URL string `json:"url"` +} diff --git a/storage_module/infra/query/storage.go b/storage_module/infra/query/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..54a73c27d1ce76829e599993d2cedde1ade6323e --- /dev/null +++ b/storage_module/infra/query/storage.go @@ -0,0 +1,36 @@ +package query + +import ( + miniogo "github.com/minio/minio-go/v7" + "octopus/storage_module/constant" + "octopus/storage_module/utils" + "path" + "path/filepath" +) + +func (s *Store) GetObject(bucket string, objectName string) (object *miniogo.Object, err error) { + var objectPath string + bucket, objectPath = utils.GetBucket(bucket) + object, err = s.minio.SetBucket(bucket).GetAOSObject(s.ctx, path.Join(objectPath, objectName)) + if err != nil { + return nil, err + } + return +} + +func (s *Store) GetObjectInfo(object *miniogo.Object) (objectInfo *miniogo.ObjectInfo, err error) { + o, err := object.Stat() + if err != nil { + return nil, err + } + objectInfo = &o + return +} + +func (s *Store) GetObjectInfoFilename(objectInfo *miniogo.ObjectInfo) string { + filename := objectInfo.UserMetadata[constant.RawFileName] + if filename == "" { + filename = filepath.Base(objectInfo.Key) + } + return filename +} diff --git a/storage_module/infra/query/store.go b/storage_module/infra/query/store.go new file mode 100644 index 0000000000000000000000000000000000000000..d51d26fb5720d6e0d6bdf86538c5dadab14b9008 --- /dev/null +++ b/storage_module/infra/query/store.go @@ -0,0 +1,16 @@ +package query + +import ( + "context" + "octopus/hextech/minio" + "octopus/hextech/server" +) + +type Store struct { + ctx context.Context + minio *minio.Client +} + +func NewStore(ctx context.Context) *Store { + return &Store{minio: server.APP.GetMinio(), ctx: ctx} +} diff --git a/storage_module/infra/repository/storage.go b/storage_module/infra/repository/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..7abcf8296491d8e59765d777ddb5c44cf3fe8afe --- /dev/null +++ b/storage_module/infra/repository/storage.go @@ -0,0 +1,56 @@ +package repository + +import ( + "context" + "errors" + "fmt" + "github.com/google/uuid" + miniogo "github.com/minio/minio-go/v7" + "io" + "mime" + "octopus/hextech/minio" + "octopus/hextech/server" + "octopus/storage_module/constant" + "octopus/storage_module/model/domain/storage" + "octopus/storage_module/utils" + "path" + "path/filepath" + "strings" +) + +type StorageRepoImpl struct { + ctx context.Context + minio *minio.Client +} + +func NewStorageRepoImpl(ctx context.Context) storage.Repository { + r := new(StorageRepoImpl) + r.minio = server.APP.GetMinio() + r.ctx = ctx + return r +} + +func (s *StorageRepoImpl) Upload(bucket string, stream io.Reader, filename string, size int64) (*miniogo.UploadInfo, error) { + if size > constant.UploadMaxSize { + return nil, errors.New("file size too large") + } + + ext := filepath.Ext(filename) + var objectPath string + + bucket, objectPath = utils.GetBucket(bucket) + + contentType := mime.TypeByExtension(ext) + if contentType == "" { + contentType = "application/octet-stream" + } + + objectName := path.Join(objectPath, strings.ReplaceAll(uuid.NewString(), "-", "")+ext) + metadata := map[string]string{constant.RawFileName: filepath.Base(filename)} + uploadInfo, err := s.minio.SetBucket(bucket).UploadStream(s.ctx, objectName, stream, size, contentType, metadata) + if err != nil { + return nil, fmt.Errorf("file upload failed. bucket: %v, filename: %v", bucket, filename) + } + + return &uploadInfo, nil +} diff --git a/experiment/main.go b/storage_module/main.go similarity index 86% rename from experiment/main.go rename to storage_module/main.go index 7122544b0cb112c815b472859a6484e50cffb281..2191df9fa96cb806ef29b3e6114fadc7f17863e1 100644 --- a/experiment/main.go +++ b/storage_module/main.go @@ -1,8 +1,8 @@ package main import ( - "octopus/experiment/router" "octopus/hextech/server" + "octopus/storage_module/router" ) const LocalConfigFile = "dev.yml" diff --git a/storage_module/model/domain/storage/storage_repo.go b/storage_module/model/domain/storage/storage_repo.go new file mode 100644 index 0000000000000000000000000000000000000000..90ce1478d23b1a0c6b63bcced5c04576f9151f14 --- /dev/null +++ b/storage_module/model/domain/storage/storage_repo.go @@ -0,0 +1,18 @@ +package storage + +import ( + miniogo "github.com/minio/minio-go/v7" + "io" +) + +type Repository interface { + Upload(bucket string, stream io.Reader, filename string, size int64) (*miniogo.UploadInfo, error) +} + +type Repo struct { + storageRepo Repository +} + +func (r *Repo) GetStorageRepo() Repository { + return r.storageRepo +} diff --git a/storage_module/model/service/storage.go b/storage_module/model/service/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..f0dd81379a525a7336d5cfaedd9991f9d5145c67 --- /dev/null +++ b/storage_module/model/service/storage.go @@ -0,0 +1,33 @@ +package service + +import ( + "context" + "octopus/storage_module/dto" + "octopus/storage_module/infra/repository" + "octopus/storage_module/model/domain/storage" + "octopus/storage_module/utils" +) + +type StorageService struct { + ctx context.Context + repo storage.Repository +} + +func NewStorageService(ctx context.Context) *StorageService { + p := &StorageService{ + ctx: ctx, + repo: repository.NewStorageRepoImpl(ctx), + } + return p +} + +func (s *StorageService) Upload(args *dto.UploadStorageRequest) (resp *dto.UploadStorageResponse, err error) { + uploadInfo, err := s.repo.Upload(args.BucketName, args.Stream, args.Filename, args.Filesize) + if err != nil { + return nil, err + } + resp = &dto.UploadStorageResponse{ + URL: utils.GetURL(args.BucketName, uploadInfo.Key), + } + return resp, nil +} diff --git a/storage_module/router/http.go b/storage_module/router/http.go new file mode 100644 index 0000000000000000000000000000000000000000..288e160f9015145642a0398dbb1fc3d6d08d7787 --- /dev/null +++ b/storage_module/router/http.go @@ -0,0 +1,13 @@ +package router + +import ( + "github.com/gin-gonic/gin" + hexmiddleware "octopus/hextech/middleware/http" +) + +func HTTP(engine *gin.Engine) { + engine.Use(gin.Recovery()) + versionGroup := engine.Group("/v1") + engine.Use(hexmiddleware.JWT) + storageRouterGroup(versionGroup) +} diff --git a/storage_module/router/storage.go b/storage_module/router/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..e41822637a1605ad944ff672504c5e4f0a7e473c --- /dev/null +++ b/storage_module/router/storage.go @@ -0,0 +1,16 @@ +package router + +import ( + "github.com/gin-gonic/gin" + "octopus/storage_module/app/command" + "octopus/storage_module/app/query" +) + +// storageRouterGroup 资源路由组 +func storageRouterGroup(group *gin.RouterGroup) { + storageRouter := group.Group("/storage") + // 下载资源 + storageRouter.GET("/:bucket/*object", query.GetStorage) + // 上传资源 + storageRouter.POST("/:bucket", command.UploadStorage) +} diff --git a/storage_module/utils/storage.go b/storage_module/utils/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..03ce11e916edca935db91a410f1b09c7eb94dabf --- /dev/null +++ b/storage_module/utils/storage.go @@ -0,0 +1,35 @@ +package utils + +import ( + "octopus/storage_module/constant" + "path" + "strings" +) + +// GetBucket 转换为真实的bucket及对象路径 +// 如没做映射,则用routerBucket表示实际的bucket +func GetBucket(routerBucket string) (bucket, objectPath string) { + bucket = strings.TrimSpace(routerBucket) + if v, ok := constant.RouterBucketMap[routerBucket]; ok { + bucket = v + } + + if pos := strings.Index(bucket, "/"); pos != -1 { + bucket, objectPath = strings.TrimSpace(bucket[:pos]), strings.TrimSpace(bucket[pos+1:]) + } + + return +} + +// GetURL 获取页面显示url +func GetURL(bucket string, storagePath string) string { + // storagePath == image/avatar/abc.png 存储路径 + // RouterBucketAvatar == "avatar" 路由bucket + if _, objectPath := GetBucket(bucket); objectPath != "" { + if strings.HasPrefix(storagePath, objectPath+"/") { + storagePath = storagePath[len(objectPath)+1:] + } + } + + return path.Join(constant.StorageRouterPrefix, bucket, storagePath) +} diff --git a/user/dto/user.go b/user/dto/user.go deleted file mode 100644 index 4f485160a978791127549382a7f5e4e92dcc9aeb..0000000000000000000000000000000000000000 --- a/user/dto/user.go +++ /dev/null @@ -1,47 +0,0 @@ -package dto - -type LoginRequest struct { - Account string `json:"account"` - Password string `json:"password"` - LoginType string `json:"login_type"` // un use - VerifyCaptchaReq -} - -type LoginResponse struct { -} - -type UserInfoRequest struct { - ID int64 `json:"id"` -} - -type UserInfoResponse struct { - ID int64 `json:"id"` - TenantId int64 `json:"tenant_id"` // 租户id - Name string `json:"name"` // 姓名 - Email string `json:"email"` // 邮箱 - Enable int64 `json:"enable"` // 是否可用 - HeadImage string `json:"head_image"` // 头像minio路径 - Mobile string `json:"mobile"` // 手机 - Telephone string `json:"telephone"` // 座机 - Embed int64 `json:"embed"` // 是否为内置账户 - LastLoginAt int64 `json:"last_login_at"` // 最近登录时间 - LastLogoutAt int64 `json:"last_logout_at"` // 最近登出时间 - JWTRefreshAt int64 `json:"jwt_refresh_at"` // jwt最后刷新时间 - DescInfo string `json:"desc_info"` // 描述 - DeleteAt int64 `json:"delete_at"` // 删除时间 - CreateAt int64 `json:"create_at"` // 创建时间 - UpdateAt int64 `json:"update_at"` // 更新时间 -} - -type CreateUserRequest struct { - Name string `json:"name"` // 姓名 - Password string `json:"password"` // 密码 - Email string `json:"email"` // 邮箱 - Mobile string `json:"mobile"` // 手机 - Telephone string `json:"telephone"` // 座机 - DescInfo string `json:"desc_info"` // 描述 -} - -type CreateUserResponse struct { - ID int64 `json:"id"` -} diff --git a/user/app/command/user.go b/user_module/app/command/user.go similarity index 75% rename from user/app/command/user.go rename to user_module/app/command/user.go index e2d8031f66b8ccda5932f79d6e85728660e73af6..be8c839063ae58137c88412ce8bde4e892fbbc8d 100644 --- a/user/app/command/user.go +++ b/user_module/app/command/user.go @@ -6,8 +6,8 @@ import ( "octopus/hextech/errors" "octopus/hextech/message" "octopus/hextech/utils" - "octopus/user/dto" - "octopus/user/model/service" + "octopus/user_module/dto" + "octopus/user_module/model/service" ) func Login(ctx *gin.Context) { @@ -26,10 +26,13 @@ func Login(ctx *gin.Context) { } // 登录成功,记录上下文登录成功标记,用于中间件刷新jwt utils.SetContextValue(ctx, constant.CtxUserLoginFlag, userID) + message.Success(ctx, dto.CreateUserResponse{ + ID: userID, + }) return } -func CreateUser(ctx *gin.Context) { +func Create(ctx *gin.Context) { args := &dto.CreateUserRequest{} err := ctx.ShouldBindJSON(args) @@ -37,6 +40,11 @@ func CreateUser(ctx *gin.Context) { message.Failed(ctx, errors.ErrInvalidParam) return } + // 手机号和邮箱必填 + if !utils.IsStringNotEmpty(args.Mobile, args.Email) { + message.Failed(ctx, errors.ErrInvalidParam) + return + } if err := service.NewUserService(ctx).Create(args); err != nil { message.FailedWithMsg(ctx, err.Error(), err) diff --git a/user/app/query/user.go b/user_module/app/query/user.go similarity index 65% rename from user/app/query/user.go rename to user_module/app/query/user.go index c3c2f26b60b099c150b0404514eafb848ea0ba0e..c698bd8f8f547a0105f7021b6f02b3220933580b 100644 --- a/user/app/query/user.go +++ b/user_module/app/query/user.go @@ -3,9 +3,9 @@ package query import ( "octopus/hextech/errors" "octopus/hextech/message" - "octopus/user/dto" - "octopus/user/infra/query" - "octopus/user/model/service" + "octopus/user_module/dto" + "octopus/user_module/infra/query" + "octopus/user_module/model/service" "path" "strings" @@ -16,7 +16,7 @@ func UserInfo(ctx *gin.Context) { args := &dto.UserInfoRequest{} err := ctx.ShouldBindJSON(args) if err != nil { - message.Failed(ctx, err) + message.Failed(ctx, errors.ErrInvalidParam) return } @@ -30,12 +30,25 @@ func UserInfo(ctx *gin.Context) { message.Failed(ctx, errors.New("user not exist")) return } - message.Success(ctx, user) + + userInfo := dto.UserInfoResponse{ + ID: user.ID, + Email: user.Email, + Enable: user.IsEnable(), + HeadImage: user.HeadImage, + Mobile: user.Mobile, + Telephone: user.Telephone, + Embed: user.IsEmbed(), + DescInfo: user.DescInfo, + } + message.Success(ctx, userInfo) + return } func GetCaptcha(ctx *gin.Context) { resp := service.NewCaptchaService(ctx).Get() message.Success(ctx, resp) + return } func ShowCaptcha(ctx *gin.Context) { diff --git a/user/conf/dev.yml b/user_module/conf/dev.yml similarity index 100% rename from user/conf/dev.yml rename to user_module/conf/dev.yml diff --git a/user/dto/captcha.go b/user_module/dto/captcha.go similarity index 100% rename from user/dto/captcha.go rename to user_module/dto/captcha.go diff --git a/user_module/dto/user.go b/user_module/dto/user.go new file mode 100644 index 0000000000000000000000000000000000000000..f97dbd4f52557a0bd3fee647268048145561993a --- /dev/null +++ b/user_module/dto/user.go @@ -0,0 +1,41 @@ +package dto + +type LoginRequest struct { + Account string `json:"account"` + Password string `json:"password"` + LoginType string `json:"login_type"` // un use + VerifyCaptchaReq +} + +type LoginResponse struct { +} + +type UserInfoRequest struct { + ID int64 `json:"id"` +} + +type UserInfoResponse struct { + ID int64 `json:"id"` + Email string `json:"email"` // 邮箱 + Enable bool `json:"enable"` // 是否可用 + HeadImage string `json:"head_image"` // 头像minio路径 + Mobile string `json:"mobile"` // 手机 + Telephone string `json:"telephone"` // 座机 + Embed bool `json:"embed"` // 是否为内置账户 + DescInfo string `json:"desc_info"` // 描述 +} + +type CreateUserRequest struct { + Name string `json:"name"` // 姓名 + Password string `json:"password"` // 密码 + Email string `json:"email"` // 邮箱 + Mobile string `json:"mobile"` // 手机 + Telephone string `json:"telephone"` // 座机 + DescInfo string `json:"desc_info"` // 描述 + HeadImage string `json:"head_image"` // 头像路径 + Enable bool `json:"enable"` // 是否可用 +} + +type CreateUserResponse struct { + ID int64 `json:"id"` +} diff --git a/user/infra/acl/convert/user.go b/user_module/infra/acl/convert/user.go similarity index 47% rename from user/infra/acl/convert/user.go rename to user_module/infra/acl/convert/user.go index 62f613a9f0be50ca9dd66ea62cca2f415690a004..8d1b08148bdf42129882231572b01421b95d9d36 100644 --- a/user/infra/acl/convert/user.go +++ b/user_module/infra/acl/convert/user.go @@ -2,9 +2,9 @@ package convert import ( "context" - "octopus/user/dto" - "octopus/user/infra/po" - "octopus/user/model/domain/user" + "octopus/user_module/dto" + "octopus/user_module/infra/po" + "octopus/user_module/model/domain/user" ) const ( @@ -12,19 +12,28 @@ const ( ) func CreateUserDTO2User(ctx context.Context, request *dto.CreateUserRequest) *user.User { + userAttr := &user.UserAttr{ + ID: NotCreateUserID, + Username: request.Name, + Password: request.Password, + Email: request.Email, + Mobile: request.Mobile, + Telephone: request.Telephone, + DescInfo: request.DescInfo, + HeadImage: request.HeadImage, + Enable: request.Enable, + } return user.NewUser( ctx, - NotCreateUserID, - request.Name, - request.Password, - request.Email, - request.Mobile, - request.Telephone, - request.DescInfo, + userAttr, ) } func UserDomain2Po(userDomain *user.User) *po.User { + var enable int8 + if userDomain.GetEnable() { + enable = po.UserEnableNormal + } u := &po.User{ Model: po.Model{ ID: userDomain.AggregateRoot.ID(), @@ -32,7 +41,7 @@ func UserDomain2Po(userDomain *user.User) *po.User { Name: userDomain.GetUsername(), Email: userDomain.GetEmail().Get(), Password: userDomain.GetPassword().Get(), - Enable: 0, + Enable: enable, HeadImage: "", Mobile: userDomain.GetMobile().Get(), Telephone: userDomain.GetTelephone(), @@ -43,15 +52,20 @@ func UserDomain2Po(userDomain *user.User) *po.User { } func UserPo2Domain(ctx context.Context, userPo *po.User) *user.User { + userAttr := &user.UserAttr{ + ID: userPo.ID, + Username: userPo.Name, + Password: userPo.Password, + Email: userPo.Email, + Mobile: userPo.Mobile, + Telephone: userPo.Telephone, + DescInfo: userPo.DescInfo, + HeadImage: userPo.HeadImage, + Enable: userPo.IsEnable(), + } u := user.NewUser( ctx, - userPo.ID, - userPo.Name, - userPo.Password, - userPo.Email, - userPo.Mobile, - userPo.Telephone, - userPo.DescInfo, + userAttr, ) return u } diff --git a/user/infra/acl/convert/user_login_history.go b/user_module/infra/acl/convert/user_login_history.go similarity index 79% rename from user/infra/acl/convert/user_login_history.go rename to user_module/infra/acl/convert/user_login_history.go index 004ba4882ef88267a4f26f1ee6bfb9fc165396a3..b4aad447b749501d78e47924f34b5b20c4df8bb2 100644 --- a/user/infra/acl/convert/user_login_history.go +++ b/user_module/infra/acl/convert/user_login_history.go @@ -1,8 +1,8 @@ package convert import ( - "octopus/user/infra/po" - "octopus/user/model/domain/user" + "octopus/user_module/infra/po" + "octopus/user_module/model/domain/user" ) func UserDomain2LoginPo(userDomain *user.User) *po.UserLoginHistory { diff --git a/user/infra/db/user.sql b/user_module/infra/db/user.sql similarity index 100% rename from user/infra/db/user.sql rename to user_module/infra/db/user.sql diff --git a/user/infra/db/user_login_history.sql b/user_module/infra/db/user_login_history.sql similarity index 100% rename from user/infra/db/user_login_history.sql rename to user_module/infra/db/user_login_history.sql diff --git a/user/infra/db/user_role.sql b/user_module/infra/db/user_role.sql similarity index 100% rename from user/infra/db/user_role.sql rename to user_module/infra/db/user_role.sql diff --git a/user/infra/po/base.go b/user_module/infra/po/base.go similarity index 100% rename from user/infra/po/base.go rename to user_module/infra/po/base.go diff --git a/user/infra/po/user.go b/user_module/infra/po/user.go similarity index 61% rename from user/infra/po/user.go rename to user_module/infra/po/user.go index f80b992987ccd58f19363d80ca6fdc22fe8b193c..1e0d562266abc2460fcbd0c2b151e97a799accec 100644 --- a/user/infra/po/user.go +++ b/user_module/infra/po/user.go @@ -6,15 +6,26 @@ type User struct { Name string `gorm:"column:name"` // 姓名 Email string `gorm:"column:email"` // 邮箱 Password string `gorm:"column:password"` // 密码 - Enable int8 `gorm:"column:enable"` // 是否可用 + Enable int8 `gorm:"column:enable"` // 是否可用 1可用,其他暂停使用 HeadImage string `gorm:"column:head_image"` // 头像minio路径 Mobile string `gorm:"column:mobile"` // 手机 Telephone string `gorm:"column:telephone"` // 座机 - Embed int8 `gorm:"column:embed"` // 是否为内置账户 + Embed int8 `gorm:"column:embed"` // 是否为内置账户 1是,其他不是 DescInfo string `gorm:"column:desc_info"` // 描述 DeleteAt int64 `gorm:"column:delete_at"` // 删除时间 } -func (User) TableName() string { +func (*User) TableName() string { return "user" } + +const UserEnableNormal int8 = 1 +const UserEmbedIn int8 = 1 + +func (p *User) IsEnable() bool { + return p != nil && p.Enable == UserEnableNormal +} + +func (p *User) IsEmbed() bool { + return p != nil && p.Embed == UserEmbedIn +} diff --git a/user/infra/po/user_login_history.go b/user_module/infra/po/user_login_history.go similarity index 100% rename from user/infra/po/user_login_history.go rename to user_module/infra/po/user_login_history.go diff --git a/user/infra/query/store.go b/user_module/infra/query/store.go similarity index 100% rename from user/infra/query/store.go rename to user_module/infra/query/store.go diff --git a/user/infra/query/user.go b/user_module/infra/query/user.go similarity index 90% rename from user/infra/query/user.go rename to user_module/infra/query/user.go index 14c23ebff7d36a503135c37df0005e747bba710e..85f5cfff9f0737d4bca466cdc61aa62efc7bda13 100644 --- a/user/infra/query/user.go +++ b/user_module/infra/query/user.go @@ -3,7 +3,7 @@ package query import ( "errors" "octopus/hextech/nlog" - "octopus/user/infra/po" + "octopus/user_module/infra/po" "gorm.io/gorm" ) @@ -36,7 +36,7 @@ func (s *Store) GetUser(email, mobile string) (resp *po.User, exist bool, err er func (s *Store) UserInfoByID(userID int64) (resp *po.User, exist bool, err error) { res := s.db.WithContext(s.ctx).Where("id = ?", userID).First(&resp) if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) { - nlog.Warn(s.ctx, "query customer info by customer id error:", res.Error, "params is : ", userID) + nlog.Warn(s.ctx, "query user info by id error: ", res.Error, " params: ", userID) return nil, false, err } else if errors.Is(res.Error, gorm.ErrRecordNotFound) { return nil, true, nil diff --git a/user/infra/repository/user.go b/user_module/infra/repository/user.go similarity index 91% rename from user/infra/repository/user.go rename to user_module/infra/repository/user.go index 9998c0f7e7aae10e4b7a95c0bb4ac086619affc4..a46cd156fde0a8aee94ed38c991503e4657805f8 100644 --- a/user/infra/repository/user.go +++ b/user_module/infra/repository/user.go @@ -3,8 +3,8 @@ package repository import ( "context" "octopus/hextech/server" - "octopus/user/infra/acl/convert" - "octopus/user/model/domain/user" + "octopus/user_module/infra/acl/convert" + "octopus/user_module/model/domain/user" "github.com/go-redis/redis/v7" "gorm.io/gorm" diff --git a/user/infra/repository/user_login_history.go b/user_module/infra/repository/user_login_history.go similarity index 73% rename from user/infra/repository/user_login_history.go rename to user_module/infra/repository/user_login_history.go index b4cee791ca0ff018c59a84350f668169cf0ff881..11f9612ec96d637e008dbb60f15085d8019bbbbe 100644 --- a/user/infra/repository/user_login_history.go +++ b/user_module/infra/repository/user_login_history.go @@ -1,8 +1,8 @@ package repository import ( - "octopus/user/infra/acl/convert" - "octopus/user/model/domain/user" + "octopus/user_module/infra/acl/convert" + "octopus/user_module/model/domain/user" ) func (u *UserRepoImpl) CreateLoginHistory(user *user.User) error { diff --git a/user/main.go b/user_module/main.go similarity index 87% rename from user/main.go rename to user_module/main.go index 187673cf88681cabc2d654e7089530108fcca29f..f048140d4a7a37419a2a907f3355f6f7581436cb 100644 --- a/user/main.go +++ b/user_module/main.go @@ -2,7 +2,7 @@ package main import ( "octopus/hextech/server" - "octopus/user/router" + "octopus/user_module/router" ) const LocalConfigFile = "dev.yml" diff --git a/user/middleware/http/captcha.go b/user_module/middleware/http/captcha.go similarity index 92% rename from user/middleware/http/captcha.go rename to user_module/middleware/http/captcha.go index 8b86c4c45bf6e7869b94d40d2d7964614f85ca6a..125d29b7d2d436de8d539a43feb12007aac13c52 100644 --- a/user/middleware/http/captcha.go +++ b/user_module/middleware/http/captcha.go @@ -7,8 +7,8 @@ import ( "io/ioutil" "octopus/hextech/errors" "octopus/hextech/message" - "octopus/user/dto" - "octopus/user/model/service" + "octopus/user_module/dto" + "octopus/user_module/model/service" ) // VerifyCaptcha 校验验证码 diff --git a/user/model/domain/base/aggregate_root.go b/user_module/model/domain/base/aggregate_root.go similarity index 100% rename from user/model/domain/base/aggregate_root.go rename to user_module/model/domain/base/aggregate_root.go diff --git a/user/model/domain/base/entity.go b/user_module/model/domain/base/entity.go similarity index 100% rename from user/model/domain/base/entity.go rename to user_module/model/domain/base/entity.go diff --git a/user/model/domain/base/role.go b/user_module/model/domain/base/role.go similarity index 100% rename from user/model/domain/base/role.go rename to user_module/model/domain/base/role.go diff --git a/user/model/domain/base/value_object.go b/user_module/model/domain/base/value_object.go similarity index 100% rename from user/model/domain/base/value_object.go rename to user_module/model/domain/base/value_object.go diff --git a/user/model/domain/user/email.go b/user_module/model/domain/user/email.go similarity index 100% rename from user/model/domain/user/email.go rename to user_module/model/domain/user/email.go diff --git a/user/model/domain/user/headimg.go b/user_module/model/domain/user/headimg.go similarity index 32% rename from user/model/domain/user/headimg.go rename to user_module/model/domain/user/headimg.go index 7c5e652ea7686c5956b01791d1076b54b87e25d8..649ee31d064d6df60507f8904b24561ef5f79797 100644 --- a/user/model/domain/user/headimg.go +++ b/user_module/model/domain/user/headimg.go @@ -2,27 +2,14 @@ package user type HeaderImg struct { objectPath string - url string } func NewHeaderImg(objectPath string) *HeaderImg { - h := &HeaderImg{} - return h + return &HeaderImg{ + objectPath: objectPath, + } } -func (h *HeaderImg) ObjectPath() string { +func (h *HeaderImg) GetObjectPath() string { return h.objectPath } - -func (h *HeaderImg) Url() string { - // - return h.url -} - -func (h *HeaderImg) SetObjectPath(objectPath string) { - h.objectPath = objectPath -} - -func (h *HeaderImg) SetUrl(url string) { - h.url = url -} diff --git a/user/model/domain/user/login_attr.go b/user_module/model/domain/user/login_attr.go similarity index 100% rename from user/model/domain/user/login_attr.go rename to user_module/model/domain/user/login_attr.go diff --git a/user/model/domain/user/mobile.go b/user_module/model/domain/user/mobile.go similarity index 100% rename from user/model/domain/user/mobile.go rename to user_module/model/domain/user/mobile.go diff --git a/user/model/domain/user/password.go b/user_module/model/domain/user/password.go similarity index 100% rename from user/model/domain/user/password.go rename to user_module/model/domain/user/password.go diff --git a/user/model/domain/user/user.go b/user_module/model/domain/user/user.go similarity index 52% rename from user/model/domain/user/user.go rename to user_module/model/domain/user/user.go index 3e30547df7905fab6e50ed46c5c4511901efec6f..0f604467420dfb5935ab3024781b45952e35ad1c 100644 --- a/user/model/domain/user/user.go +++ b/user_module/model/domain/user/user.go @@ -3,7 +3,7 @@ package user import ( "context" "octopus/hextech/utils" - "octopus/user/model/domain/base" + "octopus/user_module/model/domain/base" ) type User struct { @@ -15,19 +15,38 @@ type User struct { mobile *Mobile telephone string descInfo string + headImage *HeaderImg + enable bool loginAttr *LoginAttr } -func NewUser(ctx context.Context, id int64, username, password, email, mobile, telephone, descInfo string) *User { +type UserAttr struct { + ID int64 + Username string + Password string + Email string + Mobile string + Telephone string + DescInfo string + HeadImage string + Enable bool +} + +func NewUser(ctx context.Context, attr *UserAttr) *User { + if attr == nil { + attr = new(UserAttr) + } return &User{ ctx: ctx, - AggregateRoot: base.NewAggregateRoot(id), - username: username, - password: NewPassword(password), - email: NewEmail(email), - mobile: NewMobile(mobile), - telephone: telephone, - descInfo: descInfo, + AggregateRoot: base.NewAggregateRoot(attr.ID), + username: attr.Username, + password: NewPassword(attr.Password), + email: NewEmail(attr.Email), + mobile: NewMobile(attr.Mobile), + telephone: attr.Telephone, + descInfo: attr.DescInfo, + headImage: NewHeaderImg(attr.HeadImage), + enable: attr.Enable, loginAttr: NewLoginAttr(utils.GetClientIp(ctx)), } } @@ -60,6 +79,14 @@ func (u *User) GetLoginAttr() *LoginAttr { return u.loginAttr } +func (u *User) GetHeadImage() *HeaderImg { + return u.headImage +} + +func (u *User) GetEnable() bool { + return u.enable +} + func (u *User) Valid() bool { if u.email.IsValid() && u.mobile.IsValid() && u.password.GetValid() { return true diff --git a/user/model/domain/user/user_repo.go b/user_module/model/domain/user/user_repo.go similarity index 100% rename from user/model/domain/user/user_repo.go rename to user_module/model/domain/user/user_repo.go diff --git a/user/model/service/captcha.go b/user_module/model/service/captcha.go similarity index 97% rename from user/model/service/captcha.go rename to user_module/model/service/captcha.go index 8ad7277dffc4446ac984fb0ff482fcbde45a207c..d33d037dc31bef0f88a33c5d69f90f2b69f0981b 100644 --- a/user/model/service/captcha.go +++ b/user_module/model/service/captcha.go @@ -4,7 +4,7 @@ import ( "errors" "github.com/gin-gonic/gin" "octopus/hextech/captcha" - "octopus/user/dto" + "octopus/user_module/dto" "path" ) diff --git a/user/model/service/user.go b/user_module/model/service/user.go similarity index 83% rename from user/model/service/user.go rename to user_module/model/service/user.go index a66555e0af34105c1e8945884b01ec3d3683f632..1c0df8de0177bc9cd6ffaeb1b0b0d3c19b09f312 100644 --- a/user/model/service/user.go +++ b/user_module/model/service/user.go @@ -3,11 +3,12 @@ package service import ( "context" "errors" - "octopus/user/dto" - "octopus/user/infra/acl/convert" - "octopus/user/infra/query" - "octopus/user/infra/repository" - "octopus/user/model/domain/user" + myerrors "octopus/hextech/errors" + "octopus/user_module/dto" + "octopus/user_module/infra/acl/convert" + "octopus/user_module/infra/query" + "octopus/user_module/infra/repository" + "octopus/user_module/model/domain/user" ) type UserService struct { @@ -56,7 +57,7 @@ func (u *UserService) Login(args *dto.LoginRequest) (userID int64, err error) { userDomain := convert.UserPo2Domain(u.ctx, info) // check password if !userDomain.GetPassword().Check(args.Password) { - return 0, errors.New("incorrect user password") + return 0, myerrors.ErrLoginFailed } // update last login at and access ip diff --git a/user/router/captcha.go b/user_module/router/captcha.go similarity index 90% rename from user/router/captcha.go rename to user_module/router/captcha.go index db1874d4324550fe7461a35748a7de098ea049d2..7bef11a7b7174a8ca9d6d45d9014c7ac3972f4c3 100644 --- a/user/router/captcha.go +++ b/user_module/router/captcha.go @@ -2,7 +2,7 @@ package router import ( "github.com/gin-gonic/gin" - "octopus/user/app/query" + "octopus/user_module/app/query" ) // captchaRouterGroup 验证码路由组 diff --git a/user/router/http.go b/user_module/router/http.go similarity index 65% rename from user/router/http.go rename to user_module/router/http.go index 7e40fbca9ca52a24324b831e3f4c47fd3e9ac8d2..1530a8b96a1590492fc06b8ca1fc269b1679627a 100644 --- a/user/router/http.go +++ b/user_module/router/http.go @@ -1,9 +1,10 @@ package router import ( - "octopus/user/app/command" - "octopus/user/app/query" - middleware "octopus/user/middleware/http" + hexmiddleware "octopus/hextech/middleware/http" + "octopus/user_module/app/command" + "octopus/user_module/app/query" + middleware "octopus/user_module/middleware/http" "time" "octopus/hextech/message" @@ -28,13 +29,13 @@ func HTTP(engine *gin.Engine) { } captchaRouterGroup(baseGroup) - baseGroup.POST("/login", middleware.VerifyCaptcha, middleware.LoginAfterRefreshJWT, command.Login) + baseGroup.POST("/login", middleware.VerifyCaptcha, hexmiddleware.LoginAfterRefreshJWT, command.Login) - engine.Use(middleware.JWT) + engine.Use(hexmiddleware.JWT) versionGroup := engine.Group("/v1") userRouter := versionGroup.Group("/user") { - userRouter.POST("/create", command.CreateUser) + userRouter.POST("/create", command.Create) userRouter.GET("/info", query.UserInfo) } } diff --git a/user/test/user_test.go b/user_module/test/user_test.go similarity index 100% rename from user/test/user_test.go rename to user_module/test/user_test.go