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

2333 lines
83 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}
}