diff --git a/constants/field_status.go b/constants/field_status.go deleted file mode 100644 index 56e52bbe..00000000 --- a/constants/field_status.go +++ /dev/null @@ -1,5 +0,0 @@ -package constants - -// 普通表中status状态 -// const STATUS_ON = 1 -// const STATUS_OFF = 0 diff --git a/constants/image_cropping.go b/constants/image_cropping.go new file mode 100644 index 00000000..e8bf5d57 --- /dev/null +++ b/constants/image_cropping.go @@ -0,0 +1,4 @@ +package constants + +// 裁剪尺寸阶梯 +var IMAGE_CROPPING_STEP_SIZE = []int{200, 400, 600, 800} diff --git a/goctl_template/api/main.tpl b/goctl_template/api/main.tpl index 709ddbd1..4a7983e0 100644 --- a/goctl_template/api/main.tpl +++ b/goctl_template/api/main.tpl @@ -26,21 +26,4 @@ func main() { } - -// var testConfigFile = flag.String("f", "../etc/{{.serviceName}}.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } \ No newline at end of file + \ No newline at end of file diff --git a/model/gmodel/fs_product_design_logic.go b/model/gmodel/fs_product_design_logic.go index 23c0aa69..29022eb8 100755 --- a/model/gmodel/fs_product_design_logic.go +++ b/model/gmodel/fs_product_design_logic.go @@ -31,3 +31,6 @@ func (d *FsProductDesignModel) GetAllByIdsWithoutStatus(ctx context.Context, ids func (d *FsProductDesignModel) Create(ctx context.Context, data *FsProductDesign) error { return d.db.WithContext(ctx).Model(&FsProductDesign{}).Create(&data).Error } +func (d *FsProductDesignModel) UpdateBySn(ctx context.Context, sn string, data *FsProductDesign) error { + return d.db.WithContext(ctx).Model(&FsProductDesign{}).Where("`sn` = ?", sn).Updates(&data).Error +} diff --git a/server/backend/backend.go b/server/backend/backend.go index 901be84f..ff692e55 100644 --- a/server/backend/backend.go +++ b/server/backend/backend.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/backend.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/backend/test/basic.go b/server/backend/test/basic.go index 97e0c1fa..39dfc654 100644 --- a/server/backend/test/basic.go +++ b/server/backend/test/basic.go @@ -1,31 +1,38 @@ -package test +package backendtest import ( "fmt" "fusenapi/server/backend/internal/config" "fusenapi/server/backend/internal/handler" "fusenapi/server/backend/internal/svc" + homeuserauthtest "fusenapi/server/home-user-auth/test" + "fusenapi/utils/fstests" "log" + "runtime" "github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/rest" ) -var testConfigFile = "../etc/backend.yaml" var cnf config.Config -var gserver *rest.Server +var userver, gserver *rest.Server func init() { log.SetFlags(log.Llongfile) + userver = homeuserauthtest.GetTestServer() gserver = GetTestServer() } func GetTestServer() *rest.Server { - conf.MustLoad(testConfigFile, &cnf) + conf.MustLoad(fstests.GetEtcYamlPathAuto(), &cnf) server := rest.MustNewServer(cnf.RestConf) - defer server.Stop() + runtime.SetFinalizer(server, func(server *rest.Server) { + if server != nil { + server.Stop() + } + }) ctx := svc.NewServiceContext(cnf) handler.RegisterHandlers(server, ctx) diff --git a/server/backend/test/quotationdetaillogic_test.go b/server/backend/test/quotationdetaillogic_test.go index 8f9fa837..847819cd 100644 --- a/server/backend/test/quotationdetaillogic_test.go +++ b/server/backend/test/quotationdetaillogic_test.go @@ -1,4 +1,4 @@ -package test +package backendtest import ( "fmt" diff --git a/server/backend/test/tpl_test.go b/server/backend/test/tpl_test.go index 3a8f2400..03ccdc82 100644 --- a/server/backend/test/tpl_test.go +++ b/server/backend/test/tpl_test.go @@ -1,4 +1,4 @@ -package test +package backendtest import ( "bytes" diff --git a/server/home-user-auth/home-user-auth.go b/server/home-user-auth/home-user-auth.go index be8c4ead..7e44ddff 100644 --- a/server/home-user-auth/home-user-auth.go +++ b/server/home-user-auth/home-user-auth.go @@ -29,23 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// 测试代码 可以直接复制新建 - -// var testConfigFile = flag.String("f", "../etc/home-user-auth.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/home-user-auth/test/acceptcookielogic_test.go b/server/home-user-auth/test/acceptcookielogic_test.go index 136688e4..64af9e82 100644 --- a/server/home-user-auth/test/acceptcookielogic_test.go +++ b/server/home-user-auth/test/acceptcookielogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/basic.go b/server/home-user-auth/test/basic.go index 4b56bde8..0c71b381 100644 --- a/server/home-user-auth/test/basic.go +++ b/server/home-user-auth/test/basic.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" @@ -6,6 +6,7 @@ import ( "fusenapi/server/home-user-auth/internal/handler" "fusenapi/server/home-user-auth/internal/svc" "fusenapi/utils/fstests" + "runtime" "log" @@ -13,7 +14,6 @@ import ( "github.com/zeromicro/go-zero/rest" ) -var testConfigFile = "home-user-auth" var cnf config.Config var gserver *rest.Server @@ -24,10 +24,14 @@ func init() { func GetTestServer() *rest.Server { - conf.MustLoad(fstests.GetEtcYamlPathAuto(testConfigFile), &cnf) + conf.MustLoad(fstests.GetEtcYamlPathAuto(), &cnf) server := rest.MustNewServer(cnf.RestConf) - defer server.Stop() + runtime.SetFinalizer(server, func(server *rest.Server) { + if server != nil { + server.Stop() + } + }) ctx := svc.NewServiceContext(cnf) handler.RegisterHandlers(server, ctx) diff --git a/server/home-user-auth/test/useraddaddresslogic_test.go b/server/home-user-auth/test/useraddaddresslogic_test.go index 7305c1e5..37cf260c 100644 --- a/server/home-user-auth/test/useraddaddresslogic_test.go +++ b/server/home-user-auth/test/useraddaddresslogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/useraddresslistlogic_test.go b/server/home-user-auth/test/useraddresslistlogic_test.go index 25a85ae1..97ac3306 100644 --- a/server/home-user-auth/test/useraddresslistlogic_test.go +++ b/server/home-user-auth/test/useraddresslistlogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/userbasicinfologic_test.go b/server/home-user-auth/test/userbasicinfologic_test.go index f365f679..a98aa656 100644 --- a/server/home-user-auth/test/userbasicinfologic_test.go +++ b/server/home-user-auth/test/userbasicinfologic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/usercontactservicelogic_test.go b/server/home-user-auth/test/usercontactservicelogic_test.go index 590d52c2..2242162b 100644 --- a/server/home-user-auth/test/usercontactservicelogic_test.go +++ b/server/home-user-auth/test/usercontactservicelogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/userfontslogic_test.go b/server/home-user-auth/test/userfontslogic_test.go index feb51f6c..a79f5bb8 100644 --- a/server/home-user-auth/test/userfontslogic_test.go +++ b/server/home-user-auth/test/userfontslogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/usergettypelogic_test.go b/server/home-user-auth/test/usergettypelogic_test.go index 971a1034..6cc72a48 100644 --- a/server/home-user-auth/test/usergettypelogic_test.go +++ b/server/home-user-auth/test/usergettypelogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/useroderdeletelogic_test.go b/server/home-user-auth/test/useroderdeletelogic_test.go index 2e6e0309..c5526202 100644 --- a/server/home-user-auth/test/useroderdeletelogic_test.go +++ b/server/home-user-auth/test/useroderdeletelogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/home-user-auth/test/usersavebasicinfologic_test.go b/server/home-user-auth/test/usersavebasicinfologic_test.go index 2b7d6ac8..f8d4c5fc 100644 --- a/server/home-user-auth/test/usersavebasicinfologic_test.go +++ b/server/home-user-auth/test/usersavebasicinfologic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "encoding/json" diff --git a/server/home-user-auth/test/userstatusconfiglogic_test.go b/server/home-user-auth/test/userstatusconfiglogic_test.go index b9017d4a..3028418e 100644 --- a/server/home-user-auth/test/userstatusconfiglogic_test.go +++ b/server/home-user-auth/test/userstatusconfiglogic_test.go @@ -1,4 +1,4 @@ -package test +package homeuserauthtest import ( "fmt" diff --git a/server/inventory/inventory.go b/server/inventory/inventory.go index 83d3d6ed..576f18d6 100644 --- a/server/inventory/inventory.go +++ b/server/inventory/inventory.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/inventory.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/map-library/map-library.go b/server/map-library/map-library.go index 824d1f6c..823fe54d 100644 --- a/server/map-library/map-library.go +++ b/server/map-library/map-library.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/map-library.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/orders/orders.go b/server/orders/orders.go index d2bf841e..b8ae8605 100644 --- a/server/orders/orders.go +++ b/server/orders/orders.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/orders.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/product-model/product-model.go b/server/product-model/product-model.go index 67e2a1a0..85d3cbbf 100644 --- a/server/product-model/product-model.go +++ b/server/product-model/product-model.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/product-model.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/product-template/internal/logic/gettemplatevdetaillogic.go b/server/product-template/internal/logic/gettemplatevdetaillogic.go index 892ab9a5..dcce87fb 100644 --- a/server/product-template/internal/logic/gettemplatevdetaillogic.go +++ b/server/product-template/internal/logic/gettemplatevdetaillogic.go @@ -161,7 +161,7 @@ func (l *GetTemplatevDetailLogic) GetTemplatevDetail(req *types.GetTemplatevDeta optionModelInfoList := make([]interface{}, 0, len(model3dList)) for _, v := range model3dList { info := make(map[string]interface{}) - if v.ModelInfo != nil { + if v.ModelInfo != nil && *v.ModelInfo != "" { if err = json.Unmarshal([]byte(*v.ModelInfo), &info); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to parse model info") diff --git a/server/product-template/product-template.go b/server/product-template/product-template.go index 1be70a8a..7218da3e 100644 --- a/server/product-template/product-template.go +++ b/server/product-template/product-template.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/product-templatev2.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server/product/internal/handler/routes.go b/server/product/internal/handler/routes.go index 023a5800..d644038e 100644 --- a/server/product/internal/handler/routes.go +++ b/server/product/internal/handler/routes.go @@ -42,6 +42,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/product/info", Handler: GetProductInfoHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/product/save-design", + Handler: SaveDesignHandler(serverCtx), + }, }, ) } diff --git a/server/product/internal/handler/savedesignhandler.go b/server/product/internal/handler/savedesignhandler.go new file mode 100644 index 00000000..9c69607a --- /dev/null +++ b/server/product/internal/handler/savedesignhandler.go @@ -0,0 +1,78 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/product/internal/logic" + "fusenapi/server/product/internal/svc" + "fusenapi/server/product/internal/types" +) + +func SaveDesignHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.SaveDesignReq + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + // 创建一个业务逻辑层实例 + l := logic.NewSaveDesignLogic(r.Context(), svcCtx) + resp := l.SaveDesign(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/product/internal/logic/getproductdesignlogic.go b/server/product/internal/logic/getproductdesignlogic.go index 85b63967..8882bec3 100644 --- a/server/product/internal/logic/getproductdesignlogic.go +++ b/server/product/internal/logic/getproductdesignlogic.go @@ -83,7 +83,7 @@ func (l *GetProductDesignLogic) GetProductDesign(req *types.GetProductDesignReq, return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetProductDesignRsp{ ProductId: *designInfo.ProductId, TemplateId: *designInfo.TemplateId, - MaterialId: *designInfo.MaterialId, + //MaterialId: *designInfo.MaterialId, SizeId: *designInfo.SizeId, OptionalId: optionalId, Cover: *designInfo.Cover, diff --git a/server/product/internal/logic/getproductinfologic.go b/server/product/internal/logic/getproductinfologic.go index 852d89be..b9a43ca8 100644 --- a/server/product/internal/logic/getproductinfologic.go +++ b/server/product/internal/logic/getproductinfologic.go @@ -1,20 +1,9 @@ package logic import ( - "encoding/json" - "errors" - "fmt" - "fusenapi/constants" + "context" "fusenapi/utils/auth" "fusenapi/utils/basic" - "fusenapi/utils/format" - "fusenapi/utils/image" - "strconv" - "strings" - - "gorm.io/gorm" - - "context" "fusenapi/server/product/internal/svc" "fusenapi/server/product/internal/types" @@ -38,7 +27,7 @@ func NewGetProductInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ge func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, userinfo *auth.UserInfo) (resp *basic.Response) { //获取产品信息 - productInfo, err := l.svcCtx.AllModels.FsProduct.FindOneBySn(l.ctx, req.Pid) + /*productInfo, err := l.svcCtx.AllModels.FsProduct.FindOneBySn(l.ctx, req.Pid) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not exists") @@ -262,7 +251,8 @@ func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, useri temBytes, _ := json.Marshal(allModel3dList[key]) _ = json.Unmarshal(temBytes, &thisInfo) } - } + }*/ + //************************************************** /* //循环处理组装模板信息 foreach ($templates as $temp) { diff --git a/server/product/internal/logic/savedesignlogic.go b/server/product/internal/logic/savedesignlogic.go new file mode 100644 index 00000000..21d2c226 --- /dev/null +++ b/server/product/internal/logic/savedesignlogic.go @@ -0,0 +1,168 @@ +package logic + +import ( + "encoding/json" + "errors" + "fmt" + "fusenapi/constants" + "fusenapi/model/gmodel" + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/encryption_decryption" + "fusenapi/utils/id_generator" + "github.com/google/uuid" + "github.com/nfnt/resize" + "gorm.io/gorm" + "image" + "image/gif" + "image/jpeg" + "image/png" + "net/http" + "os" + "path" + "time" + + "context" + + "fusenapi/server/product/internal/svc" + "fusenapi/server/product/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type SaveDesignLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewSaveDesignLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SaveDesignLogic { + return &SaveDesignLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *SaveDesignLogic) SaveDesign(req *types.SaveDesignReq, userinfo *auth.UserInfo) (resp *basic.Response) { + if userinfo.GetIdType() != auth.IDTYPE_User { + return resp.SetStatusWithMessage(basic.CodeUnAuth, "please login first") + } + //查询是否是加密的(不太合理) + encryptWebsetting, err := l.svcCtx.AllModels.FsWebSet.FindValueByKey(l.ctx, "is_encrypt") + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "web setting is_encrypt is not exists") + } + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get web setting") + } + var postInfo types.SaveDesignReqRealStruct + //不加密 + if encryptWebsetting.Value == nil || *encryptWebsetting.Value == "0" { + if err = json.Unmarshal([]byte(req.Data), &postInfo); err != nil { + return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse json data,format may be invalid") + } + } else { //加密的 + //解密数据 + desData, err := encryption_decryption.CBCDecrypt(req.Data) + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "failed to decryption data") + } + if err = json.Unmarshal([]byte(desData), &postInfo); err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse json data") + } + } + infoBytes, _ := json.Marshal(postInfo.Data) + info := string(infoBytes) + now := time.Now() + logoColorBytes, _ := json.Marshal(postInfo.Data.Logo.Colors) + logoColor := string(logoColorBytes) + saveData := gmodel.FsProductDesign{ + UserId: &userinfo.UserId, + ProductId: &postInfo.ProductId, + TemplateId: &postInfo.TemplateId, + SizeId: &postInfo.SizeId, + OptionalId: &postInfo.OptionalId, + Cover: &postInfo.Cover, + Info: &info, + Utime: &now, + LogoColor: &logoColor, + PageGuid: &postInfo.PageGuid, + } + switch postInfo.Sn { + case "": //新增 + status := int64(1) + postInfo.Sn, err = id_generator.GenSnowFlakeId() + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to gen sn ") + } + saveData.Status = &status + saveData.Sn = &postInfo.Sn + err = l.svcCtx.AllModels.FsProductDesign.Create(l.ctx, &saveData) + default: //更新 + err = l.svcCtx.AllModels.FsProductDesign.UpdateBySn(l.ctx, postInfo.Sn, &saveData) + } + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to save design") + } + if postInfo.Cover == "" { + return resp.SetStatusWithMessage(basic.CodeOK, "success", types.SaveDesignRsp{Sn: postInfo.Sn}) + } + // TODO 图片待优化处理 + /*if err = l.CreateStepThumbnailImage(l.ctx, postInfo.Cover); err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to create step thumbnail image ") + }*/ + return resp.SetStatusWithMessage(basic.CodeOK, "success", types.SaveDesignRsp{Sn: postInfo.Sn}) +} + +// 创建阶梯缩略图 +func (l *SaveDesignLogic) CreateStepThumbnailImage(ctx context.Context, coverImage string) error { + httpRsp, err := http.Get(coverImage) + if err != nil { + return err + } + defer httpRsp.Body.Close() + coverImg, _, err := image.Decode(httpRsp.Body) + if err != nil { + return err + } + coverImgOrgWith := coverImg.Bounds().Dx() + coverImgOrgHeight := coverImg.Bounds().Dy() + fileExt := path.Ext(coverImage) + for _, size := range constants.IMAGE_CROPPING_STEP_SIZE { + //尺寸大于原图 + if size > coverImgOrgWith { + continue + } + //缩放比例按照宽度来设定 + scale := size / coverImgOrgWith + height := scale * coverImgOrgHeight + tmpImage := resize.Resize(uint(size), uint(height), coverImg, resize.Lanczos3) + fileName := fmt.Sprintf("%s_%d_%s", uuid.New().String(), size, fileExt) + targetFile, err := os.Create(fileName) + if err != nil { + return err + } + defer targetFile.Close() + switch fileExt { + case ".png": + err = png.Encode(targetFile, tmpImage) + case ".jpg", ".jpeg": + err = jpeg.Encode(targetFile, tmpImage, &jpeg.Options{Quality: 100}) + case ".gif": + err = gif.Encode(targetFile, tmpImage, nil) + default: + err = errors.New("unSupport image format") + } + if err != nil { + return err + } + } + return nil +} diff --git a/server/product/internal/types/types.go b/server/product/internal/types/types.go index 4d0e53ee..7d794ee4 100644 --- a/server/product/internal/types/types.go +++ b/server/product/internal/types/types.go @@ -88,7 +88,6 @@ type GetProductDesignReq struct { type GetProductDesignRsp struct { ProductId int64 `json:"product_id"` TemplateId int64 `json:"template_id"` - MaterialId int64 `json:"material_id"` SizeId int64 `json:"size_id"` OptionalId int64 `json:"optional_id"` Cover string `json:"cover"` @@ -151,6 +150,75 @@ type MaterialItem struct { Title string `json:"title"` } +type SaveDesignReq struct { + Data string `json:"data"` //加密信息 +} + +type SaveDesignRsp struct { + Sn string `json:"sn"` +} + +type SaveDesignReqRealStruct struct { + ProductId int64 `json:"product_id"` + SizeId int64 `json:"size_id"` + OptionalId int64 `json:"optional_id"` + TemplateId int64 `json:"template_id"` + Sn string `json:"sn"` + Data DesignData `json:"data"` + Cover string `json:"cover"` + PageGuid string `json:"pageGuid"` +} + +type DesignData struct { + MainColor ColorFill `json:"MainColor"` + SecondaryColor ColorFill `json:"SecondaryColor"` + Logo DesignLogo `json:"Logo"` + Slogan DesignSlogan `json:"Slogan"` + QRcode DesignQRcode `json:"QRcode"` + Website DesignWebsite `json:"Website"` + Phone DesignPhone `json:"Phone"` + Address DesignAddress `json:"Address"` +} + +type DesignAddress struct { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} + +type DesignPhone struct { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} + +type DesignWebsite struct { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} + +type DesignQRcode struct { + Text string `json:"text"` + SvgPath string `json:"svgPath"` + IfShow bool `json:"ifShow"` +} + +type DesignSlogan struct { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} + +type DesignLogo struct { + Material string `json:"material"` + MaterialName string `json:"materialName"` + MaterialTime string `json:"materialTime"` + Fill string `json:"fill"` + FillName string `json:"fill_name"` + Colors []string `json:"colors"` +} + +type ColorFill struct { + Fill string `json:"fill"` +} + type Request struct { } diff --git a/server/upload/etc/upload.yaml b/server/upload/etc/upload.yaml new file mode 100644 index 00000000..b67542b9 --- /dev/null +++ b/server/upload/etc/upload.yaml @@ -0,0 +1,15 @@ +Name: upload +Host: 0.0.0.0 +Port: 8888 +SourceMysql: "fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest" +Env: "test" +Auth: + AccessSecret: fusen2023 + AccessExpire: 604800 + RefreshAfter: 345600 +AWS: + S3: + Credentials: + AccessKeyID: AKIAZB2JKUXDPNRP4YT2 + Secret: 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 + Token: \ No newline at end of file diff --git a/server/upload/internal/config/config.go b/server/upload/internal/config/config.go new file mode 100644 index 00000000..a8d273d7 --- /dev/null +++ b/server/upload/internal/config/config.go @@ -0,0 +1,23 @@ +package config + +import ( + "fusenapi/server/upload/internal/types" + + "github.com/zeromicro/go-zero/rest" +) + +type Config struct { + rest.RestConf + SourceMysql string + Auth types.Auth + Env string + AWS struct { + S3 struct { + Credentials struct { + AccessKeyID string + Secret string + Token string + } + } + } +} diff --git a/server/upload/internal/handler/routes.go b/server/upload/internal/handler/routes.go new file mode 100644 index 00000000..0ef94f41 --- /dev/null +++ b/server/upload/internal/handler/routes.go @@ -0,0 +1,32 @@ +// Code generated by goctl. DO NOT EDIT. +package handler + +import ( + "net/http" + + "fusenapi/server/upload/internal/svc" + + "github.com/zeromicro/go-zero/rest" +) + +func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { + server.AddRoutes( + []rest.Route{ + { + Method: http.MethodGet, + Path: "/upload/up-file", + Handler: UploadUpFileHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/upload/upload-file-frontend", + Handler: UploadFileFrontendHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/upload/upload-file-backend", + Handler: UploadFileBackendHandler(serverCtx), + }, + }, + ) +} diff --git a/server/upload/internal/handler/uploadfilebackendhandler.go b/server/upload/internal/handler/uploadfilebackendhandler.go new file mode 100644 index 00000000..a3f72895 --- /dev/null +++ b/server/upload/internal/handler/uploadfilebackendhandler.go @@ -0,0 +1,89 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/upload/internal/logic" + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" +) + +func UploadFileBackendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.RequestUploadFileBackend + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + + // 解析upload文件类型 + err = basic.RequestFileParse(r, &req) + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: err.Error(), + }) + return + } + + // 创建一个业务逻辑层实例 + l := logic.NewUploadFileBackendLogic(r.Context(), svcCtx) + resp := l.UploadFileBackend(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/upload/internal/handler/uploadfilefrontendhandler.go b/server/upload/internal/handler/uploadfilefrontendhandler.go new file mode 100644 index 00000000..ca38a4f0 --- /dev/null +++ b/server/upload/internal/handler/uploadfilefrontendhandler.go @@ -0,0 +1,78 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/upload/internal/logic" + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" +) + +func UploadFileFrontendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.RequestUploadFileFrontend + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + // 创建一个业务逻辑层实例 + l := logic.NewUploadFileFrontendLogic(r.Context(), svcCtx) + resp := l.UploadFileFrontend(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/upload/internal/handler/uploadupfilehandler.go b/server/upload/internal/handler/uploadupfilehandler.go new file mode 100644 index 00000000..49f742d0 --- /dev/null +++ b/server/upload/internal/handler/uploadupfilehandler.go @@ -0,0 +1,78 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/upload/internal/logic" + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" +) + +func UploadUpFileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.RequestUpFile + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + // 创建一个业务逻辑层实例 + l := logic.NewUploadUpFileLogic(r.Context(), svcCtx) + resp := l.UploadUpFile(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/upload/internal/logic/uploadfilebackendlogic.go b/server/upload/internal/logic/uploadfilebackendlogic.go new file mode 100644 index 00000000..6b43a0d6 --- /dev/null +++ b/server/upload/internal/logic/uploadfilebackendlogic.go @@ -0,0 +1,83 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/check" + "fusenapi/utils/format" + "time" + + "context" + + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/zeromicro/go-zero/core/logx" +) + +type UploadFileBackendLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUploadFileBackendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileBackendLogic { + return &UploadFileBackendLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UploadFileBackendLogic) UploadFileBackend(req *types.RequestUploadFileBackend, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + if userinfo.IsOnlooker() { + return resp.SetStatus(basic.CodeUnAuth) + } + + var uid int64 + var keytype format.TypeFormatS3KeyName + if userinfo.IsGuest() { + uid = userinfo.GuestId + keytype = format.TypeS3KeyGuest + } else { + uid = userinfo.UserId + keytype = format.TypeS3KeyUser + } + + l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1") + svc := s3.New(l.svcCtx.AwsSession) + + if !check.CheckCategory(req.Category) { + return resp.SetStatus(basic.CodeS3CategoryErr) + } + + now := time.Now() + s3req, _ := svc.PutObjectRequest( + &s3.PutObjectInput{ + Bucket: aws.String("storage.fusenpack.com"), + Key: aws.String(format.FormatS3KeyName( + keytype, + uid, + now, + l.svcCtx.Config.Env, + req.Category, + req.File.Filename, + )), + }, + ) + + s3req.SetBufferBody(req.File.Data) + err := s3req.Send() + if err != nil { + return resp.SetStatus(basic.CodeS3PutObjectRequestErr) + } + + return resp.SetStatus(basic.CodeOK, map[string]interface{}{ + "upload_url": s3req.HTTPRequest.URL.String(), + }) + +} diff --git a/server/upload/internal/logic/uploadfilefrontendlogic.go b/server/upload/internal/logic/uploadfilefrontendlogic.go new file mode 100644 index 00000000..b9396c67 --- /dev/null +++ b/server/upload/internal/logic/uploadfilefrontendlogic.go @@ -0,0 +1,88 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/check" + "fusenapi/utils/format" + "time" + + "context" + + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/zeromicro/go-zero/core/logx" +) + +type UploadFileFrontendLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUploadFileFrontendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileFrontendLogic { + return &UploadFileFrontendLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UploadFileFrontendLogic) UploadFileFrontend(req *types.RequestUploadFileFrontend, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + + if userinfo.IsOnlooker() { + return resp.SetStatus(basic.CodeUnAuth) + } + + var uid int64 + var keytype format.TypeFormatS3KeyName + if userinfo.IsGuest() { + uid = userinfo.GuestId + keytype = format.TypeS3KeyGuest + } else { + uid = userinfo.UserId + keytype = format.TypeS3KeyUser + } + + l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1") + svc := s3.New(l.svcCtx.AwsSession) + + if req.FileSize > 1024*1024*500 { + return resp.SetStatus(basic.CodeS3PutSizeLimitErr) + } + + if !check.CheckCategory(req.Category) { + return resp.SetStatus(basic.CodeS3CategoryErr) + } + + now := time.Now() + s3req, _ := svc.PutObjectRequest( + &s3.PutObjectInput{ + Bucket: aws.String("storage.fusenpack.com"), + Key: aws.String(format.FormatS3KeyName( + keytype, + uid, + now, + l.svcCtx.Config.Env, + req.Category, + req.FileName, + )), + ContentLength: aws.Int64(req.FileSize), + }, + ) + + uri, err := s3req.Presign(time.Minute * 5) + if err != nil { + return resp.SetStatus(basic.CodeS3PutObjectRequestErr) + } + // log.Println(uri) + + return resp.SetStatus(basic.CodeOK, map[string]interface{}{ + "upload_url": uri, + }) +} diff --git a/server/upload/internal/logic/uploadupfilelogic.go b/server/upload/internal/logic/uploadupfilelogic.go new file mode 100644 index 00000000..a6988c46 --- /dev/null +++ b/server/upload/internal/logic/uploadupfilelogic.go @@ -0,0 +1,34 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "context" + + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UploadUpFileLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUploadUpFileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadUpFileLogic { + return &UploadUpFileLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UploadUpFileLogic) UploadUpFile(req *types.RequestUpFile, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + + return resp.SetStatus(basic.CodeOK) +} diff --git a/server/upload/internal/svc/servicecontext.go b/server/upload/internal/svc/servicecontext.go new file mode 100644 index 00000000..dacb4db0 --- /dev/null +++ b/server/upload/internal/svc/servicecontext.go @@ -0,0 +1,71 @@ +package svc + +import ( + "errors" + "fmt" + "fusenapi/server/upload/internal/config" + "net/http" + + "fusenapi/initalize" + "fusenapi/model/gmodel" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/golang-jwt/jwt" + "gorm.io/gorm" +) + +type ServiceContext struct { + Config config.Config + + MysqlConn *gorm.DB + AllModels *gmodel.AllModelsGen + AwsSession *session.Session +} + +func NewServiceContext(c config.Config) *ServiceContext { + + config := aws.Config{ + Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token), + } + + // config.Region = aws.String("us-west-1") + + return &ServiceContext{ + Config: c, + MysqlConn: initalize.InitMysql(c.SourceMysql), + AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), + AwsSession: session.Must(session.NewSession(&config)), + } +} + +func (svcCtx *ServiceContext) ParseJwtToken(r *http.Request) (jwt.MapClaims, error) { + AuthKey := r.Header.Get("Authorization") + if AuthKey == "" { + return nil, nil + } + + if len(AuthKey) <= 50 { + return nil, errors.New(fmt.Sprint("Error parsing token, len:", len(AuthKey))) + } + + token, err := jwt.Parse(AuthKey, func(token *jwt.Token) (interface{}, error) { + // 检查签名方法是否为 HS256 + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + // 返回用于验证签名的密钥 + return []byte(svcCtx.Config.Auth.AccessSecret), nil + }) + if err != nil { + return nil, errors.New(fmt.Sprint("Error parsing token:", err)) + } + + // 验证成功返回 + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + return claims, nil + } + + return nil, errors.New(fmt.Sprint("Invalid token", err)) +} diff --git a/server/upload/internal/types/types.go b/server/upload/internal/types/types.go new file mode 100644 index 00000000..28ea0c8f --- /dev/null +++ b/server/upload/internal/types/types.go @@ -0,0 +1,93 @@ +// Code generated by goctl. DO NOT EDIT. +package types + +import ( + "fusenapi/utils/basic" +) + +type RequestUpFile struct { + UpFile string `form:"upfile"` + IsCut string `form:"is_cut"` // 是否裁剪 +} + +type RequestUploadFileFrontend struct { + FileName string `json:"file_name"` // 文件名 + FileType string `json:"file_type"` // Image / fbx / hdr + FileSize int64 `json:"file_size"` // 文件大小 + Category string `json:"category"` // 类别 +} + +type RequestUploadFileBackend struct { + File File `file:"file"` // 文件名 + FileType string `form:"file_type"` // Image / fbx / hdr + Category string `form:"category"` // 类别 +} + +type Request struct { +} + +type Response struct { + Code int `json:"code"` + Message string `json:"msg"` + Data interface{} `json:"data"` +} + +type Auth struct { + AccessSecret string `json:"accessSecret"` + AccessExpire int64 `json:"accessExpire"` + RefreshAfter int64 `json:"refreshAfter"` +} + +type File struct { + Filename string `fsfile:"filename"` + Header map[string][]string `fsfile:"header"` + Size int64 `fsfile:"size"` + Data []byte `fsfile:"data"` +} + +type Meta struct { + TotalCount int64 `json:"totalCount"` + PageCount int64 `json:"pageCount"` + CurrentPage int `json:"currentPage"` + PerPage int `json:"perPage"` +} + +// Set 设置Response的Code和Message值 +func (resp *Response) Set(Code int, Message string) *Response { + return &Response{ + Code: Code, + Message: Message, + } +} + +// Set 设置整个Response +func (resp *Response) SetWithData(Code int, Message string, Data interface{}) *Response { + return &Response{ + Code: Code, + Message: Message, + Data: Data, + } +} + +// SetStatus 设置默认StatusResponse(内部自定义) 默认msg, 可以带data, data只使用一个参数 +func (resp *Response) SetStatus(sr *basic.StatusResponse, data ...interface{}) *Response { + newResp := &Response{ + Code: sr.Code, + } + if len(data) == 1 { + newResp.Data = data[0] + } + return newResp +} + +// SetStatusWithMessage 设置默认StatusResponse(内部自定义) 非默认msg, 可以带data, data只使用一个参数 +func (resp *Response) SetStatusWithMessage(sr *basic.StatusResponse, msg string, data ...interface{}) *Response { + newResp := &Response{ + Code: sr.Code, + Message: msg, + } + if len(data) == 1 { + newResp.Data = data[0] + } + return newResp +} diff --git a/server/upload/test/basic.go b/server/upload/test/basic.go index 11999937..606e0c0f 100644 --- a/server/upload/test/basic.go +++ b/server/upload/test/basic.go @@ -2,36 +2,38 @@ package test import ( "fmt" - "fusenapi/server/home-user-auth/test" + homeuserauthtest "fusenapi/server/home-user-auth/test" "fusenapi/server/upload/internal/config" "fusenapi/server/upload/internal/handler" "fusenapi/server/upload/internal/svc" "fusenapi/utils/fstests" "log" + "runtime" "github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/rest" ) -var env = "test" - -var testConfigFile = "upload.yaml" var cnf config.Config -var userServer *rest.Server -var gserver *rest.Server + +var userver, gserver *rest.Server func init() { log.SetFlags(log.Llongfile) - userServer = test.GetTestServer() + userver = homeuserauthtest.GetTestServer() gserver = GetTestServer() } func GetTestServer() *rest.Server { - conf.MustLoad(fstests.GetEtcYamlPathAuto(fstests.GetCurrentServiceName()+".yaml"), &cnf) - + // log.Println(fstests.GetEtcYamlPathAuto()) + conf.MustLoad(fstests.GetEtcYamlPathAuto(), &cnf) server := rest.MustNewServer(cnf.RestConf) - defer server.Stop() + runtime.SetFinalizer(server, func(server *rest.Server) { + if server != nil { + server.Stop() + } + }) ctx := svc.NewServiceContext(cnf) handler.RegisterHandlers(server, ctx) diff --git a/server/upload/test/uploadfilefrontendhandler_test.go b/server/upload/test/uploadfilefrontendhandler_test.go index 63373e57..b65f7b07 100644 --- a/server/upload/test/uploadfilefrontendhandler_test.go +++ b/server/upload/test/uploadfilefrontendhandler_test.go @@ -18,7 +18,7 @@ func TestCaseUploadfileFrontend(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSessionWithUserToken(t, userServer, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, userver, cnf.Host, cnf.Port) tp := ses.Post(fmt.Sprintf("http://%s:%d/upload/upload-file-frontend", cnf.Host, cnf.Port)) data, err := ioutil.ReadFile("./fusen.webp") @@ -27,7 +27,7 @@ func TestCaseUploadfileFrontend(t *testing.T) { return } - req := types.RequestUploadFile{ + req := types.RequestUploadFileFrontend{ FileName: "fusen.webp", FileType: "image", FileSize: int64(len(data)), Category: "personalization", } @@ -55,13 +55,14 @@ func TestCaseUploadfileFrontend(t *testing.T) { uri := result.Get("data.upload_url").String() tpUpload := requests.NewSession().Put(uri) - tpUpload.SetBodyStream(data) resp, err = tpUpload.Execute() if err != nil { - panic(err) + t.Error(err) } - log.Println(resp.Json()) + if resp.GetStatusCode() != 200 { + t.Error("put failed") + } } diff --git a/server/upload/upload.go b/server/upload/upload.go new file mode 100644 index 00000000..ed185b9c --- /dev/null +++ b/server/upload/upload.go @@ -0,0 +1,31 @@ +package main + +import ( + "flag" + "fmt" + + "fusenapi/server/upload/internal/config" + "fusenapi/server/upload/internal/handler" + "fusenapi/server/upload/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/rest" +) + +var configFile = flag.String("f", "etc/upload.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + + server := rest.MustNewServer(c.RestConf) + defer server.Stop() + + ctx := svc.NewServiceContext(c) + handler.RegisterHandlers(server, ctx) + + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) + server.Start() +} diff --git a/server/upload/upload_test.go b/server/upload/upload_test.go new file mode 100644 index 00000000..ef649768 --- /dev/null +++ b/server/upload/upload_test.go @@ -0,0 +1,7 @@ +package main + +import "testing" + +func TestMain(t *testing.T) { + main() +} diff --git a/server/webset/test/basic.go b/server/webset/test/basic.go index e8c7e486..3a8a2151 100644 --- a/server/webset/test/basic.go +++ b/server/webset/test/basic.go @@ -1,31 +1,38 @@ -package logic +package wetset_test import ( "fmt" + homeuserauthtest "fusenapi/server/home-user-auth/test" "fusenapi/server/webset/internal/config" "fusenapi/server/webset/internal/handler" "fusenapi/server/webset/internal/svc" + "fusenapi/utils/fstests" "log" + "runtime" "github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/rest" ) -var testConfigFile = "../etc/wetset.yaml" var cnf config.Config -var gserver *rest.Server +var userver, gserver *rest.Server func init() { log.SetFlags(log.Llongfile) + userver = homeuserauthtest.GetTestServer() gserver = GetTestServer() } func GetTestServer() *rest.Server { - conf.MustLoad(testConfigFile, &cnf) + conf.MustLoad(fstests.GetEtcYamlPathAuto(), &cnf) server := rest.MustNewServer(cnf.RestConf) - defer server.Stop() + runtime.SetFinalizer(server, func(server *rest.Server) { + if server != nil { + server.Stop() + } + }) ctx := svc.NewServiceContext(cnf) handler.RegisterHandlers(server, ctx) diff --git a/server/webset/test/wetset_test.go b/server/webset/test/wetset_test.go index ff783f3b..44dd81cb 100644 --- a/server/webset/test/wetset_test.go +++ b/server/webset/test/wetset_test.go @@ -1,4 +1,4 @@ -package logic +package wetset_test import ( "fmt" diff --git a/server/webset/wetset.go b/server/webset/wetset.go index d667e463..196bbd76 100644 --- a/server/webset/wetset.go +++ b/server/webset/wetset.go @@ -29,21 +29,3 @@ func main() { fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } - -// var testConfigFile = flag.String("f", "../etc/wetset.yaml", "the config file") -// var cnf config.Config - -// func GetTestServer() *rest.Server { -// flag.Parse() - -// conf.MustLoad(*testConfigFile, &cnf) - -// server := rest.MustNewServer(cnf.RestConf) -// defer server.Stop() - -// ctx := svc.NewServiceContext(cnf) -// handler.RegisterHandlers(server, ctx) - -// fmt.Printf("Starting server at %s:%d...\n", cnf.Host, cnf.Port) -// return server -// } diff --git a/server_api/basic.api b/server_api/basic.api index e05b76d5..58dac0b5 100644 --- a/server_api/basic.api +++ b/server_api/basic.api @@ -25,6 +25,15 @@ type Auth { RefreshAfter int64 `json:"refreshAfter"` } +// File 文件 +type File { + Filename string `fsfile:"filename"` + Header map[string][]string `fsfile:"header"` + Size int64 `fsfile:"size"` + Data []byte `fsfile:"data"` +} + + // 统一分页 type Meta struct { TotalCount int64 `json:"totalCount"` diff --git a/server_api/product.api b/server_api/product.api index 324a8cb8..96d6002a 100644 --- a/server_api/product.api +++ b/server_api/product.api @@ -28,6 +28,9 @@ service product { //获取产品信息 @handler GetProductInfoHandler get /product/info(GetProductInfoReq) returns (response); + //保存设计信息 + @handler SaveDesignHandler + post /product/save-design(SaveDesignReq) returns (response); } //获取产品列表 @@ -99,15 +102,14 @@ type PriceObj { Num int `json:"num"` Price float64 `json:"price"` } - //获取保存的设计信息 type GetProductDesignReq { Sn string `form:"sn"` } type GetProductDesignRsp { - ProductId int64 `json:"product_id"` - TemplateId int64 `json:"template_id"` - MaterialId int64 `json:"material_id"` + ProductId int64 `json:"product_id"` + TemplateId int64 `json:"template_id"` + //MaterialId int64 `json:"material_id"` SizeId int64 `json:"size_id"` OptionalId int64 `json:"optional_id"` Cover string `json:"cover"` @@ -162,4 +164,65 @@ type SizeTitle { type MaterialItem { Id int64 `json:"id"` Title string `json:"title"` +} +//保存设计信息 +type SaveDesignReq { + Data string `json:"data"` //加密信息 +} +type SaveDesignRsp { + Sn string `json:"sn"` +} +//保存设计信息(解密结构体) +type SaveDesignReqRealStruct { + ProductId int64 `json:"product_id"` + SizeId int64 `json:"size_id"` + OptionalId int64 `json:"optional_id"` + TemplateId int64 `json:"template_id"` + Sn string `json:"sn"` + Data DesignData `json:"data"` + Cover string `json:"cover"` + PageGuid string `json:"pageGuid"` +} + +type DesignData { + MainColor ColorFill `json:"MainColor"` + SecondaryColor ColorFill `json:"SecondaryColor"` + Logo DesignLogo `json:"Logo"` + Slogan DesignSlogan `json:"Slogan"` + QRcode DesignQRcode `json:"QRcode"` + Website DesignWebsite `json:"Website"` + Phone DesignPhone `json:"Phone"` + Address DesignAddress `json:"Address"` +} +type DesignAddress { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} +type DesignPhone { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} +type DesignWebsite { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} +type DesignQRcode { + Text string `json:"text"` + SvgPath string `json:"svgPath"` + IfShow bool `json:"ifShow"` +} +type DesignSlogan { + Text string `json:"text"` + IfShow bool `json:"ifShow"` +} +type DesignLogo { + Material string `json:"material"` + MaterialName string `json:"materialName"` + MaterialTime string `json:"materialTime"` + Fill string `json:"fill"` + FillName string `json:"fill_name"` + Colors []string `json:"colors"` +} +type ColorFill { + Fill string `json:"fill"` } \ No newline at end of file diff --git a/server_api/upload.api b/server_api/upload.api index a05abcd4..c5b0e56f 100644 --- a/server_api/upload.api +++ b/server_api/upload.api @@ -14,20 +14,26 @@ type RequestUpFile { IsCut string `form:"is_cut"` // 是否裁剪 } -type RequestUploadFile { +type RequestUploadFileFrontend { FileName string `json:"file_name"` // 文件名 FileType string `json:"file_type"` // Image / fbx / hdr FileSize int64 `json:"file_size"` // 文件大小 Category string `json:"category"` // 类别 } +type RequestUploadFileBackend { + File File `file:"file"` // 文件名 + FileType string `form:"file_type"` // Image / fbx / hdr + Category string `form:"category"` // 类别 +} + service upload { @handler UploadUpFileHandler get /upload/up-file(RequestUpFile) returns (response); @handler UploadFileFrontendHandler - post /upload/upload-file-frontend(RequestUploadFile) returns (response); + post /upload/upload-file-frontend(RequestUploadFileFrontend) returns (response); @handler UploadFileBackendHandler - post /upload/upload-file-backend(RequestUploadFile) returns (response); + post /upload/upload-file-backend(RequestUploadFileBackend) returns (response); } \ No newline at end of file diff --git a/utils/basic/basic.go b/utils/basic/basic.go index 79eb86bc..257fa6bd 100644 --- a/utils/basic/basic.go +++ b/utils/basic/basic.go @@ -1,5 +1,24 @@ package basic +import ( + "fmt" + "io" + "net/http" + "reflect" + + "github.com/zeromicro/go-zero/core/logx" +) + +const UploadFileLimitSize = 200 << 20 + +// File uploadfile 文件(multipart...) +type File struct { + Filename string + Header map[string][]string + Size int64 + Data []byte +} + // StatusResponse 公司自定义状态码 type StatusResponse struct { Code int // 状态码 @@ -136,3 +155,75 @@ func (resp *Response) SetStatusAddMessage(sr *StatusResponse, msg string, data . } return newResp } + +var fileType = reflect.TypeOf(File{}) + +func RequestFileParse(r *http.Request, req any) error { + vreq := reflect.ValueOf(req) + if vreq.Kind() != reflect.Ptr { + panic("req must &req pass") + } + + reqValue := vreq.Elem() + reqType := reqValue.Type() + for i := 0; i < reqType.NumField(); i++ { + if tname, ok := reqType.Field(i).Tag.Lookup("file"); ok { + file, fheader, err := r.FormFile(tname) + if err != nil { + logx.Info("upload file error") + return err + } + + if fheader.Size > UploadFileLimitSize { + err = fmt.Errorf("upload file size over limit %d", UploadFileLimitSize) + logx.Info(err) + return err + } + + data, err := io.ReadAll(file) + if err != nil { + logx.Info("upload file data error") + return err + } + err = file.Close() + if err != nil { + logx.Info("file close error") + return err + } + + field := reqValue.Field(i) + + // aa1: + // field.Field(0).Set(fheader.Filename) + // field.Field(1).Set( fheader.Header) + // field.Field(2).Set( fheader.Size) + // field.Field(3).Set( data) + + if field.Kind() == reflect.Ptr { + if field.IsNil() { + fsfile := reflect.New(field.Type().Elem()) + fsfile = fsfile.Elem() + fsfile.Field(0).Set(reflect.ValueOf(fheader.Filename)) + fsfile.Field(1).Set(reflect.ValueOf(fheader.Header)) + fsfile.Field(2).Set(reflect.ValueOf(fheader.Size)) + fsfile.Field(3).Set(reflect.ValueOf(data)) + field.Set(fsfile.Addr()) + } else { + field = field.Elem() + field.Field(0).Set(reflect.ValueOf(fheader.Filename)) + field.Field(1).Set(reflect.ValueOf(fheader.Header)) + field.Field(2).Set(reflect.ValueOf(fheader.Size)) + field.Field(3).Set(reflect.ValueOf(data)) + } + } else { + field.Field(0).Set(reflect.ValueOf(fheader.Filename)) + field.Field(1).Set(reflect.ValueOf(fheader.Header)) + field.Field(2).Set(reflect.ValueOf(fheader.Size)) + field.Field(3).Set(reflect.ValueOf(data)) + } + + } + } + + return nil +} diff --git a/utils/check/check.go b/utils/check/check.go new file mode 100644 index 00000000..9212d373 --- /dev/null +++ b/utils/check/check.go @@ -0,0 +1,61 @@ +package check + +import ( + "errors" + "regexp" + "strings" + "unicode/utf8" +) + +var category = map[string]bool{ + "personalization": true, +} + +// CheckCategory 检查是否存在该类型 +func CheckCategory(key string) bool { + _, ok := category[key] + return ok +} + +// CheckValidS3Key 检查s3的文件名是否符合要求 +func CheckValidS3Key(key string) (bool, error) { + if utf8.RuneCountInString(key) > 1024 { + return false, errors.New("对象键长度超过 1024 字节") + } + + if strings.HasPrefix(key, "/") || strings.HasPrefix(key, ".") { + return false, errors.New("对象键不应以 / 或 . 开头") + } + + if !utf8.ValidString(key) { + return false, errors.New("对象键必须是 UTF-8 字符串") + } + + if hasControlCharacters(key) { + return false, errors.New("对象键包含控制字符") + } + + if hasInvalidPatterns(key) { + return false, errors.New("对象键包含无效的字符或模式") + } + + return true, nil +} + +func hasControlCharacters(key string) bool { + controlCharPattern := "[\\x00-\\x1F\\x7F]" + match, _ := regexp.MatchString(controlCharPattern, key) + return match +} + +func hasInvalidPatterns(key string) bool { + invalidPatterns := []string{"[\\s]+$", "^\\s+", "\\\\", "//", "\\.\\."} + for _, pattern := range invalidPatterns { + match, _ := regexp.MatchString(pattern, key) + if match { + return true + } + } + + return false +} diff --git a/utils/format/s3keyname.go b/utils/format/s3keyname.go new file mode 100644 index 00000000..b02a84ac --- /dev/null +++ b/utils/format/s3keyname.go @@ -0,0 +1,53 @@ +package format + +import ( + "fmt" + "strings" + "time" +) + +type TypeFormatS3KeyName int + +const ( + TypeS3KeyUser TypeFormatS3KeyName = 1 // 登录用户 + TypeS3KeyGuest TypeFormatS3KeyName = 2 // 游客 +) + +// FormatS3KeyName 需要输入选 +func FormatS3KeyName(keytype TypeFormatS3KeyName, uid int64, now time.Time, env, category, name string) string { + if keytype == TypeS3KeyUser { + return FormatS3KeyNameUser(uid, now, env, category, name) + } else if keytype == TypeS3KeyGuest { + return FormatS3KeyNameGuest(uid, now, env, category, name) + } else { + panic("key type error") + } +} + +// FormatS3KeyNameUser +func FormatS3KeyNameUser(userid int64, now time.Time, env, category, name string) string { + year, month, _ := now.Date() + names := strings.Split(name, ".") + var ext string + if len(names) == 1 { + name = names[0] + } else if len(names) == 2 { + name = names[0] + ext = names[1] + } + return fmt.Sprintf("/%s/%s/%d/%04d%02d/%s_%d.%s", env, category, userid, year, int(month), name, now.Unix(), ext) +} + +// FormatS3KeyNameGuest 游客的格式化存储 +func FormatS3KeyNameGuest(guestid int64, now time.Time, env, category, name string) string { + year, month, _ := now.Date() + names := strings.Split(name, ".") + var ext string + if len(names) == 1 { + name = names[0] + } else if len(names) == 2 { + name = names[0] + ext = names[1] + } + return fmt.Sprintf("/%s/guest/%s/%d/%04d%02d/%s_%d.%s", env, category, guestid, year, int(month), name, now.Unix(), ext) +} diff --git a/utils/format/str_to_int_slice.go b/utils/format/str_to_int_slice.go index 8ddfc4b5..eadf497a 100644 --- a/utils/format/str_to_int_slice.go +++ b/utils/format/str_to_int_slice.go @@ -7,11 +7,11 @@ import ( // 字符串切片转int切片 func StrSlicToIntSlice(input []string) ([]int, error) { newSlic := make([]int, 0, len(input)) - for _, p := range input { - if p == "" { + for _, element := range input { + if element == "" { continue } - val, err := strconv.Atoi(p) + val, err := strconv.Atoi(element) if err != nil { return nil, err } @@ -23,11 +23,11 @@ func StrSlicToIntSlice(input []string) ([]int, error) { // 字符串切片转int64切片 func StrSlicToInt64Slice(input []string) ([]int64, error) { newSlic := make([]int64, 0, len(input)) - for _, p := range input { - if p == "" { + for _, element := range input { + if element == "" { continue } - val, err := strconv.ParseInt(p, 10, 64) + val, err := strconv.ParseInt(element, 10, 64) if err != nil { return nil, err } diff --git a/utils/fstests/basic.go b/utils/fstests/basic.go new file mode 100644 index 00000000..1c19783f --- /dev/null +++ b/utils/fstests/basic.go @@ -0,0 +1,154 @@ +package fstests + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/474420502/requests" +) + +func GetEtcYamlPathAuto() string { + var currentFilePath string + var ok bool + for i := 1; i < 4; i++ { + _, currentFilePath, _, ok = runtime.Caller(i) + if !ok { + panic("Error: Unable to get the current file path.") + + } + dirs := strings.Split(currentFilePath, "/") + if dirs[len(dirs)-2] != "fstests" { + break + } + } + + curdir, err := filepath.Abs(currentFilePath) + if err != nil { + panic(err) + + } + + curdir = filepath.Dir(curdir) + var limitCount = 10 + finfo, err := os.Stat(curdir + "/etc") + for err != nil || !finfo.IsDir() { + curdir = filepath.Dir(curdir) + finfo, err = os.Stat(curdir + "/etc") + limitCount-- + if limitCount <= 0 { + panic("out limit") + } + } + lidx := strings.LastIndex(curdir, "/") + + return fmt.Sprintf("%s/etc/%s.yaml", curdir, curdir[lidx+1:]) + +} + +func GetCurrentServiceName() string { + _, currentFilePath, _, ok := runtime.Caller(1) + if !ok { + panic("Error: Unable to get the current file path.") + + } + + curdir, err := filepath.Abs(currentFilePath) + if err != nil { + panic(err) + + } + + curdir = filepath.Dir(curdir) + var limitCount = 10 + finfo, err := os.Stat(curdir + "/etc") + for err != nil || !finfo.IsDir() { + curdir = filepath.Dir(curdir) + finfo, err = os.Stat(curdir + "/etc") + limitCount-- + if limitCount <= 0 { + panic("out limit") + } + } + lidx := strings.LastIndex(curdir, "/") + // log.Println(curdir[lidx+1:]) + return curdir[lidx+1:] +} + +func GetSesssion() *requests.Session { + ses := requests.NewSession() + return ses +} + +func GetSessionWithUserToken(t *testing.T, server requests.ITestServer, Host string, Port int) *requests.Session { + ses := requests.NewSession() + tp := ses.Post(fmt.Sprintf("http://%s:%d/user/login", Host, Port)) + tp.SetBodyJson(map[string]interface{}{ + "name": "9107058@qq.com", + "pwd": "$2y$13$2y4O4OIz/zcK5C0vlSc9LuSpjWySjInLBSe49yDkE.iURb.R1hDsy", + }) + resp, err := tp.TestExecute(server) + if err != nil { + t.Error(err) + } + result := resp.Json() + code := result.Get("code").Int() + if code != 200 { + t.Error("code is not 200") + } + + token := result.Get("data.token") + if !token.Exists() { + t.Error("data.token is not exists") + } + ses.Header.Add("Authorization", token.String()) + + return ses +} + +func GetBackendSessionWithUserToken(t *testing.T, server requests.ITestServer, Host string, Port int) *requests.Session { + ses := requests.NewSession() + tp := ses.Post(fmt.Sprintf("http://%s:%d/backend-user/login", Host, Port)) + tp.SetBodyJson(map[string]interface{}{ + "name": "admin@admin.com", + "pwd": "ZnVzZW5fYmFja2VuZF8yMDIz47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU=", + }) + resp, err := tp.TestExecute(server) + if err != nil { + t.Error(err) + } + result := resp.Json() + code := result.Get("code").Int() + if code != 200 { + t.Error("code is not 200") + } + + token := result.Get("data.token") + if !token.Exists() { + t.Error("data.token is not exists") + } + ses.Header.Add("Authorization", token.String()) + + return ses +} + +func GetSesssionWithGuestToken(t *testing.T, server requests.ITestServer, Host string, Port int) *requests.Session { + ses := requests.NewSession() + tp := ses.Post(fmt.Sprintf("http://%s:%d/accept/cookie", Host, Port)) + + resp, err := tp.TestExecute(server) + if err != nil { + t.Error(err) + } + result := resp.Json() + token := result.Get("data.token") + if !token.Exists() { + t.Error("data.token is not exists") + } + ses.Header.Add("Authorization", token.String()) + + return ses +} diff --git a/utils/pdf/html_to_pdf.go b/utils/pdf/html_to_pdf.go index f2a8b15e..c81f9e10 100644 --- a/utils/pdf/html_to_pdf.go +++ b/utils/pdf/html_to_pdf.go @@ -6,7 +6,11 @@ import ( "strings" ) -// html转 Pdf dataType = 1 为网页url dataType = 2为网页内容 outFile为空则不保存(使用该方法需要安装工具 sudo apt-get install wkhtmltopdf) +/* +html转 Pdf +dataType = 1 为网页url dataType = 2为网页内容 +outFile为空则不保存(使用该方法需要安装工具 sudo apt-get install wkhtmltopdf) +*/ func HtmlToPdfBase64(content string, dataType int, outFile ...string) (string, error) { pdfg, err := wkhtmltopdf.NewPDFGenerator() if err != nil { diff --git a/utils/request_parser/parser.go b/utils/request_parser/parser.go new file mode 100644 index 00000000..44a562fd --- /dev/null +++ b/utils/request_parser/parser.go @@ -0,0 +1 @@ +package requestparser