From d4e75b1efc46a457898847ca9e82b8c17ebbab68 Mon Sep 17 00:00:00 2001 From: eson <9673575+githubcontent@user.noreply.gitee.com> Date: Wed, 28 Jun 2023 19:32:41 +0800 Subject: [PATCH] =?UTF-8?q?TODO:=20=E5=8F=8D=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/gmodel/fs_cloud_pick_up_logic.go | 6 + model/gmodel/fs_order_logic.go | 11 ++ .../handler/quotationdetailhandler.go | 41 ++--- server/backend/internal/logic/init.go | 17 ++ .../internal/logic/quotationdetaillogic.go | 173 ++++-------------- .../backend/template}/products.tpl | 0 .../backend/template}/return_html.tpl | 3 + .../backend/test/quotationdetaillogic_test.go | 2 +- .../home-user-auth/internal/handler/routes.go | 5 + .../handler/usercontactservicehandler.go | 78 ++++++++ .../internal/logic/usercontactservicelogic.go | 66 +++++++ server/home-user-auth/internal/types/types.go | 16 ++ .../test/useraddaddresslogic_test.go | 2 +- .../test/useraddresslistlogic_test.go | 2 +- .../test/userbasicinfologic_test.go | 2 +- .../test/usercontactservicelogic_test.go | 107 +++++++++++ .../test/userfontslogic_test.go | 2 +- .../test/usergettypelogic_test.go | 2 +- .../test/useroderdeletelogic_test.go | 2 +- .../test/usersavebasicinfologic_test.go | 2 +- .../test/userstatusconfiglogic_test.go | 2 +- server_api/home-user-auth.api | 12 ++ utils/auth/user.go | 6 + utils/auth/user_test.go | 30 +++ utils/basic/basic.go | 8 +- utils/collect/collect.go | 88 ++++++++- utils/tests/basic.go | 28 ++- 27 files changed, 527 insertions(+), 186 deletions(-) create mode 100644 server/backend/internal/logic/init.go rename {template => server/backend/template}/products.tpl (100%) rename {template => server/backend/template}/return_html.tpl (99%) create mode 100644 server/home-user-auth/internal/handler/usercontactservicehandler.go create mode 100644 server/home-user-auth/internal/logic/usercontactservicelogic.go create mode 100644 server/home-user-auth/test/usercontactservicelogic_test.go diff --git a/model/gmodel/fs_cloud_pick_up_logic.go b/model/gmodel/fs_cloud_pick_up_logic.go index 51202633..c6fd862b 100644 --- a/model/gmodel/fs_cloud_pick_up_logic.go +++ b/model/gmodel/fs_cloud_pick_up_logic.go @@ -2,6 +2,7 @@ package gmodel import ( "context" + "gorm.io/gorm" ) @@ -29,3 +30,8 @@ func (p *FsCloudPickUpModel) SavePickUpWithTransaction(ctx context.Context, pick return nil }) } + +func (p *FsCloudPickUpModel) GetCloudPickUpByIDAndUserID(ctx context.Context, userId int64, RelationID int64) (cloudOrder *FsCloudPickUp, err error) { + + return cloudOrder, err +} diff --git a/model/gmodel/fs_order_logic.go b/model/gmodel/fs_order_logic.go index 9e83d596..3da5410b 100755 --- a/model/gmodel/fs_order_logic.go +++ b/model/gmodel/fs_order_logic.go @@ -2,6 +2,8 @@ package gmodel import ( "context" + + "gorm.io/gorm" ) func (o *FsOrderModel) FindOneBySn(ctx context.Context, userId int64, sn string) (resp *FsOrder, err error) { @@ -20,3 +22,12 @@ func (o *FsOrderModel) FindOne(ctx context.Context, userId int64, OrderId int64) func (o *FsOrderModel) Update(ctx context.Context, data *FsOrder) error { return o.db.WithContext(ctx).Model(data).Where("`id` = ?", data.Id).Updates(data).Error } + +func (o *FsOrderModel) FindOneAndCreateServiceContact(ctx context.Context, userId int64, OrderId int64) (order *FsOrder, err error) { + err = o.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + err = tx.Model(order).Where("`user_id` = ? and `id` = ?", userId, OrderId).Take(&order).Error + tx.Table("").Model(FsContactService{}) + return err + }) + return order, err +} diff --git a/server/backend/internal/handler/quotationdetailhandler.go b/server/backend/internal/handler/quotationdetailhandler.go index 024f8a4c..59640c7b 100644 --- a/server/backend/internal/handler/quotationdetailhandler.go +++ b/server/backend/internal/handler/quotationdetailhandler.go @@ -25,30 +25,27 @@ func QuotationDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { userinfo *auth.BackendUserInfo ) // 解析JWT token,并对空用户进行判断 - // claims, err := svcCtx.ParseJwtToken(r) - // // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 - // if err != nil || claims == nil { - // httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - // Code: 401, // 返回401状态码,表示未授权 - // Message: "unauthorized", // 返回未授权信息 - // }) - // logx.Info("unauthorized:", err.Error()) // 记录错误日志 - // return - // } + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil || claims == nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } - // // 从token中获取对应的用户信息 - // userinfo, err = auth.GetBackendUserInfoFormMapClaims(claims) - // // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - // if err != nil { - // httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - // Code: 401, - // Message: "unauthorized", - // }) - // logx.Info("unauthorized:", err.Error()) - // return - // } + // 从token中获取对应的用户信息 + userinfo, err = auth.GetBackendUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 if err != nil { - + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return } var req types.RequestQuotationId diff --git a/server/backend/internal/logic/init.go b/server/backend/internal/logic/init.go new file mode 100644 index 00000000..04b6be7f --- /dev/null +++ b/server/backend/internal/logic/init.go @@ -0,0 +1,17 @@ +package logic + +import ( + "os" + "regexp" +) + +var templatePath string + +func init() { + d, err := os.Getwd() + if err != nil { + panic(err) + } + + templatePath = regexp.MustCompile(".+fusenapi/server").FindString(d) + "/backend/template" +} diff --git a/server/backend/internal/logic/quotationdetaillogic.go b/server/backend/internal/logic/quotationdetaillogic.go index e0deec79..5edcecd9 100644 --- a/server/backend/internal/logic/quotationdetaillogic.go +++ b/server/backend/internal/logic/quotationdetaillogic.go @@ -51,13 +51,6 @@ func GetPrice(num int64, stepNum []int64, stepPrice []int64) int64 { // GetDemoHtml 报价单 func (l *QuotationDetailLogic) GetDemoHtml(quot *gmodel.FsQuotation, quotationProduct []*gmodel.FsQuotationProduct) (htmlcontent string, err error) { - saler, err := l.svcCtx.AllModels.FsQuotationSaler.GetOne(l.ctx, quot.Id) - if err != nil { - - return "", err - } - - log.Println(saler) // htmlContent := "" priceHtml := "" @@ -99,147 +92,18 @@ func (l *QuotationDetailLogic) GetDemoHtml(quot *gmodel.FsQuotation, quotationPr priceHtml = buf.String() } - tplcontent := ` - {{$product_num := len .products}} - {{$page := 3}} - {{$page_total := add $page $product_num}} - {{range $arr := .products}} - {{$price := json_decode $arr.price_info}} - {{$price_html := .priceHtml}} - - {{$price_html}} - - {{if gt $arr.is_gift 0 }}{{/* 赠品 */}} - -
-
-

