animeic 2 years ago
parent
commit
57994e5f9e

BIN
oilseal-train/20221212175741.xlsx


+ 0 - 78
oilseal-train/api/address.go

@@ -1,78 +0,0 @@
-package api
-
-import (
-	"errors"
-	"oilseal-train/db/model"
-	"oilseal-train/db/repo"
-	"time"
-
-	"github.com/gin-gonic/gin"
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
-
-func Address(r *GinRouter) {
-
-	CreateCRUD(r, "/address", &CRUDOption{
-		Collection: repo.CollectionAddress,
-		NewModel: func(c *gin.Context, apictx *ApiSession) (interface{}, error) {
-			entity := &model.Address{}
-			c.ShouldBindJSON(entity)
-			entity.CreateTime = time.Now()
-			_userId := apictx.User.ID
-			userId, _ := primitive.ObjectIDFromHex(_userId)
-
-			if entity.Addr == "" {
-				return nil, errors.New("地址不能为空")
-			}
-			if entity.Contact == "" {
-				return nil, errors.New("联系人不能为空")
-			}
-			entity.UserId = userId
-			// 默认设置第一条数据为默认数据
-			first, _ := repo.RepoCountDoc(apictx.CreateRepoCtx(), repo.CollectionAddress, repo.Map{"userId": userId})
-			if first > 0 {
-				entity.Defualt = -1
-			} else {
-				entity.Defualt = 1
-			}
-			return entity, nil
-		},
-		OnUpdate: func(_ *gin.Context, apictx *ApiSession, entity interface{}) {
-			address := entity.(*model.Address)
-			_userId := apictx.User.ID
-			userId, _ := primitive.ObjectIDFromHex(_userId)
-
-			// 更改默认地址的流程
-			if address.Defualt == 1 {
-				// 将已有的默认地址更改为非默认
-				opt := repo.PageSearchOptions{
-					CollectName: repo.CollectionAddress,
-					Query:       repo.Map{"userId": userId, "defualt": 1},
-					Project:     []string{"_id"},
-				}
-				defs := make([]*model.Address, 0)
-				repo.RepoDocsSearch(apictx.CreateRepoCtx(), &opt, &defs)
-				if len(defs) > 0 {
-					for _, v := range defs {
-						// 设置为非默认
-						repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionAddress, v.Id.Hex(), &model.Address{Defualt: -1})
-					}
-				}
-
-			}
-
-		},
-		EmtyModel: func(c *gin.Context, apictx *ApiSession) interface{} {
-			return &model.Address{}
-		},
-		JWT: true,
-		SearchFilter: func(_ *gin.Context, apictx *ApiSession, query map[string]interface{}) map[string]interface{} {
-			_userId := apictx.User.ID
-			userId, _ := primitive.ObjectIDFromHex(_userId)
-			query["userId"] = userId
-			return query
-		},
-		SearchProject: []string{"province", "city", "area", "addr", "contact", "phone", "defualt", "createTime"},
-		DetailProject: []string{"province", "city", "area", "addr", "contact", "phone", "defualt", "createTime"},
-	})
-}

+ 77 - 77
oilseal-train/api/collect.go

@@ -1,84 +1,84 @@
 package api
 
