finclip-app-manager/domain/service/binding.go

2333 lines
83 KiB
Go
Raw Permalink Normal View History

2023-10-31 14:07:26 +08:00
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(&copyBind, &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(&copyBind, &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, &notifyInfo)
//}
//企业端更改结束
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(&copyBind, &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, &notifyInfo)
//}
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(&copyBind, &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 关联的 %sApp 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
}
}