{{$arr.name}}

-

{{$arr.size}}

- -
-
-
-
-
-
-

FREE!

-

{{$arr.num}} Units

-
-
-
Lead Time
-
- {{$arr.cycle}}Days -
-
- FREE Design -
-
- FREE Storage -
-
- FREE Shipping -
-
-
-
- {{else}}{{/* 非赠品 */}} - {{if $arr.size}} - // 有尺寸的 -
-
-

{{$arr.name}}

-

{{$arr.size}}

- -
-
-
-
-
-
Unit Price (Tax included)
-
- Lead Time
- {{$price_html}} -
-
- {{$arr.cycle}}Days -
-
- FREE Design -
-
- FREE Storage -
-
- FREE Shipping -
-
-
-
- - {{else}} -
-
-

- {{$arr.name}}

- -
-
-
-
-
-
-
- Unit Price (Tax included)
-
- Lead Time
- {{$price_html}} -
-
- {{$arr.cycle}}Days -
-
- FREE Design -
-
- FREE Storage -
-
- FREE Shipping -
-
-
-
- {{end}} - {{end}} -
{{$page}}/{{$page_total}}
- {{$page = add $page 1}} - {{end}} ` - tpl := template.New("demo") + tpl := template.New("quto") tpl = tpl.Funcs(format.TemplateFuncMap) - tpl = template.Must(tpl.Parse(tplcontent)) - buf := bytes.NewBufferString("") + + tpl = template.Must(tpl.ParseFiles(templatePath + "/products.tpl")) + buf := &bytes.Buffer{} tpl.Execute(buf, map[string]interface{}{ "products": collect.StructSliceJson2Maps(quotationProduct), "price_html": priceHtml, }) htmlContent := buf.String() - log.Println(htmlContent) + // log.Println(htmlContent) return htmlContent, nil } @@ -427,5 +291,32 @@ func (l *QuotationDetailLogic) QuotationDetail(req *types.RequestQuotationId, us } log.Println(htmlContent) + saler, err := l.svcCtx.AllModels.FsQuotationSaler.GetOne(l.ctx, quot.Id) + if err != nil { + logx.Error(err) + if err == gorm.ErrRecordNotFound { + return resp.SetStatus(basic.CodeDbRecordNotFoundErr) + } + return resp.SetStatus(basic.CodeDbSqlErr) + } + + // log.Println(saler) + + tpl := template.New("quto") + tpl = tpl.Funcs(format.TemplateFuncMap) + + tpl = template.Must(tpl.ParseFiles(templatePath + "/return_html.tpl")) + buf := &bytes.Buffer{} + + err = tpl.Execute(buf, map[string]interface{}{ + "demoHtml": htmlContent, + "qutoInfo": collect.StructJson2Map(quot), + "salerInfo": collect.StructJson2Map(saler), + }) + if err != nil { + return resp.SetStatus(basic.CodeApiErr) + } + // returnHtmlContent := buf.String() + return resp.SetStatus(basic.CodeOK) } diff --git a/template/products.tpl b/server/backend/template/products.tpl similarity index 100% rename from template/products.tpl rename to server/backend/template/products.tpl diff --git a/template/return_html.tpl b/server/backend/template/return_html.tpl similarity index 99% rename from template/return_html.tpl rename to server/backend/template/return_html.tpl index 44099cab..cf2433a4 100644 --- a/template/return_html.tpl +++ b/server/backend/template/return_html.tpl @@ -1,3 +1,6 @@ +{{$html := .demoHtml}} +{{$saler := .salerInfo}} +{{$info := .qutoInfo}} diff --git a/server/backend/test/quotationdetaillogic_test.go b/server/backend/test/quotationdetaillogic_test.go index 5a828e51..cb8e293d 100644 --- a/server/backend/test/quotationdetaillogic_test.go +++ b/server/backend/test/quotationdetaillogic_test.go @@ -8,7 +8,7 @@ import ( ) func TestCaseQuotationDetail(t *testing.T) { - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetBackendSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 构建新增地址请求体 // addrReq := types.RequestQuotationId{ diff --git a/server/home-user-auth/internal/handler/routes.go b/server/home-user-auth/internal/handler/routes.go index 0e32f516..d5a3ba1e 100644 --- a/server/home-user-auth/internal/handler/routes.go +++ b/server/home-user-auth/internal/handler/routes.go @@ -57,6 +57,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/user/add-address", Handler: UserAddAddressHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/user/contact-service", + Handler: UserContactServiceHandler(serverCtx), + }, { Method: http.MethodPost, Path: "/user/order-delete", diff --git a/server/home-user-auth/internal/handler/usercontactservicehandler.go b/server/home-user-auth/internal/handler/usercontactservicehandler.go new file mode 100644 index 00000000..c6dd536c --- /dev/null +++ b/server/home-user-auth/internal/handler/usercontactservicehandler.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/home-user-auth/internal/logic" + "fusenapi/server/home-user-auth/internal/svc" + "fusenapi/server/home-user-auth/internal/types" +) + +func UserContactServiceHandler(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.RequestContactService + // 如果端点有请求结构体,则使用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.NewUserContactServiceLogic(r.Context(), svcCtx) + resp := l.UserContactService(&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/home-user-auth/internal/logic/usercontactservicelogic.go b/server/home-user-auth/internal/logic/usercontactservicelogic.go new file mode 100644 index 00000000..52afdb46 --- /dev/null +++ b/server/home-user-auth/internal/logic/usercontactservicelogic.go @@ -0,0 +1,66 @@ +package logic + +import ( + "fusenapi/model/gmodel" + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/collect" + + "context" + + "fusenapi/server/home-user-auth/internal/svc" + "fusenapi/server/home-user-auth/internal/types" + + "github.com/zeromicro/go-zero/core/logx" + "gorm.io/gorm" +) + +type UserContactServiceLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUserContactServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserContactServiceLogic { + return &UserContactServiceLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UserContactServiceLogic) UserContactService(req *types.RequestContactService, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + + if !userinfo.IsUser() { + return resp.SetStatus(basic.CodeUnAuth) + } + + cs := gmodel.FsContactService{} + + collect.LoadJsonTag(cs, req) + + switch req.Type { + case "order": + _, err := l.svcCtx.AllModels.FsOrder.FindOneAndCreateServiceContact(l.ctx, userinfo.UserId, req.RelationID) + if err != nil { + if err == gorm.ErrRecordNotFound { + return resp.SetStatus(basic.CodeOrderNotFoundErr) + } + return resp.SetStatus(basic.CodeDbSqlErr) + } + case "cloud": + _, err := l.svcCtx.AllModels.FsCloudPickUp.GetCloudPickUpByIDAndUserID(l.ctx, userinfo.UserId, req.RelationID) + if err != nil { + if err == gorm.ErrRecordNotFound { + return resp.SetStatus(basic.CodeCloudOrderNotFoundErr) + } + return resp.SetStatus(basic.CodeDbSqlErr) + } + default: + return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "type is unknown") + } + + return resp.SetStatus(basic.CodeOK) +} diff --git a/server/home-user-auth/internal/types/types.go b/server/home-user-auth/internal/types/types.go index 903b376d..26ad0b3a 100644 --- a/server/home-user-auth/internal/types/types.go +++ b/server/home-user-auth/internal/types/types.go @@ -5,6 +5,15 @@ import ( "fusenapi/utils/basic" ) +type RequestContactService struct { + Type string `json:"type"` // 类型 + RelationID int64 `json:"relation_id"` // 关系id + Name string `json:"name"` // 名字 + Email string `json:"email"` // email + Phone string `json:"phone,optional"` // phone + Remark string `json:"remark,optional"` // remark标记 +} + type RequestBasicInfoForm struct { FirstName string `json:"first_name"` // FirstName LastName string `json:"last_name"` // LastName @@ -123,6 +132,13 @@ type Auth struct { RefreshAfter int64 `json:"refreshAfter"` } +type Pagnation struct { + TotalCount int64 `json:"total_count"` + TotalPage int64 `json:"total_page"` + CurPage int64 `json:"cur_page"` + PageSize int64 `json:"page_size"` +} + // Set 设置Response的Code和Message值 func (resp *Response) Set(Code int, Message string) *Response { return &Response{ diff --git a/server/home-user-auth/test/useraddaddresslogic_test.go b/server/home-user-auth/test/useraddaddresslogic_test.go index 813c73b2..2f33bc2c 100644 --- a/server/home-user-auth/test/useraddaddresslogic_test.go +++ b/server/home-user-auth/test/useraddaddresslogic_test.go @@ -16,7 +16,7 @@ func TestCaseUserAddAddress(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 构建新增地址请求体 addrReq := types.RequestAddAddress{ diff --git a/server/home-user-auth/test/useraddresslistlogic_test.go b/server/home-user-auth/test/useraddresslistlogic_test.go index f311d130..163b74e3 100644 --- a/server/home-user-auth/test/useraddresslistlogic_test.go +++ b/server/home-user-auth/test/useraddresslistlogic_test.go @@ -15,7 +15,7 @@ func TestCaseAddressList(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取用户地址列表 resp, err = ses.Get(fmt.Sprintf("http://%s:%d/user/address-list", cnf.Host, cnf.Port)).TestExecute(gserver) diff --git a/server/home-user-auth/test/userbasicinfologic_test.go b/server/home-user-auth/test/userbasicinfologic_test.go index 64863bad..818e65a4 100644 --- a/server/home-user-auth/test/userbasicinfologic_test.go +++ b/server/home-user-auth/test/userbasicinfologic_test.go @@ -15,7 +15,7 @@ func TestCaseBasicInfoLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取用户基本信息 resp, err = ses.Get(fmt.Sprintf("http://%s:%d/user/basic-info", cnf.Host, cnf.Port)).TestExecute(gserver) diff --git a/server/home-user-auth/test/usercontactservicelogic_test.go b/server/home-user-auth/test/usercontactservicelogic_test.go new file mode 100644 index 00000000..33625fc9 --- /dev/null +++ b/server/home-user-auth/test/usercontactservicelogic_test.go @@ -0,0 +1,107 @@ +package logic + +import ( + "fmt" + "fusenapi/server/home-user-auth/internal/types" + fstests "fusenapi/utils/tests" + "testing" + + "github.com/474420502/requests" + "github.com/tidwall/gjson" +) + +func TestUserContactService(t *testing.T) { + var err error + var resp *requests.Response + var result gjson.Result + + // 获取 session,并携带 JWT token + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) + tp := ses.Post(fmt.Sprintf("http://%s:%d/user/contact-service", cnf.Host, cnf.Port)) + req := types.RequestContactService{Type: "order", RelationID: 123, Email: "admin@admin.com", Name: "eson"} + tp.SetBodyJson(req) + // 向服务器发送 GET 请求,获取用户基本信息 + resp, err = tp.TestExecute(gserver) + if err != nil { + t.Error(err) + } + + // 检查返回值中的 code 字段是否存在,并且值是否为 200 + result = resp.Json().Get("code") + if !result.Exists() { + t.Error("code is not exists") + } + if result.Int() != 200 { + t.Error("code != 200") + } + + // 检查返回值中的 msg 字段是否存在,并且值是否为 "success" + result = resp.Json().Get("msg") + if !result.Exists() { + t.Error("msg is not exists") + } + if result.String() != "success" { + t.Error(result.String()) + } + + // 检查返回值中的 data 字段是否存在 + result = resp.Json().Get("data") + if !result.Exists() { + t.Error("data is not exists") + } + + // 检查返回值中的 type 字段是否存在,并且值是否为 0 + result = resp.Json().Get("data.type") + if !result.Exists() { + t.Error("type is not exists") + } + + // 检查返回值中的 is_order_status_email 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_order_status_email") + if !result.Exists() { + t.Error("is_order_status_email is not exists") + } + + // 检查返回值中的 is_email_advertisement 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_email_advertisement") + if !result.Exists() { + t.Error("is_email_advertisement is not exists") + } + + // 检查返回值中的 is_order_status_phone 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_order_status_phone") + if !result.Exists() { + t.Error("is_order_status_phone is not exists") + } + + // 检查返回值中的 is_phone_advertisement 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_phone_advertisement") + if !result.Exists() { + t.Error("is_phone_advertisement is not exists") + } + + // 检查返回值中的 is_open_render 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_open_render") + if !result.Exists() { + t.Error("is_open_render is not exists") + } + + // 检查返回值中的 is_thousand_face 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_thousand_face") + if !result.Exists() { + t.Error("is_thousand_face is not exists") + } + + // 检查返回值中的 is_low_rendering 字段是否存在,并且值是否为 false + result = resp.Json().Get("data.is_low_rendering") + if !result.Exists() { + t.Error("is_low_rendering is not exists") + } + + // 检查返回值中的 is_remove_bg 字段是否存在,并且值是否为 true + result = resp.Json().Get("data.is_remove_bg") + if !result.Exists() { + t.Error("is_remove_bg is not exists") + } + +} diff --git a/server/home-user-auth/test/userfontslogic_test.go b/server/home-user-auth/test/userfontslogic_test.go index ff011b05..cb0e1241 100644 --- a/server/home-user-auth/test/userfontslogic_test.go +++ b/server/home-user-auth/test/userfontslogic_test.go @@ -16,7 +16,7 @@ func TestCaseUserFontsLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取字体列表 resp, err = ses.Get(fmt.Sprintf("http://%s:%d/user/fonts", cnf.Host, cnf.Port)).TestExecute(gserver) diff --git a/server/home-user-auth/test/usergettypelogic_test.go b/server/home-user-auth/test/usergettypelogic_test.go index 322e5b84..777912e0 100644 --- a/server/home-user-auth/test/usergettypelogic_test.go +++ b/server/home-user-auth/test/usergettypelogic_test.go @@ -15,7 +15,7 @@ func TestCaseGetTypeLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取用户类型信息 resp, err = ses.Get(fmt.Sprintf("http://%s:%d/user/get-type", cnf.Host, cnf.Port)).TestExecute(gserver) diff --git a/server/home-user-auth/test/useroderdeletelogic_test.go b/server/home-user-auth/test/useroderdeletelogic_test.go index 79bf80a8..f1ebbfe3 100644 --- a/server/home-user-auth/test/useroderdeletelogic_test.go +++ b/server/home-user-auth/test/useroderdeletelogic_test.go @@ -16,7 +16,7 @@ func TestCaseLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取用户类型信息 tp := ses.Post(fmt.Sprintf("http://%s:%d/user/order-delete", cnf.Host, cnf.Port)) diff --git a/server/home-user-auth/test/usersavebasicinfologic_test.go b/server/home-user-auth/test/usersavebasicinfologic_test.go index 42e3160a..b95f3d19 100644 --- a/server/home-user-auth/test/usersavebasicinfologic_test.go +++ b/server/home-user-auth/test/usersavebasicinfologic_test.go @@ -17,7 +17,7 @@ func TestCaseUserSaveBasicinfoLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) var tp *requests.Temporary tp = ses.Get(fmt.Sprintf("http://%s:%d/user/basic-info", cnf.Host, cnf.Port)) diff --git a/server/home-user-auth/test/userstatusconfiglogic_test.go b/server/home-user-auth/test/userstatusconfiglogic_test.go index e6336d7f..b5436a4b 100644 --- a/server/home-user-auth/test/userstatusconfiglogic_test.go +++ b/server/home-user-auth/test/userstatusconfiglogic_test.go @@ -15,7 +15,7 @@ func TestCaseUserStatusConfigLogic(t *testing.T) { var result gjson.Result // 获取 session,并携带 JWT token - ses := fstests.GetSesssionWithUserToken(t, gserver, cnf.Host, cnf.Port) + ses := fstests.GetSessionWithUserToken(t, gserver, cnf.Host, cnf.Port) // 向服务器发送 GET 请求,获取用户类型信息 resp, err = ses.Post(fmt.Sprintf("http://%s:%d/user/status-config", cnf.Host, cnf.Port)).TestExecute(gserver) diff --git a/server_api/home-user-auth.api b/server_api/home-user-auth.api index c8820ad6..aeef3cae 100644 --- a/server_api/home-user-auth.api +++ b/server_api/home-user-auth.api @@ -37,6 +37,9 @@ service home-user-auth { @handler UserAddAddressHandler post /user/add-address(RequestAddAddress) returns (response); + @handler UserContactServiceHandler + post /user/contact-service (RequestContactService) returns (response); + // @handler UserOderListHandler // get /user/order-list(RequestOrderId) returns (response); @@ -44,6 +47,15 @@ service home-user-auth { post /user/order-delete(RequestOrderId) returns (response); } +type RequestContactService { + Type string `json:"type"` // 类型 + RelationID int64 `json:"relation_id"` // 关系id + Name string `json:"name"` // 名字 + Email string `json:"email"` // email + Phone string `json:"phone,optional"` // phone + Remark string `json:"remark,optional"` // remark标记 +} + type RequestBasicInfoForm { FirstName string `json:"first_name"` // FirstName LastName string `json:"last_name"` // LastName diff --git a/utils/auth/user.go b/utils/auth/user.go index 7eba88ae..9bdb6cb2 100644 --- a/utils/auth/user.go +++ b/utils/auth/user.go @@ -1,6 +1,8 @@ package auth import ( + "crypto/sha256" + "encoding/base64" "errors" "fmt" @@ -181,6 +183,10 @@ func getJwtClaims(AuthKey string, AccessSecret *string) (jwt.MapClaims, error) { return nil, errors.New(fmt.Sprint("Invalid token", err)) } +func PasswordHash(pwd string) string { + return base64.URLEncoding.EncodeToString(sha256.New().Sum([]byte(pwd))) +} + func CheckValueRange[T comparable](v T, rangevalues ...T) bool { for _, rv := range rangevalues { if v == rv { diff --git a/utils/auth/user_test.go b/utils/auth/user_test.go index 19f0df96..c4ae2042 100644 --- a/utils/auth/user_test.go +++ b/utils/auth/user_test.go @@ -1,6 +1,9 @@ package auth import ( + "crypto/sha256" + "encoding/base64" + "log" "testing" "time" ) @@ -29,6 +32,33 @@ func TestGenJwt(t *testing.T) { // log.Println(claims) } +func TestGenBackendJwt(t *testing.T) { + now := time.Now().Unix() + secret := "fusen_backend_2023" + a, err := GenerateBackendJwtToken(&secret, 3600*24*7, now, 1, 1) + if err != nil { + t.Error(err) + } + log.Println(a) + + claims, err := getJwtClaims(a, &secret) + if err != nil { + t.Error(err) + } + userinfo, err := GetBackendUserInfoFormMapClaims(claims) + if err != nil { + t.Error(err) + } + if userinfo.UserId != 1 || userinfo.DepartmentId != 1 { + t.Error(userinfo) + } + // log.Println(claims) +} + +func TestCase1(t *testing.T) { + log.Println(base64.URLEncoding.EncodeToString(sha256.New().Sum([]byte("fusen_backend_2023")))) +} + func TestCheckValueRange(t *testing.T) { v := 1 rv1 := []int{1, 3, 4} diff --git a/utils/basic/basic.go b/utils/basic/basic.go index 23f8c8c0..58a78932 100644 --- a/utils/basic/basic.go +++ b/utils/basic/basic.go @@ -17,10 +17,12 @@ var ( CodeUserIdNotFoundErr = &StatusResponse{5051, "user not found"} // 未找到用户 CodePasswordErr = &StatusResponse{5052, "invalid password"} // 无效密码 - CodeSafeValueRangeErr = &StatusResponse{5040, "value not in range"} // 值不在范围内 + CodeSafeValueRangeErr = &StatusResponse{5040, "value not in range"} // 值不在范围内 + CodeTemplateErr = &StatusResponse{5040, "template parsed error"} // 模板解析错误 - CodeOrderNotFoundErr = &StatusResponse{5030, "order not found"} //未找到订单 - CodeOrderNotCancelledErr = &StatusResponse{5031, "current order cannot be cancelled"} // 当前订单无法取消 + CodeOrderNotFoundErr = &StatusResponse{5030, "order not found"} //未找到订单 + CodeCloudOrderNotFoundErr = &StatusResponse{5031, "cloud order not found"} //未找到云仓订单 + CodeOrderNotCancelledErr = &StatusResponse{5032, "current order cannot be cancelled"} // 当前订单无法取消 CodePayNotFoundErr = &StatusResponse{5020, "pay info not found"} // 支付信息无法查询 CodePayCancelOk = &StatusResponse{5021, "cancellation successful"} // 支付取消成功 diff --git a/utils/collect/collect.go b/utils/collect/collect.go index c8da1d2b..796993eb 100644 --- a/utils/collect/collect.go +++ b/utils/collect/collect.go @@ -1,6 +1,7 @@ package collect import ( + "log" "reflect" "strconv" ) @@ -111,7 +112,13 @@ func Array2MapByKey[KEY comparable, VALUE any](arrSrc []VALUE, fieldName string) for i := 0; i < arr.Len(); i++ { srcv := arr.Index(i) - fv := srcv.Elem().FieldByName(fieldName) + if srcv.Kind() == reflect.Ptr { + if srcv.IsNil() { + continue + } + srcv = srcv.Elem() + } + fv := srcv.FieldByName(fieldName) k := fv.Interface().(KEY) result[k] = srcv.Interface().(VALUE) } @@ -119,6 +126,7 @@ func Array2MapByKey[KEY comparable, VALUE any](arrSrc []VALUE, fieldName string) return result } +// 一个数组slice转换成 map[tag]slice ,以slice元素的某个tag为map func Array2MapByKeyTag[KEY comparable, VALUE any](arrSrc []VALUE, tag string) (result map[KEY]VALUE) { defer func() { @@ -147,6 +155,9 @@ func Array2MapByKeyTag[KEY comparable, VALUE any](arrSrc []VALUE, tag string) (r srcv := arr.Index(i) var fv reflect.Value if srcv.Kind() == reflect.Ptr { + if srcv.IsNil() { + continue + } fv = srcv.Elem().Field(j) } else { fv = srcv.Field(j) @@ -169,19 +180,20 @@ func Array2MapByKeyTag[KEY comparable, VALUE any](arrSrc []VALUE, tag string) (r func StructJson2Map(s interface{}) map[string]interface{} { t := reflect.TypeOf(s) v := reflect.ValueOf(s) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } var data = make(map[string]interface{}) for i := 0; i < t.NumField(); i++ { field := t.Field(i) - if field.Tag == "" { - continue + if tag, ok := field.Tag.Lookup("json"); ok { + val := v.Field(i) + if val.Kind() == reflect.Ptr && !val.IsNil() { + val = val.Elem() + } + data[tag] = val.Interface() } - tag := field.Tag.Get("json") - val := v.Field(i) - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - data[tag] = val.Interface() } return data } @@ -193,7 +205,7 @@ func StructSliceJson2Maps(s interface{}) []map[string]interface{} { for i := 0; i < slice.Len(); i++ { s := slice.Index(i) - if s.Kind() == reflect.Ptr { + if s.Kind() == reflect.Ptr && !s.IsNil() { s = s.Elem() } structValue := s.Interface() @@ -202,3 +214,59 @@ func StructSliceJson2Maps(s interface{}) []map[string]interface{} { } return maps } + +func LoadJsonTag(v interface{}, loaded interface{}) { + vtype := reflect.TypeOf(v) + if vtype.Kind() == reflect.Ptr { + vtype = vtype.Elem() + } + vvalue := reflect.ValueOf(v) + if vvalue.Kind() == reflect.Ptr { + vvalue = vvalue.Elem() + } + + ltype := reflect.TypeOf(loaded) + if ltype.Kind() == reflect.Ptr { + ltype = ltype.Elem() + } + lvalue := reflect.ValueOf(loaded) + if lvalue.Kind() == reflect.Ptr { + lvalue = lvalue.Elem() + } + + for i := 0; i < vtype.NumField(); i++ { + vfield := vtype.Field(i) + + if vtag, ok := vfield.Tag.Lookup("json"); ok { + + for j := 0; j < ltype.NumField(); j++ { + lfield := ltype.Field(j) + if ltag, ok := lfield.Tag.Lookup("json"); ok && vtag == ltag { + vv := vvalue.Field(i) + lv := lvalue.Field(j) + log.Println(vv.Kind(), vv.Type().Elem(), lv.Kind()) + if vv.Kind() == reflect.Ptr { + if lv.Kind() == reflect.Ptr { + vv.Set(lv) + } else { + vv = reflect.New(vv.Type().Elem()) + log.Println(vv.Type().Kind(), vv.Elem().Kind(), lv, reflect.Indirect(vv)) + reflect.Indirect(vv.Addr()).Set(lv.Addr()) + vv = reflect.New(vv.Type().Elem()) + + vv.Set(lv.Addr()) + } + + vv.Set(lv) + } else { + if lv.Kind() != reflect.Ptr { + vv.Set(lv) + } else { + vv.Set(lv.Elem()) + } + } + } + } + } + } +} diff --git a/utils/tests/basic.go b/utils/tests/basic.go index b4c2e73b..94180b1c 100644 --- a/utils/tests/basic.go +++ b/utils/tests/basic.go @@ -12,7 +12,7 @@ func GetSesssion() *requests.Session { return ses } -func GetSesssionWithUserToken(t *testing.T, server requests.ITestServer, Host string, Port int) *requests.Session { +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{}{ @@ -38,6 +38,32 @@ func GetSesssionWithUserToken(t *testing.T, server requests.ITestServer, Host st 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))