-import (
-	"errors"
-	"oilseal-train/db/model"
-	"oilseal-train/db/repo"
-	"time"
+// import (
+// 	"errors"
+// 	"oilseal-train/db/model"
+// 	"oilseal-train/db/repo"
+// 	"time"
 
-	"github.com/gin-gonic/gin"
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
+// 	"github.com/gin-gonic/gin"
+// 	"go.mongodb.org/mongo-driver/bson/primitive"
+// )
 
-func Collect(r *GinRouter) {
-	CreateCRUD(r, "/collect", &CRUDOption{
-		Collection: repo.CollectionCollect,
-		NewModel: func(c *gin.Context, apictx *ApiSession) (interface{}, error) {
-			entity := &model.Collect{}
-			err := c.ShouldBindJSON(entity)
-			if err != nil {
-				return nil, errors.New("参数错误")
-			}
-			entity.CreateTime = time.Now()
-			_userId := apictx.User.ID
-			userId, _ := primitive.ObjectIDFromHex(_userId)
+// func Collect(r *GinRouter) {
+// 	CreateCRUD(r, "/collect", &CRUDOption{
+// 		Collection: repo.CollectionCollect,
+// 		NewModel: func(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+// 			entity := &model.Collect{}
+// 			err := c.ShouldBindJSON(entity)
+// 			if err != nil {
+// 				return nil, errors.New("参数错误")
+// 			}
+// 			entity.CreateTime = time.Now()
+// 			_userId := apictx.User.ID
+// 			userId, _ := primitive.ObjectIDFromHex(_userId)
 
-			// 同一用户对同一产品只能有一条收藏记录
-			// 联合唯一索引 db.collect.ensureIndex({userId:1,productId:1},{unique:true})
-			collect := &model.Collect{}
-			found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
-				CollectName: repo.CollectionCollect,
-				Query:       repo.Map{"userId": userId, "productId": entity.ProductId},
-			}, &collect)
-			if found {
-				return entity, errors.New("该物品已被收藏")
-			}
+// 			// 同一用户对同一产品只能有一条收藏记录
+// 			// 联合唯一索引 db.collect.ensureIndex({userId:1,productId:1},{unique:true})
+// 			collect := &model.Collect{}
+// 			found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+// 				CollectName: repo.CollectionCollect,
+// 				Query:       repo.Map{"userId": userId, "productId": entity.ProductId},
+// 			}, &collect)
+// 			if found {
+// 				return entity, errors.New("该物品已被收藏")
+// 			}
 
-			entity.UserId = userId
-			return entity, nil
-		},
-		EmtyModel: func(c *gin.Context, apictx *ApiSession) interface{} {
-			return &model.Collect{}
-		},
-		noUpdate: true,
-		JWT:      true,
-		SearchFilter: func(_ *gin.Context, apictx *ApiSession, query map[string]interface{}) map[string]interface{} {
-			_userId := apictx.User.ID
-			userId, _ := primitive.ObjectIDFromHex(_userId)
-			query["userId"] = userId
-			return query
-		},
-		SearchPostProcess: func(page *repo.PageResult, _ *gin.Context, apictx *ApiSession, _ map[string]interface{}) (interface{}, error) {
-			// 查询组装数据
-			if len(page.List) > 0 {
-				for _, v := range page.List {
-					// 查询产品信息
-					productId := v["productId"].(primitive.ObjectID)
-					supplyId := v["supplyId"].(primitive.ObjectID)
-					product := model.Product{}
-					supply := model.UserSmaple{}
-					repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
-						CollectName: repo.CollectionProduct,
-						Query:       repo.Map{"_id": productId},
-						Project:     []string{"name", "unit", "cover"},
-					}, &product)
-					// 供应商信息
-					repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
-						Db:          "supply-user",
-						CollectName: "users",
-						Query:       repo.Map{"_id": supplyId},
-						Project:     []string{"name", "avatar", "email"},
-					}, &supply)
-					v["productName"] = product.Name
-					v["productUnit"] = product.Unit
-					v["productCover"] = product.Cover
-					v["supplyName"] = supply.Name
-					v["supplyAvatar"] = supply.Avatar
-					v["supplyEmail"] = supply.Email
+// 			entity.UserId = userId
+// 			return entity, nil
+// 		},
+// 		EmtyModel: func(c *gin.Context, apictx *ApiSession) interface{} {
+// 			return &model.Collect{}
+// 		},
+// 		noUpdate: true,
+// 		JWT:      true,
+// 		SearchFilter: func(_ *gin.Context, apictx *ApiSession, query map[string]interface{}) map[string]interface{} {
+// 			_userId := apictx.User.ID
+// 			userId, _ := primitive.ObjectIDFromHex(_userId)
+// 			query["userId"] = userId
+// 			return query
+// 		},
+// 		SearchPostProcess: func(page *repo.PageResult, _ *gin.Context, apictx *ApiSession, _ map[string]interface{}) (interface{}, error) {
+// 			// 查询组装数据
+// 			if len(page.List) > 0 {
+// 				for _, v := range page.List {
+// 					// 查询产品信息
+// 					productId := v["productId"].(primitive.ObjectID)
+// 					supplyId := v["supplyId"].(primitive.ObjectID)
+// 					product := model.Product{}
+// 					supply := model.UserSmaple{}
+// 					repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+// 						CollectName: repo.CollectionProduct,
+// 						Query:       repo.Map{"_id": productId},
+// 						Project:     []string{"name", "unit", "cover"},
+// 					}, &product)
+// 					// 供应商信息
+// 					repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+// 						Db:          "supply-user",
+// 						CollectName: "users",
+// 						Query:       repo.Map{"_id": supplyId},
+// 						Project:     []string{"name", "avatar", "email"},
+// 					}, &supply)
+// 					v["productName"] = product.Name
+// 					v["productUnit"] = product.Unit
+// 					v["productCover"] = product.Cover
+// 					v["supplyName"] = supply.Name
+// 					v["supplyAvatar"] = supply.Avatar
+// 					v["supplyEmail"] = supply.Email
 
-				}
-			}
-			return page, nil
-		},
-	})
-}
+// 				}
+// 			}
+// 			return page, nil
+// 		},
+// 	})
+// }

