package service import ( "context" "errors" "finclip-app-manager/domain/entity" "finclip-app-manager/domain/entity/proto/apiproto" "finclip-app-manager/domain/repository" "finclip-app-manager/infrastructure/client/httpcall" "finclip-app-manager/infrastructure/config" impl "finclip-app-manager/infrastructure/db/repo" "finclip-app-manager/infrastructure/kafka" "finclip-app-manager/infrastructure/utility" "finclip-app-manager/infrastructure/utils" "fmt" "net/http" "regexp" "strconv" "strings" "sync" "time" "unicode" "gitlab.finogeeks.club/finclip-backend/apm" "github.com/Chain-Zhang/pinyin" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "gopkg.in/mgo.v2/bson" ) const ( MAX_EXPIRE_DATA = 9999999999999 ) var gAutoBindMap = new(sync.Map) type BindingService struct { appRepo repository.AppRepository bindRepo repository.IBindingRepo bundleRepo repository.IBundleRepo } func NewBindingService() *BindingService { return &BindingService{ appRepo: impl.InitAppRepo(), bindRepo: impl.InitBindingRepo(), bundleRepo: impl.InitBundleRepo(), } } func (s BindingService) CheckReviewBySdkKey(ctx context.Context, sdkKey string) string { //return s.bindRepo.CheckReviewBySdkKey(ctx, sdkKey) reviewItem, err := s.bindRepo.GetReviewBindBySdkKey(ctx, sdkKey) if err != nil || reviewItem == nil || reviewItem.IsReview == 0 { return utility.FS_NOT_REVIEW_BINDING_ERR } if reviewItem.Status == entity.StBindInvalid { return utility.FS_COOPERATION_TERMINATED } if reviewItem.IsForbidden == 1 { return utility.FS_BIND_IS_FORBIDDEN } return utility.OK } func (s BindingService) SyncOrganBinding(ctx context.Context, req apiproto.SyncOrganBindingReq) (int, string, interface{}) { errRsp := make(map[string]interface{}) if req.Operation == "modify-group" { err := s.bindRepo.UpdateBindingGroupName(ctx, req.GroupID, req.GroupName) if err != nil && !s.NotFound(err) { log.Errorf("SyncOrganBinding UpdateBindingGroupName groupId:%s groupName:%s err:%s", req.GroupID, req.GroupName, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } log.Infof("SyncOrganBinding UpdateBindingGroupName groupId:%s groupName:%s succ", req.GroupID, req.GroupName) return http.StatusOK, utility.OK, nil } bindList, _, err := s.bindRepo.GetBindingsBySearch(ctx, 10000, 1, "", "", "", "all", entity.BINGING_PLATFORM_OPER) if err != nil { log.Errorf("SyncOrganBinding get bindings list err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } log.Infof("groupId:%s groupName:%s sync bind len:%d", req.GroupID, req.GroupName, len(bindList)) for _, bind := range bindList { copyBind := &entity.Binding{} copier.Copy(©Bind, &bind) copyBind.BindingID = bson.NewObjectId().Hex() copyBind.FromBindingID = bind.BindingID copyBind.GroupID = req.GroupID copyBind.GroupName = req.GroupName accountInfo := &httpcall.AccountInfoData{Account: copyBind.CreatedInfo.CreatedAccount} if copyBind.AutoBind == entity.BINGING_AUTO_BIND { s.operAutoAppBind(ctx, copyBind, accountInfo) } err = s.bindRepo.Insert(ctx, copyBind) if err != nil { log.Errorf("SyncOrganBinding insert groupId:%s groupName:%s copybind err:%s", req.GroupID, req.GroupName, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } else { log.Infof("SyncOrganBinding insert groupId:%s groupName:%s copybind origin binding:%s succ", req.GroupID, req.GroupName, bind.BindingID) } } return http.StatusOK, utility.OK, nil } func (s BindingService) GetBindingUsed(ctx context.Context) (int, string, interface{}) { rsp := make(map[string]interface{}) licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("GetBindingUsed bind err:%s", err.Error()) return http.StatusBadRequest, utility.FS_BAD_JSON, rsp } bindTotal, err := s.bindRepo.GetCountByStatus(ctx, "Valid", entity.BINGING_PLATFORM_ALL) if err != nil { log.Errorf("BindingLicenseCheck count err:", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, err } log.Infof("license CooAppCount:%d bindTotal:%d", licenseInfo.CooAppCount, bindTotal) return http.StatusOK, utility.OK, entity.BindingUsed{ LimitNum: licenseInfo.CooAppCount, HasUseNum: bindTotal, RemainNum: licenseInfo.CooAppCount - bindTotal, } } func (s BindingService) Create(ctx context.Context, c *gin.Context, bind *entity.Binding, isAdmin bool) (int, string, interface{}) { //license 校验 rsp := make(map[string]interface{}) licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("CreateBinding bind err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, rsp } developerID := c.Request.Header.Get("X-Consumer-Custom-ID") if !isAdmin && (config.Cfg.PublishEnv == entity.ENV_PRIVATE) { bindLimit, err := hCaller.GetBindLimitInfo(ctx, developerID) if err != nil { log.Errorf("CreateBinding bind err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, rsp } if bindLimit.CreateBinding != 1 { return http.StatusBadRequest, utility.FS_MANAGE_APP_NO_AUTH, rsp } } //if config.Cfg.PublishEnv == common.ENV_PRIVATE { httpCode, errCode, err := s.BindingLicenseCheck(ctx, licenseInfo, bind, isAdmin) if err != nil { return httpCode, errCode, rsp } //} groupInfo := &httpcall.GroupIDData{} if !isAdmin { groupInfo, err = hCaller.GetGroupInfoByUserId(ctx, developerID) if err != nil { log.Errorf("CreateBinding GetGroupInfoByUserId err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED, rsp } } accountInfo := &httpcall.AccountInfoData{} if isAdmin { operAccount, err := hCaller.GetAdminAccountInfo(ctx, developerID) if err != nil { log.Errorf("CreateBinding GetAccountInfo err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_GET_ACCOUNTINFO_ERROR, rsp } accountInfo.Account = operAccount.Account accountInfo.Name = operAccount.Name } else { organAccount, err := hCaller.GetAccountInfo(ctx, developerID) if err != nil { log.Errorf("CreateBinding GetAccountInfo err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_GET_ACCOUNTINFO_ERROR, rsp } accountInfo.Account = organAccount.Account accountInfo.Name = organAccount.Name } timestamp := time.Now().UnixNano() / 1000000 bind.BindingID = bson.NewObjectId().Hex() bind.CreatedInfo = entity.CreatedInfo{ CreatedBy: developerID, CreatedAt: timestamp, CreatedAccount: accountInfo.Account, } if isAdmin { bind.PlatForm = entity.BINGING_PLATFORM_OPER } //这里将group name也加进来,供查找用 //todo 修改group name的时候需要进行同步 bind.GroupName = groupInfo.GroupName bind.GroupID = groupInfo.GroupID bind.CooperateStatus = entity.Status{ Value: entity.StBindValid, LastUpdated: timestamp, ModifiedBy: accountInfo.Account, } repo := impl.InitBindingRepo() _, err = repo.GetByGroupIdAndName(ctx, groupInfo.GroupID, bind.Name, isAdmin) if err != nil && !repo.NotFound(err) { log.Errorf("CreateBinding get binding info err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, rsp } if !repo.NotFound(err) { log.Errorln("CreateBinding get binding info not found!") return http.StatusBadRequest, utility.FS_BINDING_NAME_REPEAT, rsp } if isAdmin { httpCode, statusCode := s.operBundle(ctx, bind, accountInfo) if httpCode != http.StatusOK { return httpCode, statusCode, nil } } //调用支付系统进行权限校验 if config.GetConfig().OpenPurchAuth && config.GetConfig().PublishEnv == entity.ENV_UAT { applyReq := httpcall.PayAddLimitReq{} applyReq.Type = httpcall.PAY_ADD_TYPE_BINDING applyReq.AccountId = developerID applyReq.BusinessId = bind.BindingID applyReq.BusinessName = bind.Name payAddRsp, httpCode, err := hCaller.PayAddLimit(ctx, &applyReq) if err != nil { return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, rsp } if httpCode != http.StatusOK { return httpCode, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, rsp } if payAddRsp.Data.EndTime == 0 { payAddRsp.Data.EndTime = MAX_EXPIRE_DATA } bind.Expire = payAddRsp.Data.EndTime } else { if !isAdmin { n := httpcall.AddLimitInfoReq{ Type: "binding", OrganId: bind.GroupID, AddNum: 1, } _, _, err = hCaller.AddLimitInfo(ctx, &n) if err != nil { log.Errorf("Failed to notify: %v\n", err) return http.StatusBadRequest, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, nil } } bind.Expire = getExpire(bind.Expire, licenseInfo.ExpireTime) } //生成子域名 if config.GetConfig().PublishEnv == entity.ENV_FDEP { resultDomain, err := getResultSubDomain(ctx, bind.GroupName, bind.Name) if err != nil { log.Errorf("get result domain error: %v,groupName:%s,bindName:%s", err, bind.GroupName, bind.Name) return http.StatusBadRequest, utility.FS_ALIYUN_ADD_ERR, nil } bind.ApiServer = resultDomain } if config.GetConfig().PublishEnv == entity.ENV_UAT { bind.ApiServer = config.GetConfig().ApiServer //"https://api.finclip.com" } if config.GetConfig().PublishEnv == entity.ENV_PRIVATE { bind.ApiServer = "" } //再插入 err = repo.Insert(ctx, bind) if err != nil { log.Errorf("CreateBinding insert binding info err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, rsp } if isAdmin { err = s.copyOperBinding(ctx, bind, accountInfo) if err != nil { log.Errorf("CreateBinding insert copy binding info err:%s", err.Error()) } } //生成操作日志 logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, groupInfo.GroupID, kafka.GenContent(kafka.BIND_ADD_LOG, bind.Name), logExp, accountInfo.Account) //移除kafka,这段代码不需要 /*if config.GetConfig().PublishEnv == entity.ENV_FDEP { //fdep才会上报tam备案 go kafka.GenTamRecordContentData(ctx, groupInfo.GroupID, bind.Owner, groupInfo.SocialCreditCode) }*/ return http.StatusCreated, utility.OK, bind } func (s BindingService) operBundle(ctx context.Context, bind *entity.Binding, accountInfo *httpcall.AccountInfoData) (int, string) { dupBundle := make(map[string]bool) bundleIds := []string{} for _, bundle := range bind.BundleInfos { if _, ok := dupBundle[bundle.BundleID]; ok { return http.StatusBadRequest, utility.FS_OPER_REPEAT_BUNDLE_ERR } dupBundle[bundle.BundleID] = true bundleIds = append(bundleIds, bundle.BundleID) } bundles, err := s.bundleRepo.GetListByBundleIds(ctx, bundleIds) if err != nil { return http.StatusInternalServerError, utility.FS_DB_ERR } bundleMap := make(map[string]entity.Bundle) for _, bundle := range bundles { bundleMap[bundle.BundleID] = bundle } bundleReq := []apiproto.CreateBundleReq{} for _, item := range bind.BundleInfos { if bundle, ok := bundleMap[item.BundleID]; ok { if bundle.IsForbidden == 0 { bundleReq = append(bundleReq, apiproto.CreateBundleReq{ BundleId: item.BundleID, Platform: bundle.Remark, SDKKey: item.SDKKey, SDKID: item.SDKID, IsFirstCreate: item.IsFirstCreate, CreatedAt: item.CreatedAt, CreatedAccount: item.CreatedAccount, CreatedBy: item.CreatedBy, IsForbidden: item.IsForbidden, }) } } } if len(bundleReq) <= 0 { return http.StatusBadRequest, utility.FS_OPER_CREATE_BUNDLE_ERR } statusCode, _ := s.BindBundles(ctx, bind.BindingID, bind.GroupID, accountInfo, bundleReq, bind, true) if statusCode != utility.OK { return http.StatusInternalServerError, statusCode } return http.StatusOK, utility.OK } func (s BindingService) operAutoMergeAppBind(ctx context.Context, bind *entity.Binding, accountName string) { _, apps, err := s.appRepo.ListApps(ctx, bind.GroupID, 1, 10000, "", "", "") if err != nil { log.Errorf("operAutoMergeAppBind organ:%s name:%s list app err:%s", bind.GroupID, bind.GroupName, err.Error()) return } exsitApps := make(map[string]bool) for _, app := range bind.AppInfos { exsitApps[app.AppID] = true } appendApps := []entity.AppInfo{} now := time.Now().UnixNano() / 1e6 for _, app := range apps { if _, ok := exsitApps[app.AppID]; !ok { appendApps = append(appendApps, entity.AppInfo{ AppID: app.AppID, AssociatedAt: now, AssociatedBy: accountName, }) } } err = s.bindRepo.AppendApps(ctx, bind.BindingID, appendApps) if err != nil { log.Errorf("operAutoMergeAppBind AppendApps err:%s", err.Error()) } } func (s BindingService) operAutoAppBind(ctx context.Context, bind *entity.Binding, accountInfo *httpcall.AccountInfoData) { _, apps, err := s.appRepo.ListApps(ctx, bind.GroupID, 1, 10000, "", "", "") if err != nil { log.Errorf("oper auto organ:%s name:%s app bind err:%s", bind.GroupID, bind.GroupName, err.Error()) return } now := time.Now().UnixNano() / 1e6 for _, app := range apps { bind.AppInfos = append(bind.AppInfos, entity.AppInfo{ AppID: app.AppID, AssociatedAt: now, AssociatedBy: accountInfo.Account, }) } } func (s BindingService) mergeOrganBundle(ctx context.Context, bind *entity.Binding) (bool, error) { list, _, err := s.bindRepo.GetDevListBinding(ctx, 10000, 1, "", "", "", bind.GroupID, "", entity.BINGING_PLATFORM_ORGAN) if err != nil { log.Errorf("get organ binding list err:%s", err.Error()) return false, err } exsitBundle := make(map[string]bool) for _, item := range list { for _, bundle := range item.BundleInfos { exsitBundle[bundle.BundleID] = true } } hasAppend := false newBundle := []entity.BundleInfo{} for _, bundle := range bind.BundleInfos { if _, ok := exsitBundle[bundle.BundleID]; !ok { newBundle = append(newBundle, bundle) hasAppend = true } } bind.BundleInfos = newBundle return hasAppend, nil } func (s BindingService) copyOperBinding(ctx context.Context, bind *entity.Binding, accountInfo *httpcall.AccountInfoData) error { log.Infof("copy oper binding begin") list, err := hCaller.GetOrganList(ctx) if err != nil { log.Errorf("copyOperBinding get organ list err:%s", err.Error()) return err } log.Infof("get organ list len:%d", len(list)) repo := impl.InitBindingRepo() for _, item := range list { copyBind := &entity.Binding{} copier.Copy(©Bind, &bind) copyBind.BindingID = bson.NewObjectId().Hex() copyBind.FromBindingID = bind.BindingID copyBind.GroupID = item.OrganId copyBind.GroupName = item.Name s.mergeOrganBundle(ctx, copyBind) // 有bundleID才同步合作应用 if len(copyBind.BundleInfos) <= 0 { continue } if copyBind.AutoBind == entity.BINGING_AUTO_BIND { s.operAutoAppBind(ctx, copyBind, accountInfo) } err = repo.Insert(ctx, copyBind) if err != nil { log.Errorf("copyOperBinding insert groupId:%s groupName:%s copybind err:%s", item.OrganId, item.Name, err.Error()) return err } log.Infof("copy oper binding to organ:%s succ", item.OrganId) } return nil } func (s BindingService) AutoBindingAppByCreate(app *entity.App, accountId string) { start := time.Now().UnixNano() / 1e6 log.Debugf("AutoBindingAppByCreate app:%s accountId:%s binding start", app.AppID, accountId) ctx := context.Background() accountInfo, err := httpcall.NewClient().GetAccountInfo(ctx, accountId) if err != nil { log.Errorf("AutoBindingAppByCreate get account info err:%s", err.Error()) return } groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, accountId) if err != nil { log.Errorf("AutoBindingAppByCreate GetGroupInfoByUserId err:%s", err.Error()) return } bindingIds, err := s.bindRepo.ListAutoBindAppBinding(ctx, groupInfo.GroupID) if err != nil { log.Errorf("AutoBindingAppByCreate ListAutoBindAppBinding err:%s", err.Error()) return } list, err := s.bindRepo.GetByBindIdList(ctx, bindingIds) if err != nil { log.Errorf("AutoBindingAppByCreate GetByBindIdList err:%s", err.Error()) return } now := time.Now().UnixNano() / 1e6 for idx := range list { appInfo := entity.AppInfo{ AppID: app.AppID, AssociatedAt: now, AssociatedBy: accountInfo.Account, } list[idx].AppInfos = append(list[idx].AppInfos, appInfo) err = s.UpdateByBindId(ctx, list[idx].BindingID, &list[idx]) if err != nil { log.Errorf("AutoBindingAppByCreate UpdateByBindId bindingID:%s err:%s", list[idx].BindingID, err.Error()) } } end := time.Now().UnixNano() / 1e6 log.Debugf("AutoBindingAppByCreate app:%s accountId:%s binding finish handle len:%d spend:%d ms", app.AppID, accountId, len(list), end-start) } func (s BindingService) BindingLicenseCheck(ctx context.Context, licenseInfo *httpcall.LicenseData, bindingReq *entity.Binding, isAdmin bool) (int, string, error) { log.Infof("BindingLicenseCheck get license info:%+v", licenseInfo) //校验应用数量 repo := impl.InitBindingRepo() platform := entity.BINGING_PLATFORM_ORGAN if isAdmin { platform = entity.BINGING_PLATFORM_OPER } bindTotal, err := repo.GetCountByStatus(ctx, "Valid", platform) if err != nil { log.Errorf("BindingLicenseCheck count err:", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, err } if licenseInfo.CooAppCount <= bindTotal { log.Errorf("BindingLicenseCheck bind total over limit,bind num:%d,license num:%d", bindTotal, licenseInfo.CooAppCount) return http.StatusForbidden, utility.FC_PRI_OPERA_LIMIT_BIND_OVER_ERROR, errors.New("binding limit over license limit") } /* //校验bundleId总数 bundleIdTotal, err := repo.GetBundleIdNum(ctx) if err != nil { log.Errorf("BindingLicenseCheck count bundle id err:", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, err } if licenseInfo.BundleIdCount < bundleIdTotal+len(bindingReq.BundleInfos) { log.Errorf("BindingLicenseCheck BundleId total over limit,bundleIdTotal:%d, len(bindingReq.BundleInfos):%d, license num:%d", bundleIdTotal, len(bindingReq.BundleInfos), licenseInfo.BundleIdCount) return http.StatusForbidden, utility.FS_BUNDLE_ID_COUNT_OVER, errors.New("bundle id limit over license limit") } */ return http.StatusOK, utility.OK, nil } type DetailRsp struct { BindingID string `json:"bindingId"` //应用的id Name string `json:"name"` //应用名称 BundleInfos []entity.BundleInfo `json:"bundleInfos"` //bundle ids } func (s BindingService) Detail(c *gin.Context, ctx context.Context, bindingId string) { repo := impl.InitBindingRepo() bindingInfo, err := repo.GetInfo(ctx, bindingId) if err != nil { log.Errorf("BindingService Detail err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusNotFound, utility.FS_BAD_JSON, make(map[string]interface{})) return } licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("get license info err:%v", err) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_SYSTEM_CALL, make(map[string]interface{})) return } bindingInfo.Expire = getExpire(bindingInfo.Expire, licenseInfo.ExpireTime) rspData := DetailRsp{ BindingID: bindingInfo.BindingID, Name: bindingInfo.Name, } for _, v := range bindingInfo.BundleInfos { rspData.BundleInfos = append(rspData.BundleInfos, v) } utility.MakeLocRsp(c, http.StatusOK, utility.OK, bindingInfo) return } func (s BindingService) GetInfo(ctx context.Context, bindingId string) (*entity.Binding, error) { return s.bindRepo.GetInfo(ctx, bindingId) } func (s BindingService) BindBundles(ctx context.Context, bindingId, groupId string, accountInfo *httpcall.AccountInfoData, bundleReqs []apiproto.CreateBundleReq, binding *entity.Binding, isCreateBinding bool) (string, interface{}) { licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("BindBundles get license err:%s", err.Error()) return utility.FS_SYSTEM_CALL, nil } //repo := impl.InitBindingRepo() bundleCount, err := s.bindRepo.BundleIdCount(ctx, "") if err != nil { log.Errorf("BindBundles bundle count err:%s", err.Error()) return utility.FS_DB_ERR, nil } //数量只校验bundleReqs中,isForbidden为0(未禁用) lenCount := 0 for _, v := range bundleReqs { if v.IsForbidden == 0 { lenCount++ } } if config.Cfg.PublishEnv != entity.ENV_PRIVATE && config.Cfg.PublishEnv != entity.ENV_COMMUNITY { if licenseInfo.BundleIdCount < bundleCount+lenCount { log.Errorf("BindBundles over limit,license info:%+v,bundle id count:%d", licenseInfo, bundleCount) return utility.FS_BUNDLE_ID_COUNT_OVER_TO_WEB_ERR, nil } } statusCode, appendBundles := s.handleBundles(ctx, groupId, accountInfo, bundleReqs, licenseInfo, false) if statusCode != utility.OK { return statusCode, nil } if binding == nil { binding, err = s.bindRepo.GetBindingByGroupIdAndBindingId(ctx, groupId, bindingId) if err != nil { log.Errorln(fmt.Sprintf("GetOne err: %s", err)) return utility.FS_DB_ERR, nil } log.Infoln("binding %v", binding) } if isCreateBinding { if lenCount > config.GetConfig().AddAvailableBundleNum { return utility.FS_BUNDLE_AVAILABLE_NUM_LIMIT, nil } if len(bundleReqs) > config.GetConfig().AddALLBundleNum { return utility.FS_BUNDLE_ALL_NUM_LIMIT, nil } binding.BundleInfos = appendBundles } else { num := 0 for _, v := range binding.BundleInfos { if v.IsForbidden == 0 { num++ } } if num+lenCount > config.GetConfig().AddAvailableBundleNum { return utility.FS_BUNDLE_AVAILABLE_NUM_LIMIT, nil } if len(bundleReqs)+len(binding.BundleInfos) > config.GetConfig().AddALLBundleNum { return utility.FS_BUNDLE_ALL_NUM_LIMIT, nil } err = s.bindRepo.AppendBundles(ctx, bindingId, groupId, appendBundles) //err = s.bindRepo.UpdateBundleInfosByGroupIdAndBindId(ctx, groupId, bindingId, binding.BundleInfos) if err != nil { if err.Error() == utility.FS_BIND_IS_FORBIDDEN { log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return utility.FS_BIND_IS_FORBIDDEN, nil } log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return utility.FS_DB_ERR, nil } binding.BundleInfos = append(binding.BundleInfos, appendBundles...) } appIds := []string{} for _, v := range binding.AppInfos { appIds = append(appIds, v.AppID) } go s.AdminNotifySdkKey(ctx, appIds, binding, httpcall.BIND_SDK) return utility.OK, binding } func (s BindingService) AdminUpdateBundles(ctx context.Context, binding *entity.Binding, groupId string, bundleReqs []apiproto.CreateBundleReq) (int, string, interface{}) { errRsp := make(map[string]interface{}) originBundleReview := make(map[string]int) for _, bundle := range binding.BundleInfos { originBundleReview[bundle.BundleID] = bundle.IsReview } checkRepeat := make(map[string]bool) removeRepeat := []apiproto.CreateBundleReq{} for idx, bundle := range bundleReqs { if _, ok := checkRepeat[bundle.BundleId]; !ok { checkRepeat[bundle.BundleId] = true if v, exsit := originBundleReview[bundle.BundleId]; exsit { bundleReqs[idx].IsReview = v } else { bundleReqs[idx].IsReview = 0 } removeRepeat = append(removeRepeat, bundleReqs[idx]) } } bundleReqs = removeRepeat // 先修改运营端自身 statusCode, _ := s.UpdateBundles(ctx, binding.BindingID, groupId, bundleReqs) if statusCode != utility.OK { return http.StatusBadRequest, statusCode, errRsp } // 再修改从运营端复制的 bindingIds, _, err := s.bindRepo.ListCopyOperBinding(ctx, binding.BindingID) if err != nil { log.Errorf("AdminBindBundles ListCopyOperBinding bindingID:%s err:%s", binding.BindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } bindList, err := s.bindRepo.GetByBindIdList(ctx, bindingIds) if err != nil { log.Errorf("AdminBindBundles GetByBindIdList bindingID:%s err:%s", binding.BindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } updateReq := make(map[string]entity.BundleInfo) for _, bundleReq := range bundleReqs { updateReq[bundleReq.BundleId] = entity.BundleInfo{ BundleID: bundleReq.BundleId, Remark: bundleReq.Platform, IsForbidden: bundleReq.IsForbidden, CreatedBy: bundleReq.CreatedBy, CreatedAccount: bundleReq.CreatedAccount, CreatedAt: bundleReq.CreatedAt, IsFirstCreate: bundleReq.IsFirstCreate, SDKID: bundleReq.SDKID, SDKKey: bundleReq.SDKKey, } } for _, item := range bindList { updateBundles := []entity.BundleInfo{} for _, bundle := range item.BundleInfos { if v, ok := updateReq[bundle.BundleID]; ok { updateBundles = append(updateBundles, v) } else { updateBundles = append(updateBundles, bundle) } } err = s.bindRepo.UpdateBundles(ctx, item.BindingID, groupId, updateBundles) if err != nil { if err.Error() == utility.FS_BIND_IS_FORBIDDEN { log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return http.StatusInternalServerError, utility.FS_BIND_IS_FORBIDDEN, nil } else { log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } } } return http.StatusOK, utility.OK, nil } func (s BindingService) MoveBundles(ctx context.Context, bind *entity.Binding, req *apiproto.BindingUpdateRequest, platform int) (int, string, interface{}) { errRsp := make(map[string]interface{}) toBind, err := s.bindRepo.GetInfo(ctx, req.ToBindingID) if err != nil && !s.NotFound(err) { log.Errorf("MoveBundles get bindingId:%s binding info err:%s", req.ToBindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } if s.bindRepo.NotFound(err) { log.Errorf("MoveBundles get bindingId:%s binding info err:%s", req.ToBindingID, "NOT FOUND ID") return http.StatusNotFound, utility.FS_NOT_FOUND, errRsp } if bind.PlatForm != platform || (platform == entity.BINGING_PLATFORM_ORGAN && bind.PlatForm != toBind.PlatForm) || (platform == entity.BINGING_PLATFORM_OPER && (bind.PlatForm != toBind.PlatForm || bind.GroupID != "" || toBind.GroupID != "")) { log.Errorf("MoveBundles source platform:%d to platform:%d handle platform:%d", bind.PlatForm, toBind.PlatForm, platform) return http.StatusBadRequest, utility.FC_MOVE_BINDING_NO_AUTH, errRsp } if len(req.BundlesInfo) <= 0 { return http.StatusBadRequest, utility.FC_LACK_OF_BUNDLE_ERR, nil } num := 0 for _, v := range toBind.BundleInfos { if v.IsForbidden == 0 { num++ } } if num >= config.GetConfig().AddAvailableBundleNum { return http.StatusBadRequest, utility.FS_BUNDLE_AVAILABLE_NUM_LIMIT, nil } if len(toBind.BundleInfos) >= config.GetConfig().AddALLBundleNum { return http.StatusBadRequest, utility.FS_BUNDLE_ALL_NUM_LIMIT, nil } // 确认来源binding sourceBind, err := s.bindRepo.GetBundleByGroupIdAndBundleId(ctx, bind.GroupID, req.BundlesInfo[0].BundleId) if err != nil && !s.NotFound(err) { log.Errorf("MoveBundles get bundle err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } if sourceBind.BindingID != bind.BindingID { log.Errorf("MoveBundles bind:%s exsit other bind:%s has same bundle", bind.BindingID, sourceBind.BindingID) return http.StatusBadRequest, utility.FS_APP_BUNDLEID_REPEAT, nil } sourceBundle := entity.BundleInfo{} for _, bundle := range sourceBind.BundleInfos { if bundle.BundleID == req.BundlesInfo[0].BundleId { sourceBundle = bundle break } } // 将bundle的源bindingId改为目标bindingId err = s.bindRepo.UpdateBundleBindingId(ctx, req.BundlesInfo[0].BundleId, bind.BindingID, toBind.BindingID) if err != nil { log.Errorf("MoveBundles UpdateBundleBindingId err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } //由于bundleId移动,应用数据发生变化,需更新小程序搜索数据 //if config.Cfg.PublishEnv == entity.ENV_UAT { //根据bundleId获取sdkkey reqBundleSdkkey := "" for _, v := range sourceBind.BundleInfos { if v.BundleID == req.BundlesInfo[0].BundleId { reqBundleSdkkey = v.SDKKey break } } notifyInfo := httpcall.UpdateForbiddenSdkKeys{} //小程序搜索数据中删除原应用绑定的appid中所移动的sdkkey for _, v := range sourceBind.AppInfos { removeItem := httpcall.SdkKeyUpdate{} removeItem.AppId = v.AppID removeItem.SdkKey = reqBundleSdkkey notifyInfo.RemoveSdkKeys = append(notifyInfo.RemoveSdkKeys, removeItem) } //2 to 小程序数据中添加现应用绑定的appid中所移动的sdkkey moveToBind, err := s.bindRepo.GetInfo(ctx, req.ToBindingID) if err != nil && !s.NotFound(err) { log.Errorf("MoveBundles get bindingId:%s binding info err:%s", req.ToBindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } for _, v := range moveToBind.AppInfos { addItem := httpcall.SdkKeyUpdate{} addItem.AppId = v.AppID addItem.SdkKey = reqBundleSdkkey notifyInfo.AddSdkKeys = append(notifyInfo.AddSdkKeys, addItem) } hCaller.UpdateBundleForbiddenInfo(ctx, ¬ifyInfo) //} //企业端更改结束 if platform == entity.BINGING_PLATFORM_ORGAN { return http.StatusOK, utility.OK, nil } // 如果是运营端移动,还需要对复制的应用进行移动操作 // 没复制,说明源应用下的bundle在没复制的企业下已经有其他应用包括源应用的所有bundleId,则不用处理 _, sourceBinds, err := s.bindRepo.ListCopyOperBinding(ctx, bind.BindingID) if err != nil { log.Errorf("MoveBundles List sourceBinds CopyOperBinding err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } _, toBinds, err := s.bindRepo.ListCopyOperBinding(ctx, toBind.BindingID) if err != nil { log.Errorf("MoveBundles List toBinds CopyOperBinding err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } organMap := make(map[string]string) for _, item := range toBinds { organMap[item.GroupID] = item.BindingID } for _, item := range sourceBinds { //如果当前企业存在目标应用,则直接更改bundle的bindingId if v, ok := organMap[item.GroupID]; ok { err = s.bindRepo.UpdateBundleBindingId(ctx, req.BundlesInfo[0].BundleId, item.BindingID, v) // 如果源应用下不存在此bundle,说明当前企业在其他企业端应用下有此bundle信息,则不用处理 if err != nil && !s.bindRepo.NotFound(err) { log.Errorf("MoveBundles UpdateBundleBindingId err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } } else { //当前企业没有复制目标应用,即目标应用在复制时,所有bundleId已经在企业端应用下有 //如果这个新移动的bundleID在企业端应用下有,即企业端创建的应用下有此bundle,则不做处理 targetBind, err := s.bindRepo.GetBundleByGroupIdAndBundleId(ctx, item.GroupID, req.BundlesInfo[0].BundleId) if err != nil { // 不存在,则已此bundleId复制应用 if s.bindRepo.NotFound(err) { copyBind := &entity.Binding{} copier.Copy(©Bind, &toBind) copyBind.BindingID = bson.NewObjectId().Hex() copyBind.FromBindingID = toBind.BindingID copyBind.GroupID = item.GroupID copyBind.GroupName = item.GroupName accountInfo := &httpcall.AccountInfoData{Account: copyBind.CreatedInfo.CreatedAccount} if copyBind.AutoBind == entity.BINGING_AUTO_BIND { s.operAutoAppBind(ctx, copyBind, accountInfo) } copyBind.BundleInfos = []entity.BundleInfo{sourceBundle} err = s.bindRepo.Insert(ctx, copyBind) if err != nil { log.Errorf("MoveBundles insert groupId:%s groupName:%s copybind err:%s", item.GroupID, item.GroupName, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } else { log.Infof("MoveBundles insert groupId:%s groupName:%s copybind origin binding:%s succ", item.GroupID, item.GroupName, bind.BindingID) } } else { log.Errorf("MoveBundles GetBundleByGroupIdAndBundleId err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, nil } } else { //存在,则不做处理 log.Infof("groupId:%s bundleId:%s has exsit in other binding:%s", item.GroupID, req.BundlesInfo[0].BundleId, targetBind.BindingID) } } } return http.StatusOK, utility.OK, nil } func (s BindingService) UpdateBundles(ctx context.Context, bindingId, groupId string, bundleReqs []apiproto.CreateBundleReq) (string, interface{}) { licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("BindBundles get license err:%s", err.Error()) return utility.FS_SYSTEM_CALL, nil } num := 0 for _, v := range bundleReqs { if v.IsForbidden == 0 { num++ } } if num > config.GetConfig().AddAvailableBundleNum { return utility.FS_BUNDLE_AVAILABLE_NUM_LIMIT, nil } if len(bundleReqs) > config.GetConfig().AddALLBundleNum { return utility.FS_BUNDLE_ALL_NUM_LIMIT, nil } //repo := impl.InitBindingRepo() bundleCount, err := s.bindRepo.BundleIdCount(ctx, "") if err != nil { log.Errorf("BindBundles bundle count err:%s", err.Error()) return utility.FS_DB_ERR, nil } //数量只校验bundleReqs中,isForbidden为0(未禁用) lenCount := 0 updateBundles := make([]entity.BundleInfo, 0) for _, v := range bundleReqs { item := entity.BundleInfo{} if v.IsForbidden == 0 { lenCount++ } item.BundleID = v.BundleId item.Remark = v.Platform item.IsForbidden = v.IsForbidden item.CreatedBy = v.CreatedBy item.CreatedAccount = v.CreatedAccount item.CreatedAt = v.CreatedAt item.IsFirstCreate = v.IsFirstCreate item.SDKID = v.SDKID item.SDKKey = v.SDKKey item.IsReview = v.IsReview updateBundles = append(updateBundles, item) if config.Cfg.PublishEnv != entity.ENV_PRIVATE && config.Cfg.PublishEnv != entity.ENV_COMMUNITY { if v.IsForbidden == 0 { if licenseInfo.BundleIdCount < bundleCount+lenCount { log.Errorf("BindBundles over limit,license info:%+v,bundle id count:%d", licenseInfo, bundleCount) return utility.FS_BUNDLE_ID_COUNT_OVER_TO_WEB_ERR, nil } } } } /*statusCode, appendBundles := s.handleBundles(ctx, groupId, accountInfo, bundleReqs, licenseInfo.IsConfiguration, operationType) if statusCode != utility.OK { return statusCode, nil }*/ /*binding, err := s.bindRepo.GetBindingByGroupIdAndBindingId(ctx, groupId, bindingId) if err != nil { log.Errorln(fmt.Sprintf("GetOne err: %s", err)) return utility.FS_DB_ERR, nil }*/ /*if len(binding.BundleInfos) > 1 { return utility.FS_BIND_BUNDLE_LIMIT, nil }*/ //binding.BundleInfos = append(binding.BundleInfos, bundles...) err = s.bindRepo.UpdateBundles(ctx, bindingId, groupId, updateBundles) //binding.BundleInfos = append(binding.BundleInfos, appendBundles...) //binding.BundleInfos = binding.BundleInfos //err = s.bindRepo.UpdateBundleInfosByGroupIdAndBindId(ctx, groupId, bindingId, binding.BundleInfos) if err != nil { if err.Error() == utility.FS_BIND_IS_FORBIDDEN { log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return utility.FS_BIND_IS_FORBIDDEN, nil } else { log.Errorln(fmt.Sprintf("UpdateOne err: %s", err)) return utility.FS_DB_ERR, nil } } bind, err := s.bindRepo.GetInfo(ctx, bindingId) if err != nil && !s.bindRepo.NotFound(err) { log.Errorf("UpdateBinding get binding info err:%s", err.Error()) return utility.FS_DB_ERR, nil } appIds := []string{} for _, v := range bind.AppInfos { appIds = append(appIds, v.AppID) } notifyInfo := httpcall.UpdateForbiddenSdkKeys{} //if config.Cfg.PublishEnv == entity.ENV_UAT { for _, appInfo := range bind.AppInfos { for _, v := range bind.BundleInfos { if v.IsForbidden == 1 { removeItem := httpcall.SdkKeyUpdate{} removeItem.AppId = appInfo.AppID removeItem.SdkKey = v.SDKKey notifyInfo.RemoveSdkKeys = append(notifyInfo.RemoveSdkKeys, removeItem) } else { addItem := httpcall.SdkKeyUpdate{} addItem.AppId = appInfo.AppID addItem.SdkKey = v.SDKKey notifyInfo.AddSdkKeys = append(notifyInfo.AddSdkKeys, addItem) } } } hCaller.UpdateBundleForbiddenInfo(ctx, ¬ifyInfo) //} return utility.OK, nil } func (s BindingService) NotFound(err error) bool { return s.bindRepo.NotFound(err) } func (s BindingService) recooperate(c *gin.Context, req *apiproto.BindingUpdateRequest, bind *entity.Binding, developerID string, account string, isAdmin bool) (int, string, interface{}) { traceCtx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) if bind.CooperateStatus.Value != entity.StBindInvalid { log.Errorf("bind cooperate status Invalid,bind id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_INVALID_COOPERATE_STATUS, errRsp } timestamp := time.Now().UnixNano() / 1000000 bind.CooperateStatus = entity.Status{ Value: entity.StBindValid, LastUpdated: timestamp, ModifiedBy: account, } bind.CooperateValidStatus = entity.SpecificStatus{ LastUpdated: timestamp, ModifiedBy: account, } licenseInfo, err := hCaller.GetLicense(traceCtx) if err != nil { log.Errorf("GetBundleIdLimitHand get err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_LICENSE_SERVER_ERROR, errRsp } httpCode, errCode, err := s.BindingLicenseCheck(traceCtx, licenseInfo, nil, isAdmin) if err != nil { return httpCode, errCode, errRsp } //调用支付系统进行权限校验 if config.GetConfig().OpenPurchAuth && config.GetConfig().PublishEnv == entity.ENV_UAT { applyReq := httpcall.PayAddLimitReq{} applyReq.Type = httpcall.PAY_ADD_TYPE_BINDING applyReq.AccountId = developerID applyReq.BusinessId = bind.BindingID applyReq.BusinessName = bind.Name payAddRsp, httpCode, err := hCaller.PayAddLimit(traceCtx, &applyReq) if err != nil { return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRsp } if httpCode != http.StatusOK { return httpCode, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, errRsp } if payAddRsp.Data.EndTime == 0 { payAddRsp.Data.EndTime = MAX_EXPIRE_DATA } bind.Expire = payAddRsp.Data.EndTime } else { if !isAdmin { n := httpcall.AddLimitInfoReq{ Type: "binding", OrganId: bind.GroupID, AddNum: 1, } _, _, err := hCaller.AddLimitInfo(traceCtx, &n) if err != nil { log.Errorf("Failed to AddLimitInfo: %v\n", err) return http.StatusBadRequest, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, errRsp } } } err = s.UpdateByBindId(traceCtx, req.BindingID, bind) if err != nil { log.Errorf("bind update err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } if isAdmin { s.updateRelateRecooperate(traceCtx, bind) } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, bind.GroupID, kafka.GenContent(kafka.BIND_RECOVE_COOP_LOG, bind.Name), logExp, account) return http.StatusOK, utility.OK, nil } func (s BindingService) updateRelateRecooperate(ctx context.Context, bind *entity.Binding) error { repo := impl.InitBindingRepo() return repo.UpdateRelatedBindingCooperate(ctx, bind.BindingID, bind.CooperateStatus, bind.CooperateValidStatus, true) } func (s BindingService) updateRelateDiscooperate(ctx context.Context, bind *entity.Binding) error { repo := impl.InitBindingRepo() return repo.UpdateRelatedBindingCooperate(ctx, bind.BindingID, bind.CooperateStatus, bind.CooperateInvalidStatus, false) } func (s BindingService) discooperate(c *gin.Context, req *apiproto.BindingUpdateRequest, bind *entity.Binding, developerID string, account string, isAdmin bool) (int, string, interface{}) { traceCtx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) if bind.CooperateStatus.Value != entity.StBindValid { log.Errorf("discooperate bind CooperateStatus invalid,bind id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_INVALID_COOPERATE_STATUS, errRsp } timestamp := time.Now().UnixNano() / 1000000 bind.CooperateStatus = entity.Status{ Value: entity.StBindInvalid, LastUpdated: timestamp, ModifiedBy: account, } bind.CooperateInvalidStatus = entity.SpecificStatus{ LastUpdated: timestamp, ModifiedBy: account, } //调用支付系统进行权限校验 if config.GetConfig().OpenPurchAuth && config.GetConfig().PublishEnv == entity.ENV_UAT { applyReq := httpcall.PayAddLimitReq{} applyReq.Type = httpcall.PAY_ADD_TYPE_BINDING applyReq.AccountId = developerID applyReq.BusinessId = bind.BindingID applyReq.BusinessName = bind.Name _, httpCode, err := hCaller.PayUpdateLimit(traceCtx, &applyReq) if err != nil { return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRsp } if httpCode != http.StatusOK { return httpCode, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, errRsp } } else { if !isAdmin { n := httpcall.AddLimitInfoReq{ Type: "binding", OrganId: bind.GroupID, AddNum: -1, } _, _, err := hCaller.AddLimitInfo(traceCtx, &n) if err != nil { log.Errorf("Failed to notify: %v\n", err) return http.StatusBadRequest, utility.FC_OPERA_LIMIT_BIND_OVER_ERROR, errRsp } } } err := s.UpdateByBindId(traceCtx, req.BindingID, bind) if err != nil { log.Errorf("discooperate update err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } if isAdmin { s.updateRelateDiscooperate(traceCtx, bind) } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, bind.GroupID, kafka.GenContent(kafka.BIND_STOP_COOP_LOG, bind.Name), logExp, account) //更新小程序详情缓存 //rs := service.NewRuntimeService() //rs.Discooperate(traceCtx, req.BindingID) ////更新小程序版本详情缓存 //appVerSvr := service.NewAppVerService() //appVerSvr.BindCancelCoop(traceCtx, req.BindingID) //model.NewAsyncMessageRepo().GenAppStatusChangeInfo(traceCtx, model.AppStatusChangeInfo{Event: model.BindingCancelCoopreate, Info: map[string]interface{}{"bindingId": bind.BindingID}}) return http.StatusOK, utility.OK, nil } func (s BindingService) AdminReviewBundleList(ctx context.Context, c *gin.Context, req *apiproto.ListReviewBundleReq) (int, string, interface{}) { rsp := make(map[string]interface{}) total, list, err := s.bindRepo.ListReviewBundle(ctx, req.PageSize, req.PageNo, req.SearchText, req.Type) if err != nil { return http.StatusInternalServerError, utility.FS_DB_ERR, rsp } rsp["total"] = total rsp["list"] = list return http.StatusOK, utility.OK, rsp } func (s BindingService) UpdateReviewBundle(ctx context.Context, c *gin.Context, req *apiproto.UpdateReviewBundleReq) (int, string, interface{}) { rsp := make(map[string]interface{}) switch req.Operation { case entity.OpBindingReviewAdd: err := s.bindRepo.UpdateBundleIsView(ctx, req.Reviews, 1) if err != nil { return http.StatusInternalServerError, utility.FS_DB_ERR, rsp } case entity.OpBindingReviewRemove: err := s.bindRepo.UpdateBundleIsView(ctx, req.Reviews, 0) if err != nil { return http.StatusInternalServerError, utility.FS_DB_ERR, rsp } default: return http.StatusBadRequest, utility.FS_OPER_HANDLE_ERR, rsp } return http.StatusOK, utility.OK, rsp } func (s BindingService) AdminBindingUpdate(ctx context.Context, c *gin.Context, req *apiproto.BindingUpdateRequest) (int, string, interface{}) { traceCtx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) //bind := entity.Binding{} repo := impl.InitBindingRepo() bind, err := repo.GetInfo(ctx, req.BindingID) if err != nil && !s.NotFound(err) { log.Errorf("BindingUpdate get binding info err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } if repo.NotFound(err) { log.Errorf("BindingUpdate get binding info err:%s", "NOT FOUND ID") return http.StatusNotFound, utility.FS_NOT_FOUND, errRsp } developerID := c.Request.Header.Get("X-Consumer-Custom-ID") accountInfo, err := hCaller.GetAdminAccountInfo(ctx, developerID) if err != nil { log.Errorf("UpdateBinding get account info err:%s", err.Error()) return http.StatusBadRequest, utility.FS_MANAGE_APP_NO_AUTH, errRsp } switch req.Operation { case entity.OpBindingRecooperate: return s.recooperate(c, req, bind, developerID, accountInfo.Account, true) case entity.OpBindingDiscooperate: return s.discooperate(c, req, bind, developerID, accountInfo.Account, true) case entity.OpBindingModifyName: return s.modifyBindingName(c, req, bind, developerID, accountInfo.Account, true) case entity.OpBindingAutoBind, entity.OpBindingHiddenBundle: return s.updateBindingInfo(c, req, bind, developerID, accountInfo.Account, true) case entity.OpBindBundle: accountInfoData := &httpcall.AccountInfoData{ Account: accountInfo.Account, Name: accountInfo.Name, } return s.AdminBindBundles(traceCtx, "", accountInfoData, req.BundlesInfo, bind, false) case entity.OpUpdateBundle: return s.AdminUpdateBundles(traceCtx, bind, "", req.BundlesInfo) case entity.OpBindingDisassociate: if req.Reason == "" { log.Errorf("AdminUpdateBinding OpBindingDisassociate reason empty !!!") return http.StatusBadRequest, utility.FS_PARAM_ERR, errRsp } return s.disassociate(traceCtx, bind, req) case entity.OpMoveBundle: if req.ToBindingID == "" { log.Errorf("UpdateBinding to binding id empty !!!") return http.StatusBadRequest, utility.FC_LACK_OF_TO_BINDING_ID, errRsp } if req.BindingID == req.ToBindingID { log.Errorf("UpdateBinding binding id:%s equal to binding id:%s", req.BindingID, req.ToBindingID) return http.StatusBadRequest, utility.FC_BINDING_ID_EQUAL_TO_INDING_ID, errRsp } return s.MoveBundles(traceCtx, bind, req, entity.BINGING_PLATFORM_OPER) default: return http.StatusBadRequest, utility.FS_OPER_HANDLE_ERR, errRsp } } func (s BindingService) adminDisassociate(c *gin.Context, appIds []string, bind *entity.Binding, account string) (int, string, interface{}) { ctx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) if bind.CooperateStatus.Value != entity.StBindValid { log.Errorf("disassociate bind CooperateStatus invalid,bind id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_INVALID_COOPERATE_STATUS, errRsp } removeApps := []string{} //产品要求,加一个校验,已经取消关联的,不可重复取消 for _, id := range appIds { found := false for _, info := range bind.AppInfos { if id == info.AppID { found = true } } if !found { log.Errorf("disassociate repeat,binding id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_APP_NOT_ASSOCIATED, errRsp } removeApps = append(removeApps, id) } err := s.bindRepo.RemoveApps(ctx, bind.BindingID, removeApps) if err != nil { log.Errorf("disassociate update err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } //这里做个上报 appSvr := NewAppService() logAppMap := make(map[string]string) for _, appId := range appIds { app, err := appSvr.GetAppInfoByAppId(ctx, appId) if err != nil { log.Errorf("GetAppInfoByAppId err:%s", err.Error()) continue } logAppMap[appId] = app.Name } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, bind.GroupID, kafka.GenContentAssApp(kafka.BIND_CANCEL_ASS_APP_LOG, bind.Name, logAppMap), logExp, account) ////更新运行时获取小程序缓存 //rs := service.NewRuntimeService() //rs.Disassociate(traceCtx, bind.BindingID, appIds) ////更新小程序版本详情缓存 //appVerSvr := service.NewAppVerService() //appVerSvr.BindDisAssApp(traceCtx, bind.BindingID, appIds) //model.NewAsyncMessageRepo().GenAppStatusChangeInfo(traceCtx, model.AppStatusChangeInfo{Event: model.BindingDisassApps, Info: map[string]interface{}{"bindingId": bind.BindingID, "appIds": appIds}}) return http.StatusOK, utility.OK, nil } func (s BindingService) getMergeBundle(ctx context.Context, bundleInfos []entity.BundleInfo, groupID string) ([]entity.BundleInfo, error) { list, _, err := s.bindRepo.GetDevListBinding(ctx, 10000, 1, "", "", "", groupID, "", entity.BINGING_PLATFORM_ORGAN) if err != nil { log.Errorf("get organ binding list err:%s", err.Error()) return nil, err } exsitBundle := make(map[string]bool) for _, item := range list { for _, bundle := range item.BundleInfos { exsitBundle[bundle.BundleID] = true } } appendBundle := []entity.BundleInfo{} for _, bundle := range bundleInfos { if _, ok := exsitBundle[bundle.BundleID]; !ok { appendBundle = append(appendBundle, bundle) } } return appendBundle, nil } func (s BindingService) AdminBindBundles(ctx context.Context, groupId string, accountInfo *httpcall.AccountInfoData, bundleReqs []apiproto.CreateBundleReq, binding *entity.Binding, isCreateBinding bool) (int, string, interface{}) { errRsp := make(map[string]interface{}) // 先修改运营端自身 statusCode, _ := s.BindBundles(ctx, binding.BindingID, groupId, accountInfo, bundleReqs, binding, isCreateBinding) if statusCode != utility.OK { return http.StatusBadRequest, statusCode, errRsp } // 再修改从运营端复制的 bindingIds, _, err := s.bindRepo.ListCopyOperBinding(ctx, binding.BindingID) if err != nil { log.Errorf("AdminBindBundles ListCopyOperBinding bindingID:%s err:%s", binding.BindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } bindList, err := s.bindRepo.GetByBindIdList(ctx, bindingIds) if err != nil { log.Errorf("AdminBindBundles GetByBindIdList bindingID:%s err:%s", binding.BindingID, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } hasCopyedOrgans, notCopyedOrgans := make(map[string]entity.Binding), make(map[string]*httpcall.OrganListItem) for _, item := range bindList { hasCopyedOrgans[item.GroupID] = item } list, err := hCaller.GetOrganList(ctx) if err != nil { log.Errorf("AdminBindBundles get organ list err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRsp } for _, item := range list { if _, ok := hasCopyedOrgans[item.OrganId]; !ok { notCopyedOrgans[item.OrganId] = item } } licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("BindBundles get license err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRsp } // 以前复制了的企业端 for _, v := range hasCopyedOrgans { statusCode, appendBundles := s.handleBundles(ctx, v.GroupID, accountInfo, bundleReqs, licenseInfo, true) if statusCode != utility.OK { return http.StatusInternalServerError, statusCode, errRsp } if len(appendBundles) <= 0 { continue } err = s.bindRepo.AppendBundles(ctx, v.BindingID, v.GroupID, appendBundles) if err != nil { log.Errorf("AdminBindBundles AppendBundles err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } } // 以前没有复制的企业端 for _, v := range notCopyedOrgans { statusCode, appendBundles := s.handleBundles(ctx, v.OrganId, accountInfo, bundleReqs, licenseInfo, true) if statusCode != utility.OK { return http.StatusInternalServerError, statusCode, errRsp } if len(appendBundles) <= 0 { continue } // 这次新加的bundle需要创建新的合作应用 copyBind := &entity.Binding{} copier.Copy(©Bind, &binding) copyBind.BindingID = bson.NewObjectId().Hex() copyBind.FromBindingID = binding.BindingID copyBind.GroupID = v.OrganId copyBind.GroupName = v.Name copyBind.BundleInfos = appendBundles if copyBind.AutoBind == entity.BINGING_AUTO_BIND { s.operAutoAppBind(ctx, copyBind, accountInfo) } err = s.bindRepo.Insert(ctx, copyBind) if err != nil { log.Errorf("AdminBindBundles copy new insert groupId:%s groupName:%s copybind err:%s", v.OrganId, v.Name, err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } } return http.StatusOK, utility.OK, nil } func (s BindingService) updateBindingInfo(c *gin.Context, req *apiproto.BindingUpdateRequest, bind *entity.Binding, developerID string, account string, isAdmin bool) (int, string, interface{}) { traceCtx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) platform := entity.BINGING_PLATFORM_ORGAN if isAdmin { platform = entity.BINGING_PLATFORM_OPER } repo := impl.InitBindingRepo() switch req.Operation { case entity.OpBindingAutoBind: _, ok := gAutoBindMap.Load(req.BindingID) if ok { return http.StatusBadRequest, utility.FS_OPER_AUTO_BIND_DOING_ERR, errRsp } gAutoBindMap.Store(req.BindingID, true) if req.AutoBind == 1 { bindingIds, _, err := repo.ListCopyOperBinding(traceCtx, req.BindingID) if err != nil { log.Errorf("OpBindingAutoBind ListCopyOperBinding err:%s", err.Error()) gAutoBindMap.Delete(req.BindingID) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } bindings, err := repo.GetByBindIdList(traceCtx, bindingIds) if err != nil { log.Errorf("OpBindingAutoBind GetByBindIdList err:%s", err.Error()) gAutoBindMap.Delete(req.BindingID) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } for _, binding := range bindings { s.operAutoMergeAppBind(traceCtx, &binding, account) } } err := repo.UpdateBindingInfo(traceCtx, req.BindingID, map[string]interface{}{ "auto_bind": req.AutoBind, }, platform) if err != nil { log.Errorf("OpBindingAutoBind UpdateBindingInfo err:%s", err.Error()) gAutoBindMap.Delete(req.BindingID) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } gAutoBindMap.Delete(req.BindingID) return http.StatusOK, utility.OK, nil case entity.OpBindingHiddenBundle: err := repo.UpdateBindingInfo(traceCtx, req.BindingID, map[string]interface{}{ "hidden_bundle": req.HiddenBundle, }, platform) if err != nil { log.Errorf("OpBindingHiddenBundle update binding err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } return http.StatusOK, utility.OK, nil } return http.StatusOK, utility.OK, nil } func (s BindingService) modifyBindingName(c *gin.Context, req *apiproto.BindingUpdateRequest, bind *entity.Binding, developerID string, account string, isAdmin bool) (int, string, interface{}) { traceCtx := apm.ApmClient().TraceContextFromGin(c) errRsp := make(map[string]interface{}) if bind.CooperateStatus.Value != entity.StBindValid { log.Errorf("modifyBindingName bind CooperateStatus invalid,bind id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_INVALID_COOPERATE_STATUS, errRsp } groupInfo := &httpcall.GroupIDData{} var err error if !isAdmin { //上报用 groupInfo, err = hCaller.GetGroupInfoByUserId(traceCtx, developerID) if err != nil || groupInfo == nil || groupInfo.GroupID == "" { log.Errorf("modifyBindingName get group info err:%+v", err) return http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED, errRsp } } result, err := s.GetBindingByGroupIdAndName(traceCtx, groupInfo.GroupID, req.AppName, isAdmin) if err != nil && !s.NotFound(err) { log.Errorf("modifyBindingName get info err:%+v", err) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } if !s.NotFound(err) && result.BindingID != req.BindingID { log.Errorf("modifyBindingName found binding !!!") return http.StatusInternalServerError, utility.FS_BINDING_NAME_REPEAT, errRsp } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, groupInfo.GroupID, kafka.GenContent(kafka.BIND_UP_LOG, bind.Name, req.AppName), logExp, account) /*bind.Name = req.AppName bind.Owner = req.Owner err = s.UpdateByBindId(traceCtx, req.BindingID, bind) if err != nil { log.Errorf("modifyBindingName up binding err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp }*/ platform := entity.BINGING_PLATFORM_ORGAN if isAdmin { platform = entity.BINGING_PLATFORM_OPER } repo := impl.InitBindingRepo() err = repo.UpdateBindingInfo(traceCtx, req.BindingID, map[string]interface{}{ "name": req.AppName, "owner": req.Owner, }, platform) if err != nil { log.Errorf("modifyBindingName up binding err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } return http.StatusOK, utility.OK, nil } func (s *BindingService) AdminNotifySdkKey(ctx context.Context, appIds []string, bind *entity.Binding, bindType string) { notifys := &httpcall.NotifySpiderUpdate{Type: bindType} for _, info := range bind.BundleInfos { //if info.IsForbidden == 0 { for _, appID := range appIds { notifys.SdkKeys = append(notifys.SdkKeys, httpcall.SdkKeyUpdate{AppId: appID, SdkKey: info.SDKKey}) } //} } _, err := hCaller.Notify(ctx, notifys) if err != nil { log.Errorf("notfiy spider updates:%+v err:%s", notifys, err.Error()) } return } func (s *BindingService) disassociate(ctx context.Context, bind *entity.Binding, req *apiproto.BindingUpdateRequest) (int, string, interface{}) { errRsp := make(map[string]interface{}) if bind.CooperateStatus.Value != entity.StBindValid { log.Errorf("disassociate bind CooperateStatus invalid,bind id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_INVALID_COOPERATE_STATUS, errRsp } //产品要求,加一个校验,已经取消关联的,不可重复取消 removeApps := []string{} for _, id := range req.AppIDs { found := false for _, info := range bind.AppInfos { if id == info.AppID { found = true } } if !found { log.Errorf("disassociate not binding id:%s", bind.BindingID) return http.StatusBadRequest, utility.FS_APP_NOT_ASSOCIATED, errRsp } removeApps = append(removeApps, id) } err := s.bindRepo.RemoveApps(ctx, bind.BindingID, removeApps) if err != nil { log.Errorf("disassociate update err:%s", err.Error()) return http.StatusInternalServerError, utility.FS_DB_ERR, errRsp } // 临时注释app //apps := make([]entity.App, 0) //appT := db.NewTable(db.TableApp) logAppMap := make(map[string]string) //filter := bson.M{"appId": bson.M{"$in": req.AppIds}} //_, err := appT.GetAll(ctx, filter, []string{}, &apps) //if err != nil { // log.Errorf("disassociate get log man err:%s", err.Error()) // return http.StatusInternalServerError, common.FS_DB_ERR, errRsp //} //for _, appInfo := range apps { // logAppMap[appInfo.AppID] = appInfo.Name //} notifyContent := kafka.NotifyContent{} notifyContent.Title = "【重要】小程序关联应用被取消" notifyContent.Result = "fail" notifyContent.Msg = fmt.Sprintf("与 %s 关联的 %s(App ID:%s )被运营端取消关联,"+ "该应用上的小程序服务将不可用。但其他应用上的该小程序服务仍将正常运行。取消关联说明为:%s", bind.Name, logAppMap[req.AppIDs[0]], req.AppIDs[0], req.Reason) notifyContent.Reason = req.Reason go kafka.GenNotifyData(ctx, bind.GroupID, 1001, notifyContent) //更新缓存 //rs := NewRuntimeService() //rs.Disassociate(ctx, req.BindingId, req.AppIds) ////更新小程序版本详情缓存 //appVerSvr := NewAppVerService() //appVerSvr.BindDisAssApp(ctx, req.BindingId, req.AppIds) //model.NewAsyncMessageRepo().GenAppStatusChangeInfo(ctx, model.AppStatusChangeInfo{Event: model.BindingCancelCoopreate, Info: map[string]interface{}{"bindingId": bind.BindingID, "appIds": req.AppIds}}) return http.StatusOK, utility.OK, errRsp } func (s BindingService) GetBindingsByIds(ctx context.Context, ids []string) ([]entity.Binding, error) { repo := impl.InitBindingRepo() result, err := repo.GetByBindIdList(ctx, ids) if err != nil { return nil, err } return result, nil } func (s BindingService) GetBindingByGroupId(ctx context.Context, groupId string, pageSize int, pageNo int) ([]entity.Binding, int, error) { return s.bindRepo.GetBindListByGroupId(ctx, groupId, pageSize, pageNo) } func (s BindingService) GetAssBindsByAppId(ctx context.Context, appId string) ([]entity.Binding, error) { return s.bindRepo.GetAllAssBinds(ctx, appId) } type ListBindingListRsp struct { Total int `json:"total"` List []DevListBindingListItem `json:"list"` } type DevListBindingListItem struct { BindingID string `json:"bindingId"` Name string `json:"name"` GroupName string `json:"groupName"` //企业名称(为了查询) AppInfos []entity.AppInfo `json:"appInfos"` BundleInfos []entity.BundleInfo `json:"bundleInfos"` CreatedInfo entity.CreatedInfo `json:"createdInfo"` //创建信息 GroupID string `json:"groupId"` CooperateStatus entity.Status `json:"cooperateStatus"` //合作状态 CooperateValidStatus entity.SpecificStatus `json:"cooperateValidStatus"` //合作状态详情 CooperateInvalidStatus entity.SpecificStatus `json:"cooperateInvalidStatus"` //解除合作状态详情 Owner string `json:"owner"` //所属企业 Expire int64 `json:"expire"` ApiServer string `json:"apiServer"` ApmServer string `json:"apmServer"` PlatForm int `json:"platform" bson:"platform"` //来源平台 AutoBind int `json:"autoBind" bson:"autoBind"` //自动关联小程序 HiddenBundle int `json:"hiddenBundle" bson:"hiddenBundle"` //隐藏bundle信息 FromBindingID string `json:"fromBindingId" bson:"fromBindingId"` //来源ID } func (s BindingService) ListBinding(c *gin.Context, ctx context.Context, req apiproto.ListBindingsReq) { var rspData ListBindingListRsp repo := impl.InitBindingRepo() bindList, total, err := repo.GetBindingsBySearch(ctx, req.PageSize, req.PageNo, req.Sort, req.SearchText, req.SearchFields, req.CooperateStatus, req.Platform) if err != nil { log.Errorf("BindingService DevListBindingList db err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_DB_ERR, rspData) return } rspData.Total = total rspData.List = []DevListBindingListItem{} for _, v := range bindList { item := DevListBindingListItem{ BindingID: v.BindingID, Name: v.Name, GroupName: v.GroupName, Owner: v.Owner, AppInfos: v.AppInfos, CreatedInfo: v.CreatedInfo, GroupID: v.GroupID, BundleInfos: v.BundleInfos, CooperateStatus: v.CooperateStatus, CooperateValidStatus: v.CooperateValidStatus, CooperateInvalidStatus: v.CooperateInvalidStatus, Expire: v.Expire, ApiServer: v.ApiServer, ApmServer: config.Cfg.ApmServer, PlatForm: v.PlatForm, AutoBind: v.AutoBind, HiddenBundle: v.HiddenBundle, FromBindingID: v.FromBindingID, } if item.ApiServer == "" { item.ApiServer = config.Cfg.ApiServer } rspData.List = append(rspData.List, item) } utility.MakeLocRsp(c, http.StatusOK, utility.OK, rspData) return } func (s BindingService) GetBindingsByAppId(c *gin.Context, ctx context.Context, req apiproto.GetBindingsByAppIdReq) { var rspData ListBindingListRsp repo := impl.InitBindingRepo() bindList, total, err := repo.GetBindingsByAppId(ctx, req.PageSize, req.PageNo, req.AppId) if err != nil { log.Errorf("BindingService DevListBindingList db err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_DB_ERR, rspData) return } rspData.Total = total for _, v := range bindList { item := DevListBindingListItem{ BindingID: v.BindingID, Name: v.Name, GroupName: v.GroupName, Owner: v.Owner, AppInfos: v.AppInfos, CreatedInfo: v.CreatedInfo, GroupID: v.GroupID, BundleInfos: v.BundleInfos, CooperateStatus: v.CooperateStatus, CooperateValidStatus: v.CooperateValidStatus, CooperateInvalidStatus: v.CooperateInvalidStatus, Expire: v.Expire, ApiServer: v.ApiServer, ApmServer: config.Cfg.ApmServer, } if item.ApiServer == "" { item.ApiServer = config.Cfg.ApiServer } rspData.List = append(rspData.List, item) } utility.MakeLocRsp(c, http.StatusOK, utility.OK, rspData) return } type DevListBindingListRsp struct { Total int `json:"total"` List []DevListBindingListItem `json:"list"` } func (s BindingService) DevListBinding(c *gin.Context, ctx context.Context, req *apiproto.DevListBindingReq) { errRspData := make(map[string]interface{}) groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, req.UserId) if err != nil { log.Errorf("BindingService DevListBinding get group id by user id err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRspData) return } bindList, total, err := s.bindRepo.GetDevListBinding(ctx, req.PageSize, req.PageNo, req.SortType, req.SearchTxt, req.PullType, groupInfo.GroupID, req.BindStatus, req.Platform) if err != nil { log.Errorf("DevListBinding GetDevListBinding err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_DB_ERR, errRspData) } licenseInfo, err := hCaller.GetLicense(ctx) if err != nil && config.Cfg.PublishEnv != entity.ENV_UAT { log.Errorf("AppService DevListApps get license info err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_SYSTEM_CALL, errRspData) return } succRspData := DevListBindingListRsp{Total: total, List: make([]DevListBindingListItem, 0)} for _, v := range bindList { item := DevListBindingListItem{ BindingID: v.BindingID, Name: v.Name, GroupName: v.GroupName, Owner: v.Owner, AppInfos: v.AppInfos, BundleInfos: v.BundleInfos, CooperateStatus: v.CooperateStatus, CooperateValidStatus: v.CooperateValidStatus, CooperateInvalidStatus: v.CooperateInvalidStatus, Expire: v.Expire, ApiServer: v.ApiServer, ApmServer: config.Cfg.ApmServer, CreatedInfo: v.CreatedInfo, PlatForm: v.PlatForm, AutoBind: v.AutoBind, HiddenBundle: v.HiddenBundle, FromBindingID: v.FromBindingID, GroupID: v.GroupID, } if item.ApiServer == "" { item.ApiServer = config.Cfg.ApiServer } item.Expire = getExpire(item.Expire, licenseInfo.ExpireTime) //if item.Expire == MAX_EXPIRE_DATA { // common.GLog.Infof("item expire is max expire data:%+v", v) // item.Expire = 0 //} ////非uat环境取license过期时间 //if config.Cfg.PublishEnv != common.ENV_UAT { // item.Expire = licenseInfo.ExpireTime //} if req.Platform == entity.BINGING_PLATFORM_OPER && item.HiddenBundle == 1 { item.BundleInfos = []entity.BundleInfo{} } succRspData.List = append(succRspData.List, item) } utility.MakeLocRsp(c, http.StatusOK, utility.OK, succRspData) return } func (s BindingService) GetBindingByGroupIdAndName(ctx context.Context, groupId string, name string, isAdmin bool) (*entity.Binding, error) { repo := impl.InitBindingRepo() return repo.GetByGroupIdAndName(ctx, groupId, name, isAdmin) } func (s BindingService) UpdateByBindId(ctx context.Context, bindingId string, bind *entity.Binding) error { repo := impl.InitBindingRepo() return repo.UpdateByBindId(ctx, bindingId, bind) } func (s BindingService) RemoveApps(ctx context.Context, bindingId string, apps []string) error { return s.bindRepo.RemoveApps(ctx, bindingId, apps) } //更新应用过期时间 func (s *BindingService) UpExpire(ctx context.Context, bindingId string, expire int64) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() repo := impl.InitBindingRepo() err := repo.UpdateExpire(ctx, bindingId, expire) if err != nil { log.Errorf("AppService UpExpire err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } return rsp.SetLoc(http.StatusOK, utility.OK) } func (s BindingService) AssApps(ctx context.Context, c *gin.Context, bindingId string, appIds []string, account string) *utility.SvrRsp { var ( rsp = utility.DefaultSvrRsp() now = utils.GetNowMs() logAppMap = make(map[string]string) ) bind, err := s.bindRepo.GetInfo(ctx, bindingId) if err != nil { log.Errorf("AssApps get binding info err:%s,binding id:%s", err.Error(), bindingId) return rsp.SetLoc(http.StatusBadRequest, utility.FS_DB_ERR) } appendsApps := []entity.AppInfo{} //log.Infof("before ass apps binding binding_id:%s len bundle:%d len apps:%d", bind.BindingID, len(bind.BundleInfos), len(bind.AppInfos)) for _, appID := range appIds { appDevInfo, err := s.appRepo.GetAppInfo(ctx, appID) if err != nil { log.Errorf("AssApps appid:[%s] err:%s", appID, err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_DB_ERR) } //判断该应用是否已经关联了该小程序 found := false for _, info := range bind.AppInfos { if appID == info.AppID { found = true break } } if found { log.Errorf("associate app has exist !!") return rsp.SetLoc(http.StatusBadRequest, utility.FS_APP_ASSOCIATED) } appInfo := entity.AppInfo{ AppID: appID, AssociatedAt: now, AssociatedBy: account, } //bind.AppInfos = append(bind.AppInfos, appInfo) logAppMap[appID] = appDevInfo.Name appendsApps = append(appendsApps, appInfo) } //log.Infof("after ass apps binding binding_id:%s len bundle:%d len apps:%d", bind.BindingID, len(bind.BundleInfos), len(bind.AppInfos)) err = s.bindRepo.AppendApps(ctx, bindingId, appendsApps) if err != nil { log.Errorf("AppendApps err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_DB_ERR) } //日志 logExp := make(map[string]interface{}) logReq := httpcall.GenOperateDataV2Req{ OrganId: bind.GroupID, Content: kafka.GenContentAssApp(kafka.BIND_ASS_APP_LOG, bind.Name, logAppMap), Extra: logExp, Oper: "", AccountId: c.GetHeader(entity.ACCOUNT_ID_HEADER_KEY), IsDev: true, } hCaller.AddOperateLogV2(c, logReq) return rsp } func (s BindingService) handleBundles(ctx context.Context, groupId string, accountInfo *httpcall.AccountInfoData, bundles []apiproto.CreateBundleReq, license *httpcall.LicenseData, copyOper bool) (string, []entity.BundleInfo) { newBundIds := make([]entity.BundleInfo, 0) createAt := time.Now().UnixNano() / 1e6 for _, v := range bundles { if v.BundleId == "" { continue } //bundle id不能重 repo := impl.InitBindingRepo() _, err := repo.GetBundleByGroupIdAndBundleId(ctx, groupId, v.BundleId) if err != nil && !s.NotFound(err) { log.Errorf("CreateBinding get bundle repeat err:%s", err.Error()) return utility.FS_DB_ERR, nil } if !s.NotFound(err) { if copyOper { continue } log.Errorf("CreateBinding bundle Id has exist,bundle Id:%s", v.BundleId) return utility.FS_APP_BUNDLEID_REPEAT, nil } //去除首位空格 v.BundleId = strings.TrimSpace(v.BundleId) //var newV model.BundleInfo var newV = entity.BundleInfo{ BundleID: v.BundleId, Remark: v.Platform, SDKKey: "", SDKID: "", IsFirstCreate: true, CreatedAt: createAt, CreatedAccount: accountInfo.Account, CreatedBy: accountInfo.Name, IsForbidden: v.IsForbidden, } //创建的时候对白名单做特殊处理 if utils.InArry(v.BundleId, config.WhiteBundleIdArry) { log.Debugf("CreateBinding bundleId in white list!!!") key, secret := config.WhiteListGetSDKKeyAndId(v.BundleId) newV.SDKID = secret newV.SDKKey = key } else { //先生成sdkkey newSdkey := genSdkKeyV2(v.BundleId, "1", license.IsConfiguration, license.IsApiCover, license.DeviceNum) newSdkeyId := utils.GenAppSecret(newSdkey) //先获取下是否已经存在这个sdkKey exiResult, err := s.bindRepo.GetbundlesByBundleId(ctx, v.BundleId) if err != nil && !s.NotFound(err) { log.Errorf("CreateBinding get binding info err:%s", err.Error()) return utility.FS_DB_ERR, nil } log.Infof("exiResult result:%+v", exiResult) if !s.NotFound(err) { for _, b := range exiResult.BundleInfos { if b.BundleID == v.BundleId { //newV = b newV.SDKKey = b.SDKKey newV.SDKID = b.SDKID newV.IsFirstCreate = false break } } } else { if config.Cfg.PublishEnv == entity.ENV_PRIVATE { bundleInfo, err := s.bundleRepo.GetInfoByBundleId(ctx, v.BundleId) if err != nil && !s.NotFound(err) { log.Errorf("update get bundle info err:%s", err) return utility.FS_DB_ERR, nil } if s.NotFound(err) { log.Errorf("update get bundle info err:%s", err) return utility.FS_BUNDLE_ID_NOT_FOUND, nil } newV.SDKKey = bundleInfo.SDKKey newV.SDKID = bundleInfo.SDKID } else { newV.SDKKey = newSdkey //genSdkKey(v.BundleId, "1") newV.SDKID = newSdkeyId //utils.GenAppSecret(newV.SDKKey) newV.IsFirstCreate = true newV.Remark = v.Platform newV.CreatedAt = createAt newV.CreatedAccount = accountInfo.Account newV.CreatedBy = accountInfo.Name } } } //将SDKKey与对应的SDKId存储redis //authCache := cache.NewRuntimeAuthCheckCache() //err := authCache.SetSecret(ctx, newV.SDKKey, newV.SDKID) //if err != nil { // log.Errorf("CreateBinding set secret to cache err:%s", err.Error()) // return common.FS_DB_ERR, nil //} newV.BundleID = v.BundleId newBundIds = append(newBundIds, newV) log.Infoln(newV.SDKKey) } return utility.OK, newBundIds } func (s BindingService) BundleLimit(ctx context.Context, c *gin.Context) (limitNum, hasUseNum int, statusCode string) { licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("CreateBundles GetLicense err:%s", err.Error()) return 0, 0, utility.FS_LICENSE_SERVER_ERROR } log.Infof("BundleLicenseCheck get license info:%+v", licenseInfo) repo := impl.InitBindingRepo() //bindTotal, err := repo.GetBundleIdNum(ctx) bindTotal, err := repo.GetBundleLimit(ctx) if err != nil { log.Errorf("BundleLicenseCheck count err:", err.Error()) return 0, 0, utility.FS_DB_ERR } return licenseInfo.BundleIdCount, bindTotal, utility.OK } func (s BindingService) GetBundleIdLimitHand(ctx context.Context, groupId string) (int, error) { repo := impl.InitBindingRepo() return repo.GetBundleIdLimitHand(ctx, groupId) } func (s BindingService) GetBindingBySdkKey(ctx context.Context, sdkKey string) (*entity.Binding, error) { repo := impl.InitBindingRepo() return repo.GetBindingBySdkKey(ctx, sdkKey) } func (s BindingService) GetBindInfoByParam(ctx context.Context, sdkKey, organId, appId string) (*entity.Binding, error) { return s.bindRepo.GetInfoByParams(ctx, sdkKey, organId, appId) } func (s BindingService) ListBindings(ctx context.Context, groupId string, searchText string, pageNo int, pageSize int) ([]entity.Binding, int, error) { return s.bindRepo.ListBindings(ctx, groupId, searchText, pageNo, pageSize) } func (s BindingService) ListAllBundleInfos(ctx context.Context, searchText string, selectType, pageNo int, pageSize int) (int, []entity.Bundle, error) { return s.bundleRepo.ListAllBundleInfos(ctx, searchText, selectType, pageNo, pageSize) } func genSdkKey(bundleId string, openApm string) string { str := config.Cfg.SDKVersion + "&" + bundleId + "&" + openApm fmt.Println("encry str:%s", str) switch config.Cfg.EncryType { case "", "MD5": fmt.Println("encry type md5!!!") return utils.Encrypt(str) case "SM": fmt.Println("encry type sm!!!") return utils.EncryptSM4(str) } fmt.Println("encry type default !!!") return utils.Encrypt(str) } func genSdkKeyV2(bundleId string, openApm string, isConfiguration, isApiCover bool, deviceNum int) string { str := config.Cfg.SDKVersion + "&" + bundleId + "&" + openApm + "&0" if isConfiguration { if deviceNum > 0 { str += "&2" } else { str += "&1" } } else { str += "&0" } if isApiCover { str += "&1" } else { str += "&0" } fmt.Printf("encry str:%s\n", str) switch config.Cfg.EncryType { case "", "MD5": fmt.Println("encry type md5!!!") return utils.Encrypt(str) case "SM": fmt.Println("encry type sm!!!") return utils.EncryptSM4(str) } fmt.Println("encry type default !!!") return utils.Encrypt(str) } //获取生成的域名 func getResultSubDomain(ctx context.Context, groupName string, bindingName string) (string, error) { leftStr, err := getDomainRuleResultStr(groupName) if err != nil { log.Errorf("get str error: %v\n", err) return "", err } rightStr, err := getDomainRuleResultStr(bindingName) if err != nil { log.Errorf("get str error: %v\n", err) return "", err } subName := leftStr + "-" + rightStr i := 0 resultSubName, err := getSubDomainRecord(ctx, subName, i) if err != nil { log.Errorf("search subdomain err: %v\n", err) return "", err } log.Infof("resultSubName=%s\n", resultSubName) return "https://" + resultSubName + "-" + config.GetConfig().AliyunMainDomainSuffix + "." + config.GetConfig().AliyunMainDomain, nil } func getExpire(ms int64, licenseExp int64) int64 { if ms == MAX_EXPIRE_DATA { return 0 } //非uat环境取license过期时间 if config.GetConfig().PublishEnv != entity.ENV_UAT { return licenseExp } return ms } func getDomainRuleResultStr(str string) (string, error) { //这里只保留字母和中文 reg, err := regexp.Compile("[\u4e00-\u9fa5a-zA-Z]") //中文 if reg == nil { return "", err } regResult := reg.FindAllStringSubmatch(str, -1) var s = "" for _, v := range regResult { for _, v1 := range v { s += v1 } } if len(s) == 0 { return "", errors.New("format err") } //rs := []rune(str) rs := []rune(s) var result string for k, v := range rs { isAble := IsChinese(string(v)) if isAble { str, err := pinyin.New(string(rs[k])).Split(" ").Mode(pinyin.WithoutTone).Convert() if err != nil { log.Errorf("Hanzi to pingyin err:", err.Error()) return "", err } else { rs := []rune(str) result += string(rs[0]) } } else { result += string(rs[k]) } } if len(result) > 6 { //todo resultStr := []rune(result) return string(resultStr[0:6]), nil } return result, nil } func getSubDomainRecord(ctx context.Context, subName string, i int) (string, error) { leftDomain := "https://" + config.GetConfig().AliyunMainDomainPrefix rightDomain := "-" + config.GetConfig().AliyunMainDomainSuffix + "." + config.GetConfig().AliyunMainDomain var apiServer string if i < 1 { apiServer = leftDomain + subName + rightDomain } else { apiServer = leftDomain + subName + strconv.Itoa(i) + rightDomain } repo := impl.InitBindingRepo() result, err := repo.GetByApiServer(ctx, apiServer) if err != nil && !repo.NotFound(err) { log.Errorf("get apiServer err:%s", err.Error()) return "", err } if result.BindingID == "" { if i == 0 { return subName, nil } else { return subName + strconv.Itoa(i), nil } } else { i++ return getSubDomainRecord(ctx, subName, i) } } func IsChinese(str string) bool { for _, v := range str { if unicode.Is(unicode.Han, v) { return true } } return false } type CreateBundlesReq struct { List []CreateBundleReq `json:"list"` DeveloperID string } type CreateBundleReq struct { BundleId string `json:"bundleId"` Platform string `json:"platform"` } type UpdateBundleIsForbiddenReq struct { BundleId string `json:"bundleId"` IsForbidden int `json:"isForbidden"` //0:可用 1:禁用 } type UpdateBundlePlatformReq struct { BundleId string `json:"bundleId"` Platform string `json:"platform"` //平台 } func (s BindingService) CreateBundles(ctx context.Context, c *gin.Context, req CreateBundlesReq) string { length := len(req.List) if length == 0 { return utility.OK } limitNum, hasUseNum, statusCode := s.BundleLimit(ctx, c) if statusCode != utility.OK { return statusCode } if limitNum < hasUseNum+length { log.Errorf("BundleLicenseCheck bind total over limit,bind num:%d,createNum:%d,license num:%d", hasUseNum, length, limitNum) return utility.FC_OPERA_LIMIT_BIND_OVER_ERROR } bundleIds := make([]string, 0, length) for _, val := range req.List { if val.BundleId == "" || val.Platform == "" { log.Errorf("CreateBundles req param empty!") return utility.FS_BAD_JSON } bundleIds = append(bundleIds, val.BundleId) } existBundleIds, statusCode := s.BundleIsExist(ctx, bundleIds) if statusCode != utility.OK { return statusCode } if len(existBundleIds) != 0 { return utility.FS_APP_BUNDLEID_REPEAT } accountInfo, err := hCaller.GetAdminAccountInfo(ctx, req.DeveloperID) if err != nil { log.Errorln(fmt.Sprintf(fmt.Sprintf("GetAccountInfo err:%s", err.Error()))) return utility.FS_GET_ACCOUNTINFO_ERROR } licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("CreateBundles GetLicense err:%s", err.Error()) return utility.FS_LICENSE_SERVER_ERROR } bundles := s.reqToBundleInfos(req, accountInfo, time.Now().UnixNano()/1e6, licenseInfo) //将SDKKey与对应的SDKId存储redis //authCache := cache.NewRuntimeAuthCheckCache() //datas := make([]interface{}, 0, len(bundles)) //for _, val := range bundles { // err = authCache.SetSecret(ctx, val.SDKKey, val.SDKID) // if err != nil { // log.Errorf("CreateBundles set secret to cache err:%s", err.Error()) // return common.FS_DB_ERR // } // datas = append(datas, val) //} log.Debugln("bundles", bundles) repo := impl.InitBundleRepo() err = repo.Insert(ctx, bundles) if err != nil { log.Errorf("CreateBundles insert bundle info err:%s", err.Error()) return utility.FS_DB_ERR } else { return utility.OK } } func (s BindingService) UpdateBundleIsForbidden(ctx context.Context, req UpdateBundleIsForbiddenReq) string { limitNum, hasUseNum, statusCode := s.BundleLimit(ctx, nil) if statusCode != utility.OK { return statusCode } if req.IsForbidden == 0 { if limitNum < hasUseNum+1 { log.Errorf("BundleLicenseCheck bind total over limit,bind num:%d,createNum:%d,license num:%d", hasUseNum, limitNum) return utility.FS_OPER_BUNDLE_NUM_LIMIT } } repo := impl.InitBundleRepo() err := repo.UpdateBundleForbidden(ctx, req.BundleId, req.IsForbidden) if err != nil { log.Errorf("UpdateBundleIsForbidden bundle info err:%s", err.Error()) return utility.FS_DB_ERR } if req.IsForbidden == 1 { err := impl.InitBindingRepo().UpdateBundleIdIsForbidden(ctx, req.BundleId) if err != nil { log.Errorf("UpdateBundleIsForbidden bundle info err:%s", err.Error()) return utility.FS_DB_ERR } } return utility.OK } func (s BindingService) UpdateBundlesPlatform(ctx context.Context, req UpdateBundlePlatformReq) string { repo := impl.InitBundleRepo() err := repo.UpdateBundlePlatform(ctx, req.BundleId, req.Platform) if err != nil { log.Errorf("UpdateBundlesPlatform bundle info err:%s", err.Error()) return utility.FS_DB_ERR } err = impl.InitBindingRepo().UpdateBundleIdPlatform(ctx, req.BundleId, req.Platform) if err != nil { log.Errorf("UpdateBundleIsForbidden bundle info err:%s", err.Error()) return utility.FS_DB_ERR } return utility.OK } func (s *BindingService) reqToBundleInfos(req CreateBundlesReq, account *httpcall.AdminAccountInfo, createAt int64, license *httpcall.LicenseData) []entity.Bundle { bundles := make([]entity.Bundle, 0, len(req.List)) for _, val := range req.List { //SDKKey := genSdkKey(val.BundleId, "1") SDKKey := genSdkKeyV2(val.BundleId, "1", license.IsConfiguration, license.IsApiCover, license.DeviceNum) SDKID := utils.GenAppSecret(SDKKey) bundle := entity.Bundle{ BundleID: val.BundleId, Remark: val.Platform, SDKKey: SDKKey, SDKID: SDKID, IsFirstCreate: true, CreatedAt: createAt, CreatedAccount: account.Account, CreatedBy: account.Name, IsForbidden: 0, } bundles = append(bundles, bundle) } return bundles } func (s BindingService) BundleIsExist(ctx context.Context, bundleIds []string) (existBundleIds []string, statusCode string) { length := len(bundleIds) if length == 0 { return nil, utility.OK } existBundleIds = make([]string, 0) bundleInfos, err := s.bundleRepo.GetListByBundleIds(ctx, bundleIds) log.Errorf("bundleInfos", utility.InterfaceToJsonString(bundleInfos)) if err != nil { log.Errorf("BundleIsExist GetListByBundleIds err:%s", err.Error()) return } else if len(bundleInfos) == 0 { return existBundleIds, utility.OK } else { for _, val := range bundleInfos { existBundleIds = append(existBundleIds, val.BundleID) } return existBundleIds, utility.OK } }