+ 11 - 34
oilseal-train/api/controller.go

@@ -80,12 +80,12 @@ func ResultJWTWrapper(handle JWTHander, svc *Service) gin.HandlerFunc {
 
 		if claims["id"] != nil {
 			id := claims["id"].(string)
-			name := claims["phone"].(string)
+			loginName := claims["loginName"].(string)
+			name := claims["name"].(string)
 			role := claims["role"].(string)
-			parent := claims["parent"].(string)
 			state := int32(claims["state"].(float64))
 
-			usr = &JWTUser{ID: id, Phone: name, Parent: parent, Role: role, State: state}
+			usr = &JWTUser{ID: id, Name: name, LoginName: loginName, Role: role, State: state}
 		}
 		var apis = &ApiSession{
 			Svc:  svc,
@@ -129,7 +129,7 @@ func ResultJWTTestWrapper(handle JWTHander, svc *Service) gin.HandlerFunc {
 			}
 		}()
 
-		var usr *JWTUser = &JWTUser{ID: svc.DebugUserId, Phone: svc.DebugUserPhone, Parent: svc.DebugUserId, Role: svc.DebugUserRole}
+		var usr *JWTUser = &JWTUser{ID: svc.DebugUserId, Role: svc.DebugUserRole}
 
 		data, err := handle(c, &ApiSession{Svc: svc, User: usr})
 
@@ -172,17 +172,11 @@ func ResultJWTWrapperKey(handle JWTHander, svc *Service, keys []string) gin.Hand
 
 		if claims["id"] != nil {
 			id := claims["id"].(string)
-			phone := claims["phone"].(string)
 			name := claims["name"].(string)
+			loginName := claims["loginName"].(string)
 			role := claims["role"].(string)
-			parent := claims["parent"].(string)
 			state := int32(claims["state"].(float64))
-			key := ""
-			if claims["key"] != nil {
-				key = claims["key"].(string)
-			}
-
-			usr = &JWTUser{ID: id, Name: name, Phone: phone, Parent: parent, Role: role, State: state, Key: key}
+			usr = &JWTUser{ID: id, Name: name, LoginName: loginName, Role: role, State: state}
 		}
 
 		var apis = &ApiSession{
@@ -190,19 +184,6 @@ func ResultJWTWrapperKey(handle JWTHander, svc *Service, keys []string) gin.Hand
 			User: usr,
 		}
 
-		flag := false
-		for _, key := range keys {
-			if usr.Key == key {
-				flag = true
-				break
-			}
-		}
-		if !flag {
-			c.JSON(http.StatusForbidden, NewFailResult("您没有权限"))
-			c.Abort()
-			return
-		}
-
 		data, err := handle(c, apis)
 
 		if err != nil {
@@ -370,15 +351,11 @@ func NewErrorWithCode(desc string, code int32) HTTPError {
 
 // JWTUser jwt登录用户
 type JWTUser struct {
-	ID       string `json:"id"`
-	Parent   string `json:"parent"`
-	Name     string `json:"name"`
-	Phone    string `json:"phone"`
-	Role     string `json:"role"`
-	Perms    string `json:"perms"`
-	State    int32  `json:"state"`
-	Key      string `json:"key"`
-	UserType int    `json:"userType"`
+	ID        string `json:"id"`
+	Name      string `json:"name"`
+	LoginName string `json:"loginName"`
+	Role      string `json:"role"`
+	State     int32  `json:"state"`
 }
 
 func UtilQueryMap(c *gin.Context) map[string]interface{} {

+ 8 - 10
oilseal-train/api/jwt.go

@@ -41,11 +41,11 @@ func NewUitlsJwt(app *conf.AppConf) *UtilsJwt {
 		PayloadFunc: func(data interface{}) jwt.MapClaims {
 			if v, ok := data.(*JWTUser); ok {
 				return jwt.MapClaims{
-					"id":     v.ID,
-					"phone":  v.Phone,
-					"role":   v.Role,
-					"parent": v.Parent,
-					"state":  v.State,
+					"id":        v.ID,
+					"name":      v.Name,
+					"loginName": v.LoginName,
+					"role":      v.Role,
+					"state":     v.State,
 				}
 			}
 			return jwt.MapClaims{}
@@ -55,10 +55,8 @@ func NewUitlsJwt(app *conf.AppConf) *UtilsJwt {
 			// lg.Debug().Msgf("token: %v\n", claims)
 
 			u := &JWTUser{
-				ID:     claims["id"].(string), //uint32(claims["id"].(float64)),
-				Phone:  claims["phone"].(string),
-				Role:   claims["role"].(string),
-				Parent: claims["parent"].(string),
+				ID:   claims["id"].(string), //uint32(claims["id"].(float64)),
+				Role: claims["role"].(string),
 			}
 			if claims["state"] != nil {
 				u.State = int32(claims["state"].(float64))
@@ -68,7 +66,7 @@ func NewUitlsJwt(app *conf.AppConf) *UtilsJwt {
 		},
 
 		Authenticator: func(c *gin.Context) (interface{}, error) {
-			return &JWTUser{Phone: "empty"}, nil
+			return &JWTUser{}, nil
 		},
 
 		Authorizator: func(data interface{}, _ *gin.Context) bool {

+ 5 - 3
oilseal-train/api/router.go

@@ -9,9 +9,11 @@ import (
 // RegRouters 注册路由
 func RegRouters(svc *Service) {
 
-	_3dshow := svc.NewGinRouter("/" + svc.Conf.Name)
-	_3dshow.group.Use(Logger())
-	_3dshow.GET("/printr", Printr)
+	train := svc.NewGinRouter("/" + svc.Conf.Name)
+	train.group.Use(Logger())
+	train.GET("/printr", Printr)
+
+	User(train)
 
 }
 

+ 1 - 1
oilseal-train/api/test_print.go

@@ -6,5 +6,5 @@ import (
 
 func Printr(c *gin.Context, apictx *ApiSession) (interface{}, error) {
 
-	return nil, nil
+	return "success", nil
 }

+ 377 - 0
oilseal-train/api/user.go

@@ -0,0 +1,377 @@
+package api
+
+import (
+	"errors"
+	"fmt"
+	"oilseal-train/db/model"
+	"oilseal-train/db/repo"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/xuri/excelize/v2"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+func User(r *GinRouter) {
+	r.POST("/user/login", Login)
+	r.POST("/user/register", Register)
+	r.POSTJWT("/user/create", UserAdd)
+	r.GETJWT("/user/list", UserList)
+	r.POSTJWT("/user/update", UserEdit)
+	r.POSTJWT("/user/delete/:id", UserDelete)
+	r.GETJWT("/user/exportXls", UserExportXls)
+	r.POSTJWT("/user/importXls", UserImportXls)
+}
+
+// 用户登录 student teacher admin
+func Login(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	var form model.User
+
+	err := c.ShouldBindJSON(&form)
+	if err != nil {
+		return nil, errors.New("参数错误")
+	}
+
+	ctx := apictx.CreateRepoCtx()
+	// 查找用户
+	user := &model.User{}
+	options := &repo.DocSearchOptions{
+		Query:       repo.Map{"loginName": form.LoginName, "password": UtilMd5(form.Password)},
+		CollectName: repo.CollectionUser,
+	}
+	found, err := repo.RepoSeachDoc(ctx, options, user)
+	if err != nil {
+		return false, err
+	}
+	if !found {
+		return false, NewError("账号密码不对")
+	}
+	if user.State == -1 {
+		return false, NewError("当前用户已禁用")
+	}
+	if form.Role != user.Role {
+		return false, NewError("当前账号角色不正确")
+	}
+
+	// 封装JWT
+	jwtU := &JWTUser{ID: user.Id.Hex(), Name: user.Name, LoginName: user.LoginName, State: 1, Role: user.Role}
+
+	token, _, err := apictx.Svc.JWT.JwtCreateToken(jwtU)
+	if err != nil {
+		return false, err
+	}
+
+	// 前端返回处理
+	user.Password = ""
+	out := map[string]interface{}{
+		"token": token,
+		"user":  user,
+	}
+	return out, nil
+}
+
+// 创建账号 主要用于admin注册
+func Register(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	var form model.User
+	err := c.ShouldBindJSON(&form)
+	if err != nil {
+		return nil, errors.New("参数错误")
+	}
+	if form.LoginName == "" {
+		return nil, errors.New("登录名为空")
+	}
+	if form.Password == "" {
+		return nil, errors.New("密码为空")
+	}
+	form.Role = "admin"
+	form.State = 1
+	form.Password = UtilMd5(form.Password)
+	form.CreateTime = time.Now()
+	form.UpdateTime = time.Now()
+	return repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, &form)
+}
+
+// 添加用户
+func UserAdd(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	var form model.User
+	err := c.ShouldBindJSON(&form)
+	if err != nil {
+		return nil, errors.New("参数错误")
+	}
+	if form.LoginName == "" {
+		return nil, errors.New("登录名为空")
+	}
+	if form.Password == "" {
+		return nil, errors.New("密码为空")
+	}
+	if form.Role == "" {
+		return nil, errors.New("角色为空")
+	}
+	form.State = 1
+	form.Password = UtilMd5(form.Password)
+	form.CreateTime = time.Now()
+	form.UpdateTime = time.Now()
+	return repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, &form)
+}
+
+// 用户列表 模糊匹配
+func UserList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	page, size, query := UtilQueryPageSize(c)
+	if _name, ok := query["name"]; ok {
+		query["name"] = bson.M{"$regex": _name.(string)}
+	}
+	if _loginName, ok := query["loginName"]; ok {
+		query["loginName"] = bson.M{"$regex": _loginName.(string)}
+	}
+	return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
+		CollectName: repo.CollectionUser,
+		Page:        page,
+		Size:        size,
+		Query:       query,
+		Project:     []string{"name", "loginName", "role", "createTime", "updateTime"},
+		Sort:        bson.M{"_id": -1},
+	})
+}
+
+// 更新用户
+func UserEdit(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	var form model.User
+	err := c.ShouldBindJSON(&form)
+	if err != nil {
+		return nil, errors.New("参数错误")
+	}
+	if len(form.Id) != 12 {
+		return nil, errors.New("id不正确")
+	}
+
+	return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionUser, form.Id.Hex(), &form)
+}
+
+// 删除用户
+func UserDelete(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	_id := c.Param("id")
+	_, err := primitive.ObjectIDFromHex(_id)
+	if err != nil {
+		return nil, errors.New("id错误")
+	}
+	return repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionUser, _id)
+}
+
+type ExcelColumn struct {
+	Style  int
+	Width  float64
+	Header string
+	Key    string
+}
+
+// 6396e841e90c9e38d70793d0,6396e841e90c9e38d70793d0
+func UserExportXls(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	selections := c.Query("selections")
+	query := repo.Map{}
+	if len(selections) > 12 {
+		selects := strings.Split(selections, ",")
+		query["_id"] = bson.M{"$in": selects}
+	}
+	users := make([]map[string]interface{}, 0)
+	err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
+		CollectName: repo.CollectionUser,
+		Query:       query,
+		Sort:        bson.M{"_id": -1},
+	}, &users)
+	if err != nil {
+		return nil, err
+	}
+	if len(users) < 1 {
+		return users, nil
+	}
+
+	f := excelize.NewFile()
+	defer f.Close()
+
+	sheetName := "用户列表"
+	f.SetSheetName("Sheet1", sheetName)
+	f.SetPageLayout(sheetName, excelize.PageLayoutOrientation("portrait"), excelize.PageLayoutPaperSize(9))
+
+	f.SetHeaderFooter(sheetName, &excelize.FormatHeaderFooter{
+		FirstHeader: "用户列表",
+		FirstFooter: "用户列表",
+		OddFooter:   "第 &P 页,共 &N页",
+	})
+
+	style, _ := f.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{
+			Horizontal: "center",
+			Vertical:   "center",
+		},
+	})
+	columns := []ExcelColumn{
+		{
+			Style:  style,
+			Width:  20,
+			Header: "登录名",
+			Key:    "loginName",
+		},
+		{
+			Style:  style,
+			Width:  20,
+			Header: "姓名",
+			Key:    "name",
+		},
+		{
+			Style:  style,
+			Width:  20,
+			Header: "角色",
+			Key:    "role",
+		},
+		{
+
+			Style:  style,
+			Width:  40,
+			Header: "密码",
+			Key:    "password",
+		},
+	}
+
+	// 代表每列的单元格字符
+	cos := []string{"A", "B", "C", "D"}
+	// 设置列格式 和 表头内容(第一列)
+	i := 1
+	for k, col := range columns {
+		f.SetColStyle(sheetName, cos[k], col.Style)
+		f.SetColWidth(sheetName, cos[k], cos[k], col.Width) // A,A,10
+		setstring := fmt.Sprintf("%s%d", cos[k], i)
+		f.SetCellValue(sheetName, setstring, col.Header)
+	}
+
+	setCellKey := map[string]string{
+		"A": "name",
+		"B": "loginName",
+		"C": "role",
+		"D": "password",
+	}
+
+	i++
+	// rows
+	for _, user := range users {
+		// 每行的单元格
+		for k, v := range user {
+			for _, c := range cos {
+				// "id" == "id" -- set A3
+				if setCellKey[c] == k { // A,B,C与item.key的关系
+					setString := fmt.Sprintf("%s%d", c, i)
+					f.SetCellValue(sheetName, setString, v)
+				}
+			}
+		}
+		i++
+
+	}
+	// 另存为
+	_ = os.MkdirAll("excel", os.ModePerm)
+	filename1 := time.Now().Format("20060102150405") + ".xlsx"
+	err = f.SaveAs(filename1)
+	if err != nil {
+		return nil, err
+	}
+
+	filename := time.Now().Format("20060102150405") + ".xlsx"
+	c.Header("Content-Type", "application/octet-stream")
+	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
+	c.Header("Content-Transfer-Encoding", "binary")
+	err = f.Write(c.Writer)
+
+	if err != nil {
+		fmt.Println(err)
+		return false, err
+	}
+
+	return true, nil
+
+}
+
+func UserImportXls(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 操作用户为admin
+	if apictx.User.Role != "admin" {
+		return nil, errors.New("当前用户不是管理员")
+	}
+	file, _, err := c.Request.FormFile("file")
+	if err != nil {
+		return nil, errors.New("文件错误")
+	}
+	excel, err := excelize.OpenReader(file)
+	if err != nil {
+		return nil, err
+	}
+	users, err := excel.GetRows("用户列表")
+	if err != nil {
+		return nil, err
+	}
+	errors := []error{}
+	if len(users) > 0 {
+		for index, user := range users {
+			if index == 0 {
+				continue
+			}
+			addUser, err := formatUser(user, index)
+			if err != nil {
+				errors = append(errors, err)
+				continue
+			}
+			_, err = repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, addUser)
+			if err != nil {
+				errf := fmt.Errorf("第%d行%s", index, err.Error())
+				errors = append(errors, errf)
+			}
+
+		}
+	}
+
+	return errors, nil
+}
+
+func formatUser(u []string, rowNum int) (*model.User, error) {
+	user := &model.User{
+		LoginName: u[0],
+		Name:      u[1],
+		Role:      u[2],
+		Password:  u[3],
+	}
+
+	if user.LoginName == "" {
+		return nil, fmt.Errorf("第%d行%s", rowNum, "登录名为空")
+	}
+
+	if user.Role == "" {
+		return nil, fmt.Errorf("第%d行%s", rowNum, "角色为空")
+	}
+	if user.Password == "" {
+		return nil, fmt.Errorf("第%d行%s", rowNum, "角色为空")
+	}
+	user.State = 1
+	user.CreateTime = time.Now()
+	user.UpdateTime = time.Now()
+	return user, nil
+}

+ 2 - 2
oilseal-train/app.yaml

@@ -17,7 +17,7 @@ debug:
   UserRole: string
 
 nats:
-  # url: nats://124.71.139.24:14302
-  url: nats://127.0.0.1:14302
+  url: nats://124.71.139.24:14302
+  # url: nats://127.0.0.1:14302
   maxReconnect: 1000
   reconnDelaySecond: 5

+ 1 - 1
oilseal-train/db/db.go

@@ -35,7 +35,7 @@ func (db *MongoDB) GetOrCreateDatabase(name string) *mongo.Database {
 }
 
 func NewMongoDB(bus *comm.NatsBus) *MongoDB {
-	inst, err := bus.NewMongoDBFromConfig("oilseal-train-mongo")
+	inst, err := bus.NewMongoDBFromConfigDev("oilseal-train-mongo")
 	if err != nil {
 		panic(err)
 	}

+ 0 - 26
oilseal-train/db/model/product.go

@@ -1,26 +0,0 @@
-package model
-
-import (
-	"time"
-
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
-
-// 产品
-type Product struct {
-	Id         primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
-	SupplyId   primitive.ObjectID `bson:"supplyId,omitempty" json:"supplyId"`
-	AssetId    primitive.ObjectID `bson:"assetId,omitempty" json:"assetId"`
-	Name       string             `bson:"name,omitempty" json:"name"`
-	Type       string             `bson:"type,omitempty" json:"type"` // 类型 单鞋:shoes 凉鞋:sandals 靴子:boots
-	Unit       string             `bson:"unit,omitempty" json:"unit"` // 型号
-	Price      float64            `bson:"price,omitempty" json:"price"`
-	Cover      string             `bson:"cover,omitempty" json:"cover"` // 封面图
-	Colors     []string           `bson:"colors,omitempty" json:"colors"`
-	Size       []int              `bson:"size,omitempty" json:"size"`                 // 尺寸
-	Thumbnail  []string           `bson:"thumbnail,omitempty" json:"thumbnail"`       // 缩略图集合
-	Status     int                `bson:"status,omitempty" json:"status"`             // -1:下架 1:上架
-	OnsaleTime time.Time          `bson:"onsaleTime,omitempty" json:"onsaleTimeTime"` // 上架时间
-	CreateTime time.Time          `bson:"createTime,omitempty" json:"createTime"`
-	UpdateTime time.Time          `bson:"updateTime,omitempty" json:"updateTime"`
-}

+ 19 - 0
oilseal-train/db/model/user.go

@@ -0,0 +1,19 @@
+package model
+
+import (
+	"time"
+
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+// 用户
+type User struct {
+	Id         primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
+	LoginName  string             `bson:"loginName,omitempty" json:"loginName,omitempty"`
+	Password   string             `bson:"password,omitempty" json:"password,omitempty"`
+	Name       string             `bson:"name,omitempty" json:"name,omitempty"`
+	Role       string             `bson:"role,omitempty" json:"role,omitempty"` // admin student teacher
+	CreateTime time.Time          `bson:"createTime,omitempty" json:"createTime,omitempty"`
+	UpdateTime time.Time          `bson:"updateTime,omitempty" json:"updateTime,omitempty"`
+	State      int32              `bson:"state,omitempty" json:"state,omitempty"` //-1 禁用 1 正常
+}

+ 1 - 1
oilseal-train/db/redis.go

@@ -6,7 +6,7 @@ import (
 )
 
 func NewRedisClient(bus *comm.NatsBus) *redis.Client {
-	client, err := bus.NewRedisFromConfig("oilseal-train-redis")
+	client, err := bus.NewRedisFromConfigDev("oilseal-train-redis")
 	if err != nil {
 		return nil
 	}

+ 1 - 7
oilseal-train/db/repo/repo.go

@@ -18,13 +18,7 @@ type RepoSession struct {
 }
 
 const (
-	CollectionSupply   = "supply"
-	CollectionCollect  = "collect"
-	CollectionProduct  = "product"
-	CollectionAddress  = "address"
-	CollectionOrder    = "order"
-	CollectionShopCart = "shopCart"
-	CollectionAssets   = "assets"
+	CollectionUser = "users"
 )
 
 type Map map[string]interface{}

+ 9 - 3
oilseal-train/go.mod

@@ -10,6 +10,7 @@ require (
 	github.com/go-redis/redis/v8 v8.11.5
 	github.com/natefinch/lumberjack v2.0.0+incompatible
 	github.com/spf13/viper v1.9.0
+	github.com/xuri/excelize/v2 v2.6.1
 	go.mongodb.org/mongo-driver v1.9.1
 	go.uber.org/dig v1.12.0
 	go.uber.org/zap v1.17.0
@@ -43,6 +44,7 @@ require (
 	github.com/mitchellh/mapstructure v1.4.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
 	github.com/nats-io/jwt/v2 v2.3.0 // indirect
 	github.com/nats-io/nats.go v1.13.1-0.20220308171302-2f2f6968e98d // indirect
 	github.com/nats-io/nkeys v0.3.0 // indirect
@@ -50,6 +52,8 @@ require (
 	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
 	github.com/pelletier/go-toml v1.9.4 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/richardlehane/mscfb v1.0.4 // indirect
+	github.com/richardlehane/msoleps v1.0.3 // indirect
 	github.com/spf13/afero v1.6.0 // indirect
 	github.com/spf13/cast v1.4.1 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -59,13 +63,15 @@ require (
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.0.2 // indirect
 	github.com/xdg-go/stringprep v1.0.2 // indirect
+	github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
+	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
-	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
+	golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
+	golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
-	golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
+	golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect

+ 27 - 8
oilseal-train/go.sum

@@ -284,6 +284,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
 github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
@@ -314,6 +316,11 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
+github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
+github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
+github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@@ -336,8 +343,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tidwall/gjson v1.9.4 h1:oNis7dk9Rs3dKJNNigXZT1MTOiJeBtpurn+IpCB75MY=
@@ -356,6 +364,12 @@ github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c=
+github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.6.1 h1:ICBdtw803rmhLN3zfvyEGH3cwSmZv+kde7LhTDT659k=
+github.com/xuri/excelize/v2 v2.6.1/go.mod h1:tL+0m6DNwSXj/sILHbQTYsLi9IF4TW59H2EF3Yrx1AU=
+github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M=
+github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -395,8 +409,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
+golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -409,6 +423,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
+golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -470,8 +486,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
+golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -556,10 +573,11 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -784,8 +802,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=