package service import ( "archive/zip" "context" "encoding/json" "errors" "finclip-app-manager/domain/entity" "finclip-app-manager/domain/entity/proto" "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" pb "finclip-app-manager/infrastructure/protobuf/golang" "finclip-app-manager/infrastructure/utility" "finclip-app-manager/infrastructure/utils" "fmt" "io" "os" "path" "path/filepath" "strings" ezip "github.com/alexmullins/zip" "github.com/gin-gonic/gin" "gopkg.in/mgo.v2/bson" "net/http" "time" ) const ( /** * 开发中: InDevelopment * 审核中: Publishing * 撤销审核: PublishWithdraw * 审核通过:PublishApproved * 审核被拒:PublishRejected * 已上架:Published * 高本版上架致下架:UnpublishedByNewSeq * 开发者下架: UnpublishedByDev * 运营端下架:UnpublishedByAdmin **/ AppExternalStatusInDevelopment = "InDevelopment" AppExternalStatusPublishing = "Publishing" AppExternalStatusPublishWithdrawed = "PublishWithdrawed" AppExternalStatusPublishApproved = "PublishApproved" AppExternalStatusPublishRejected = "PublishRejected" AppExternalStatusPublished = "Published" AppExternalStatusUnpublishedByNewSeq = "UnpublishedByNewSeq" AppExternalStatusUnpublishedByDev = "UnpublishedByDev" AppExternalStatusUnpublishedByAdmin = "UnpublishedByAdmin" ) type AppService struct { appRepo repository.AppRepository buildRepo repository.IAppBuildInfoRepo bindingRepo repository.IBindingRepo tempAppRepo repository.IAppTempInfoRepo //qrcodeRepo repository.IQrCodeInfoRepo prviacySettingRepo repository.IPrivacySettingRepo tool *BoxTool } func NewAppService() *AppService { return &AppService{ appRepo: impl.InitAppRepo(), buildRepo: impl.InitBuildInfoRepo(), bindingRepo: impl.InitBindingRepo(), tempAppRepo: impl.InitAppTempInfoRepo(), //qrcodeRepo: impl.InitQrCodeInfoRepo(), prviacySettingRepo: impl.InitPrivacySettingRepo(), tool: NewBoxTool(), } } func (as *AppService) CreateApp(ctx context.Context, c *gin.Context, req proto.CreateAppReq, accountId string) (*entity.App, *utility.SvrRsp) { log.Infof("createApp get req:%+v", req) rsp := utility.DefaultSvrRsp() groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, accountId) if err != nil { log.Errorf("createApp GetGroupID err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } accountInfo, err := hCaller.GetAccountInfo(ctx, accountId) if err != nil { log.Errorf("createApp GetAccountInfo err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_ACCOUNTINFO_ERROR) } if req.ProjectType < 0 || req.ProjectType > 2 { log.Errorf("createApp param err") return nil, rsp.SetLoc(http.StatusBadRequest, utility.FS_PARAM_ERR) } info := entity.App{} info.AppClass = req.AppClass info.AppTag = req.AppTag info.AppType = req.AppType info.CoreDescription = req.CoreDescription info.Logo = req.Logo info.Name = req.Name info.GroupID = groupInfo.GroupID info.CreatedBy = accountInfo.Account info.DeveloperID = accountId info.AppID = bson.NewObjectId().Hex() info.ProjectType = req.ProjectType timestamp := time.Now().UnixNano() / 1e6 info.Status = entity.Status{ Value: entity.StInDevelopment, LastUpdated: timestamp, ModifiedBy: info.DeveloperID, } info.Created = timestamp info.IsForbidden = 0 licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("createApp get license info error:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } log.Infof("createApp get license info:%+v", licenseInfo) appCount, err := as.appRepo.AppCount(ctx, "") if err != nil { log.Errorf("createApp get app count error:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if appCount >= licenseInfo.AppCount { log.Errorf("createApp app count has over license limit app count:%d", appCount) return nil, rsp.SetLoc(http.StatusForbidden, utility.FC_PRI_LIMIT_APPID_OVER_ERROR) } //调用支付权限模块增加小程序数量 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { applyReq := httpcall.PayAddLimitReq{} applyReq.Type = httpcall.PAY_ADD_TYPE_APP applyReq.AccountId = accountId applyReq.BusinessId = info.AppID applyReq.BusinessName = info.Name payAddRsp, httpCode, err := hCaller.PayAddLimit(ctx, &applyReq) if err != nil { log.Errorf("PayAddLimit err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if httpCode != http.StatusOK { return nil, rsp.SetLoc(httpCode, utility.FC_OPERA_LIMIT_APPID_OVER_ERROR) } if payAddRsp.Data.EndTime == 0 { payAddRsp.Data.EndTime = MAX_EXPIRE_DATA } info.Expire = payAddRsp.Data.EndTime } else { //调用运营端增加企业appid数量,会做校验 n := httpcall.AddLimitInfoReq{ Type: "appId", OrganId: info.GroupID, AddNum: 1, } httpCode, _, err := hCaller.AddLimitInfo(ctx, &n) if err != nil { log.Errorf("createApp AddLimitInfo err:%s", err.Error()) return nil, rsp.SetLoc(httpCode, utility.FC_OPERA_LIMIT_APPID_OVER_ERROR) } } if err = as.appRepo.InsertApp(ctx, info); err != nil { log.Errorf("createApp insert appVer info err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_DB_ERR) } //生成操作日志 logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, groupInfo.GroupID, kafka.GenContent(kafka.APP_ADD_LOG, info.Name, info.AppID), logExp, accountInfo.Account) info.Expire = getExpire(info.Expire, licenseInfo.ExpireTime) return &info, rsp.SetLoc(http.StatusCreated, utility.OK) } func (as *AppService) WithdrawPublishRequest(ctx context.Context, c *gin.Context, appId string, seq int, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appVer, err := as.appRepo.GetAppVerInfo(ctx, appId, seq) if err != nil { log.Errorf("withdrawPublishRequest get app ver err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("withdrawPublishRequest GetGroupID err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } err = as.appRepo.WithdrawPubApp(ctx, appId, seq, accountInfo.Account) if err != nil { log.Errorf("withdrawPublishRequest db err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, accountInfo.OrganId, kafka.GenContent(kafka.APP_CANCEL_REVIEW_LOG, appVer.Name, appVer.AppID), logExp, accountInfo.Account) //model.NewAsyncMessageRepo().GenAppStatusChangeInfo(traceCtx, model.AppStatusChangeInfo{Event: model.AppWithdrawPubReq, Info: map[string]interface{}{"appId": appVer.AppID}}) return rsp } func (as *AppService) UpdateApp(ctx context.Context, c *gin.Context, req proto.AppUpdateReq, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appInfo, err := as.appRepo.GetAppInfo(ctx, req.AppId) if err != nil { log.Errorf("UpdateApp app info not found,req:%+v", req) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } oldName := appInfo.Name groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, userId) if err != nil { log.Errorf("updateApp GetGroupID err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } if groupInfo.GroupID != appInfo.GroupID { log.Errorf("updateApp group id not equal,req groupId:%+v,get groupId:%s", groupInfo, appInfo.GroupID) return rsp.SetLoc(http.StatusForbidden, utility.FS_FORBIDDEN) } //err = as.appRepo.UpdateApp(ctx, appInfo) //if err != nil { // log.Errorf("updateApp app err:%s", err.Error()) // return rsp.SetLoc(http.StatusForbidden, utility.FS_DB_ERR) //} appInfo.Name = req.Name appInfo.Logo = req.Logo appInfo.AppClass = req.AppClass appInfo.AppTag = req.AppTag appInfo.CoreDescription = req.CoreDescription appInfo.CustomData.DetailDescription = req.CustomData.DetailDescription err = as.appRepo.UpdateApp(ctx, appInfo) if err != nil { log.Errorf("UpdateApp repo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if oldName != req.Name { if err = as.appRepo.UpdateAppVerAppName(ctx, req.AppId, req.Name); err != nil { log.Errorf("UpdateAppVerAppName repo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } //操作日志 logExp := make(map[string]interface{}) logReq := httpcall.GenOperateDataV2Req{ OrganId: appInfo.GroupID, Content: kafka.GenContent(kafka.APP_EDIT_INFO_LOG, appInfo.Name, appInfo.AppID), Extra: logExp, Oper: "", AccountId: userId, IsDev: true, } hCaller.AddOperateLogV2(c, logReq) return rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) UpdateAppIsForbidden(ctx context.Context, req proto.AppIsForbiddenUpdateReq, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appInfo, err := as.appRepo.GetAppInfo(ctx, req.AppId) if err != nil { log.Errorf("UpdateAppIsForbidden app info not found,req:%+v", req) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, userId) if err != nil { log.Errorf("updateAppIsForbidden GetGroupID err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } if groupInfo.GroupID != appInfo.GroupID { log.Errorf("updateAppIsForbidden group id not equal,req groupId:%+v,get groupId:%s", groupInfo, appInfo.GroupID) return rsp.SetLoc(http.StatusForbidden, utility.FS_FORBIDDEN) } if req.IsForbidden == 0 { licenseInfo, err := hCaller.GetLicense(ctx) if err != nil { log.Errorf("createApp get license info error:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } log.Infof("createApp get license info:%+v", licenseInfo) appCount, err := as.appRepo.AppCount(ctx, "") if err != nil { log.Errorf("createApp get app count error:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if appCount >= licenseInfo.AppCount { log.Errorf("createApp app count has over license limit app count:%d", appCount) return rsp.SetLoc(http.StatusOK, utility.FC_PRI_LIMIT_APPID_OVER_ERROR) } } appInfo.IsForbidden = req.IsForbidden //调用支付权限模块增加小程序数量 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { applyReq := httpcall.PayAddLimitReq{} applyReq.Type = httpcall.PAY_ADD_TYPE_APP applyReq.AccountId = userId applyReq.BusinessId = req.AppId applyReq.BusinessName = appInfo.Name if req.IsForbidden == 0 { payAddRsp, httpCode, err := hCaller.PayAddLimit(ctx, &applyReq) if err != nil { log.Errorf("PayAddLimit err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if httpCode != http.StatusOK { return rsp.SetLoc(httpCode, utility.FC_OPERA_LIMIT_APPID_OVER_ERROR) } if payAddRsp.Data.EndTime == 0 { payAddRsp.Data.EndTime = MAX_EXPIRE_DATA } appInfo.Expire = payAddRsp.Data.EndTime } else { _, httpCode, err := hCaller.PayUpdateLimit(ctx, &applyReq) if err != nil { log.Errorf("PayAddLimit err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if httpCode != http.StatusOK { return rsp.SetLoc(httpCode, utility.FC_OPERA_LIMIT_APPID_OVER_ERROR) } } } else { //调用运营端增加企业appid数量,会做校验 addNum := 1 if req.IsForbidden == 1 { addNum = -1 } n := httpcall.AddLimitInfoReq{ Type: "appId", OrganId: appInfo.GroupID, AddNum: addNum, } httpCode, _, err := hCaller.AddLimitInfo(ctx, &n) if err != nil { log.Errorf("createApp AddLimitInfo err:%s", err.Error()) return rsp.SetLoc(httpCode, utility.FC_OPERA_LIMIT_APPID_OVER_ERROR) } } err = as.appRepo.UpdateApp(ctx, appInfo) if err != nil { log.Errorf("UpdateAppIsForbidden repo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } /*//操作日志 logExp := make(map[string]interface{}) logReq := kafka.GenOperateDataV2Req{ OrganId: appInfo.GroupID, Content: kafka.GenContent(kafka.APP_EDIT_INFO_LOG, appInfo.Name, appInfo.AppID), Extra: logExp, Oper: "", AccountId: userId, IsDev: true, } kafka.GenOperateDataV2(ctx, c, logReq)*/ return rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) PubApp(ctx context.Context, appId string, seq int, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appVerInfo, err := as.appRepo.GetAppVerInfo(ctx, appId, seq) if err != nil { log.Errorf("as.appRepo.GetAppVerInfo err:%s", err.Error()) if repository.NotFound(err) { log.Errorf("DevPublishApp get appVer not found!") return rsp.SetLoc(http.StatusNotFound, utility.FS_APP_SEQUENCE_NOT_FOUND) } } log.Debugf("as.appRepo.GetAppVerInfo err:%s", utility.InterfaceToJsonString(appVerInfo)) groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, userId) if err != nil { log.Errorf("DevPublishApp GetGroupID err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } if groupInfo.GroupID != appVerInfo.GroupID { log.Errorf("DevPublishApp group id no equal,app ver group Id:%s,get group info:%+v", appVerInfo.GroupID, groupInfo) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_APP_SEQUENCE_NOT_FOUND) } accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("DevPublishApp GetAccountInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_ACCOUNTINFO_ERROR) } _, onlineAppErr := as.appRepo.GetOnlineAppVer(ctx, appId) if onlineAppErr != nil { if !repository.NotFound(onlineAppErr) { log.Errorf("GetOnlineAppVer err:%s", onlineAppErr.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } lastPubVerInfo, err := as.appRepo.GetLatestPubAppVer(ctx, appId) if err != nil && !repository.NotFound(err) { log.Errorf("DevPublishApp GetLatestPubAppVer err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } var isRollback = false if !repository.NotFound(err) && lastPubVerInfo.Sequence > seq { //代表回退版本 if repository.NotFound(onlineAppErr) { //如果当前小程序未上架,不允许回退 log.Errorf("no pub app,appId:[%s]", appId) return rsp.SetLoc(http.StatusBadRequest, utility.FS_ROLLBACK_FORBID) } isRollback = true //如果当前上架的小程序版本已经是回退版本,那不可再次回退 if lastPubVerInfo.Status.Value == entity.StPublished && lastPubVerInfo.IsRollback { log.Errorf("roll back app ver has rollback,info:%+v", lastPubVerInfo) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_MULTI_ROLLBACK_FORBID) } //校验是否可以回退----不是最近下架的5个版本 rollbackList, err := as.appRepo.GetRollbackAbleList(ctx, groupInfo.GroupID, appId, lastPubVerInfo.Sequence) if err != nil { log.Errorf("GetRollbackAbleList err:%s,info:%+v", err.Error(), lastPubVerInfo) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } isValidRollbackSeq := false for _, v := range rollbackList { if v.Sequence == seq { isValidRollbackSeq = true } } if !isValidRollbackSeq { log.Errorf("roll back app not valid,req appId:%s,seq:%d", appId, seq) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_ROLLBACK_FORBID) } log.Infof("PubApp appId:[%s],seq:[%d] is rollback!", appId, seq) } else { if appVerInfo.Status.Value != entity.StPublishApproved { log.Errorf("PubApp status not valid,appId:[%s],seq:[%d]", appId, seq) return rsp.SetLoc(http.StatusBadRequest, utility.FS_INVALID_STATE) } } err = as.pubAppHelp(ctx, appId, seq, accountInfo.Account, true, isRollback, userId, appVerInfo.ActionStatus.ModifiedBy) if err != nil { log.Errorf("pubAppHelp err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_SYSTEM_CALL) } //service.NewWechatInfoService().TouchWechatInfo(traceCtx, appVer.AppID) //if isDev { // logExp := make(map[string]interface{}) // go model.GenOperateData(traceCtx, c, groupID, GenContent(APP_PUB_LOG, appVer.Name, appVer.AppID, appVer.Sequence), logExp, accountInfo.Account) //} //notifySpiderPushApp(traceCtx, req.AppID, client.UP_STATE) //sendSwanReport(ctx, "userId", userId) //c.JSON(http.StatusOK, gin.H{}) sendDelaySms(ctx, appVerInfo.DeveloperID, true, true, true, appId, appVerInfo.Name, seq) //上架通过后,更新小程序隐私中的updateTime与effectiveTime total, err := as.prviacySettingRepo.Count(ctx, appId) if total > 0 { item, err := as.prviacySettingRepo.GetInfoByAppId(ctx, appId) if err != nil { log.Errorf("PrviacySettingRepo insert err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } /*if item.EffectiveTime == 0 { item.EffectiveTime = time.Now().UnixNano() / 1e6 }*/ item.UpdateTime = time.Now().UnixNano() / 1e6 err = as.prviacySettingRepo.UpdateInfo(ctx, *item) if err != nil { log.Errorf("PrviacySettingRepo UpdateInfo time err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } return rsp.SetLoc(http.StatusOK, utility.OK) } //下架小程序 func (as *AppService) UnpubApp(ctx context.Context, c *gin.Context, appId string, seq int, userId string, isDev bool, reason string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appVerInfo, err := as.appRepo.GetAppVerInfo(ctx, appId, seq) if err != nil { log.Errorf("UnpubApp GetAppVerInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } log.Debugf("UnpubApp appVerInfo:%+v", appVerInfo) if appVerInfo.Status.Value != entity.StPublished { log.Errorf("UnpubApp status err,need approved,appId:%s,seq:%d", appId, seq) return rsp.SetLoc(http.StatusBadRequest, utility.FS_INVALID_STATE) } var account string if isDev { groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, userId) if err != nil { log.Errorf("UnpubApp get group info err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if groupInfo.GroupID != appVerInfo.GroupID { log.Errorf("unpublishAppHelp group id not equal appVer group id:%s,get group id:%+v", appVerInfo.GroupID, groupInfo) return rsp.SetLoc(http.StatusForbidden, utility.FS_FORBIDDEN) } accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("UnpubApp GetAccountInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } account = accountInfo.Account } else { adminInfo, err := hCaller.GetAdminAccountInfo(ctx, userId) if err != nil { log.Errorf("UnpubApp GetAdminAccountInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } account = adminInfo.Account } err = as.appRepo.UnpubApp(ctx, appId, seq, account, reason, isDev) if err != nil { log.Errorf("UnpubApp db err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if isDev { logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, appVerInfo.GroupID, kafka.GenContent(kafka.APP_DOWN_LOG, appVerInfo.Name, appVerInfo.AppID, appVerInfo.Sequence), logExp, account) } else { notifyContent := kafka.NotifyContent{} notifyContent.Title = fmt.Sprintf("小程序“%s”被下架", appVerInfo.Name) notifyContent.Result = "fail" notifyContent.Msg = fmt.Sprintf("小程序 %s(App ID:%s)被进行下架操作。用户暂无法使用小程序的所有服务(关联应用也无法使用)。下架理由为:%s", appVerInfo.Name, appVerInfo.AppID, reason) notifyContent.Reason = reason go kafka.GenNotifyData(ctx, appVerInfo.GroupID, 1000, notifyContent) } notifySpiderPushApp(ctx, appId, httpcall.DOWN_STATE) return rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) RollbackAppList(ctx context.Context, appId, userId string) ([]entity.AppVersion, error) { accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("RollbackAppList GetAccountInfo err:%s", err.Error()) return nil, err } latestPubAppVer, err := as.appRepo.GetLatestPubAppVer(ctx, appId) if err != nil { if repository.NotFound(err) { log.Errorf("RollbackAppList not found,appId:%s", appId) return make([]entity.AppVersion, 0), nil } return nil, err } if latestPubAppVer.Status.Value != entity.StPublished { log.Errorf("RollbackAppList latestPubAppVer no pub,appId:[%s]", appId) return make([]entity.AppVersion, 0), nil } if latestPubAppVer.IsRollback { log.Errorf("RollbackAppList latestPubAppVer has rollback,appId:[%s]", appId) return make([]entity.AppVersion, 0), nil } rollbackList, err := as.appRepo.GetRollbackAbleList(ctx, accountInfo.OrganId, appId, latestPubAppVer.Sequence) if err != nil { log.Errorf("GetRollbackAbleList db err:%s", err.Error()) return nil, err } return rollbackList, nil } func (as *AppService) SubmitApp(ctx context.Context, c *gin.Context, req apiproto.SubmitPublishReqest, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() buildInfo, err := as.buildRepo.GetInfoById(ctx, req.Id) if as.buildRepo.NotFound(err) || buildInfo == nil { buildInfo, err = as.buildRepo.GetInfoByBuildId(ctx, req.Id) if err != nil || buildInfo == nil { if err != nil { log.Errorf("SubmitApp get build info err:%s", err.Error()) } else { log.Errorf("SubmitApp get build info nil") } return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } if buildInfo.AppID != req.AppID { log.Errorf("buildID err") return rsp.SetLoc(http.StatusBadRequest, utility.FS_PARAM_ERR) } if config.GetConfig().IsOpenAuditSecurity { auditInfo, err := hCaller.GetAuditDataInfoByBuildInfoId(ctx, buildInfo.BuildInfoId) log.Debugln("GetAuditDataInfoByBuildInfoId:%v", utility.InterfaceToJsonString(auditInfo)) if err != nil { log.Errorf("GetAuditDataInfoByBuildInfoId err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_PARAM_ERR) } //0无,1审核中,2通过,3不通过 if auditInfo.Data.Status != 2 && auditInfo.Data.OperOpinion != 1 { log.Errorf("auditInfo.Data.Status not pass:%v", auditInfo.Data.Status) return rsp.SetLoc(http.StatusBadRequest, utility.FS_PARAM_ERR) } } appInfo, err := as.appRepo.GetAppInfo(ctx, req.AppID) if err != nil { log.Errorf("SubmitApp GetAppInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("SubmitApp GetAccountInfo err:%s,user id:%s", err.Error(), userId) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if appInfo.GroupID != accountInfo.OrganId { log.Errorf("SubmitApp group id not match!") return rsp.SetLoc(http.StatusBadRequest, utility.FS_BAD_JSON) } maxSeqAppVerInfo, err := as.appRepo.GetMaxSeqAppVer(ctx, req.AppID) if err != nil { if !repository.NotFound(err) { log.Errorf("SubmitApp GetMaxSeqAppVer err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } else { if maxSeqAppVerInfo.Status.Value == entity.StPublishing { log.Errorf("submitPublishRequest max version Publishing!!!") return rsp.SetLoc(http.StatusBadRequest, utility.FS_PUBLISHING_OR_UNPUBLISHING) } } oper := c.GetHeader("C-Open-Api") if oper == "" { oper = accountInfo.Account } SubmitAppReq := entity.SubmitAppReq{ AppId: req.AppID, BuildId: req.Id, Account: oper, NeedAutoPub: req.NeedAutoPub, TestInfo: req.TestInfo, UserId: userId, } err = as.appRepo.SubmitApp(ctx, SubmitAppReq, 0, userId) if err != nil { log.Errorf("SubmitApp app err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, appInfo.GroupID, kafka.GenContent(kafka.APP_SUB_REVIEW_LOG, appInfo.Name, appInfo.AppID), logExp, oper) if config.Cfg.PublishEnv == config.ENV_UAT { // 通知中心发送消息 notifyContent := kafka.NotifyContent{} notifyContent.Title = fmt.Sprintf("%s提交了”%s”小程序审核", accountInfo.Account, appInfo.Name) notifyContent.Result = "success" notifyContent.Msg = fmt.Sprintf("%s提交了小程序“%s”(APPID: %s)的上架审核申请", oper, appInfo.Name, appInfo.AppID) go kafka.GenNotifyData(ctx, accountInfo.OrganId, 1000, notifyContent) } return rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) ApproveApp(ctx context.Context, req apiproto.ApproveAppReq, isAdmin bool, userId string) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() appVerInfo, err := as.appRepo.GetAppVerInfo(ctx, req.AppID, req.Sequence) if err != nil { log.Errorf("ApproveApp get app version info err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_APP_SEQUENCE_NOT_FOUND) } var account string if isAdmin { adminInfo, err := hCaller.GetAdminAccountInfo(ctx, userId) if err != nil { log.Errorf("approveApp GetAdminAccountInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_GET_ACCOUNTINFO_ERROR) } account = adminInfo.Account } else { devAccountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("approveApp GetAdminAccountInfo err:%s", err.Error()) return rsp.SetLoc(http.StatusBadRequest, utility.FS_GET_ACCOUNTINFO_ERROR) } if devAccountInfo.OrganId != appVerInfo.GroupID { log.Errorf("ApproveApp organ id not match,req organ id:%s,app ver:%+v", devAccountInfo.OrganId, appVerInfo) return rsp.SetLoc(http.StatusNotFound, utility.FS_FORBIDDEN) } account = devAccountInfo.Account } if req.RequestFrom != "" { account = req.RequestFrom } var isPass = false if req.Status == entity.StPublishApproved { isPass = true } var isPubImmediately = false if appVerInfo.NeedAutoPub && isPass { isPubImmediately = true } log.Infof("isPass:%t isPubImmediately:%t", isPass, isPubImmediately) err = as.appRepo.ApproveApp(ctx, req.AppID, req.Sequence, account, req.Reason, isPass) if err != nil { log.Errorf("ApproveApp db err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } { //给通知中心发消息 st := time.Unix(appVerInfo.PublishingStatus.LastUpdated/1000, 0).Format("2006-01-02 15:04") at := time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04") notifyContent := kafka.NotifyContent{} if isPass { notifyContent.Title = fmt.Sprintf("小程序“%s”上架审核成功", appVerInfo.Name) notifyContent.Result = "success" //notifyContent.Msg = fmt.Sprintf("小程序 %s(APP ID: %s)已经通过审核,可进行后续操作。
申请时间:%s,审核时间:%s", // appVerInfo.Name, appVerInfo.AppID, st, at) notifyContent.Msg = fmt.Sprintf("小程序 %s(APP ID: %s)您提交的小程序已经通过审核,请在小程序详情中进行版本上架操作。
申请时间:%s,审核时间:%s", appVerInfo.Name, appVerInfo.AppID, st, at) notifyContent.Reason = req.Reason } else { notifyContent.Title = fmt.Sprintf("小程序“%s”上架审核失败", appVerInfo.Name) notifyContent.Result = "fail" notifyContent.Msg = fmt.Sprintf("小程序 %s(APP ID: %s)未通过审核,可进行后续操作。
申请时间:%s,审核时间:%s", appVerInfo.Name, appVerInfo.AppID, st, at) notifyContent.Reason = req.Reason } go kafka.GenNotifyData(ctx, appVerInfo.GroupID, 1000, notifyContent) sendDelaySms(ctx, appVerInfo.DeveloperID, isPass, isPubImmediately, false, req.AppID, appVerInfo.Name, req.Sequence) } if isPubImmediately { err = as.pubAppHelp(ctx, req.AppID, req.Sequence, "自动上架", false, false, "[auto]", appVerInfo.ActionStatus.ModifiedBy) //err = as.appRepo.PubApp(ctx, req.AppID, req.Sequence, "自动上架", true, false) if err != nil { log.Errorf("ApproveApp auto pub app err:%s", err.Error()) } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) } else { appTagStr := "" if len(appVerInfo.AppTag) > 0 { for _, v := range appVerInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagStr += tag.Name + "," log.Debugln("appTagStr", appTagStr) } } } if len(appTagStr) > 0 { appTagStr = appTagStr[0 : len(appTagStr)-1] } } } //sendSwanReport(ctx, "account", appVerInfo.RequestStatus.ModifiedBy) } return rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) pubAppHelp(ctx context.Context, appId string, seq int, account string, isDev, isRollback bool, userId, requestAccount string) error { //通知灰度发布并更新状态 var err error if isDev { //运营端审核通过自动上架,做一个特殊处理 err = hCaller.PubNotifyRuleEngine(ctx, appId, seq, userId, isDev) } else { err = hCaller.PubNotifyRuleEngine(ctx, appId, seq, "", isDev) } if err != nil { log.Errorf("pubAppHelp PubNotifyRuleEngine err:%s", err.Error()) return err } err = as.appRepo.PubApp(ctx, appId, seq, account, isDev, isRollback) if err != nil { log.Errorf("PubAppVer err:%s,appId:%s,seq:%d", err.Error(), appId, seq) return err } appVersion, err := as.appRepo.GetAppVerInfo(ctx, appId, seq) if err != nil { log.Errorf("pubAppHelp GetAppVerInfo err:%s", err.Error()) return nil } //service.NewWechatInfoService().TouchWechatInfo(traceCtx, appVer.AppID) //if isDev { // logExp := make(map[string]interface{}) // go model.GenOperateData(traceCtx, c, groupID, GenContent(APP_PUB_LOG, appVer.Name, appVer.AppID, appVer.Sequence), logExp, accountInfo.Account) //} //notifySpiderPushApp(traceCtx, req.AppID, client.UP_STATE) err = hCaller.TouchWechatInfo(ctx, appId) if err != nil { log.Errorf("TouchWechatInfo err:%s", err.Error()) return nil } /*appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return err } log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) if len(appVersion.AppTag) > 0 { log.Debugln("AppTag:", appVersion.AppTag) for _, v := range appVersion.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagStr += tag.Name + "," log.Debugln("appTagStr", appTagStr) } } } if len(appTagStr) > 0 { appTagStr = appTagStr[0 : len(appTagStr)-1] } }*/ /* if len(appVersion.AppTag) > 0 { for _, v := range appTagInfo.Data.AppClass { if v.Key == appVersion.AppClass { appClassStr = v.Name } } }*/ /*if len(appVersion.CustomData.SourceFile) > 0 { notifySpiderPubApp(ctx, appVersion.AppID, appVersion.Name, appVersion.CoreDescription, "", appVersion.CustomData.SourceFile[0].SourceFileUrl, appTagStr, appClassStr) }*/ go hCaller.PubAppNotifyToMiniprogram(ctx, &appVersion) sendSwanReport(ctx, "account", requestAccount) return nil } type GetStatisticsResponse struct { Created int `json:"created"` Submited int `json:"submited"` Approved int `json:"approved"` Published int `json:"published"` } func (as *AppService) AppStatistics(ctx context.Context, startTime, endTime int64, groupId string, distinct bool, isForbidden int) (GetStatisticsResponse, error) { var ( result = GetStatisticsResponse{} err error ) result.Created, err = as.appRepo.GetCreatedStatistics(ctx, startTime, endTime, groupId, isForbidden) if err != nil { return GetStatisticsResponse{}, err } result.Submited, err = as.appRepo.GetSubmittedStatistics(ctx, startTime, endTime, groupId, distinct) if err != nil { return GetStatisticsResponse{}, err } result.Approved, err = as.appRepo.GetApprovedStatistics(ctx, startTime, endTime, groupId, distinct) if err != nil { return GetStatisticsResponse{}, err } result.Published, err = as.appRepo.GetPublishedStatistics(ctx, startTime, endTime, groupId) if err != nil { return GetStatisticsResponse{}, err } return result, nil } func (as *AppService) GetAppInfoByAppId(ctx context.Context, appId string) (entity.App, error) { return as.appRepo.GetAppInfo(ctx, appId) } func (as *AppService) GetAppVerInfo(ctx context.Context, appId string, seq int) (entity.AppVersion, error) { return as.appRepo.GetAppVerInfo(ctx, appId, seq) } func (as *AppService) GetLatestPubAppVer(ctx context.Context, appId string) (entity.AppVersion, error) { return as.appRepo.GetLatestPubAppVer(ctx, appId) } func (as *AppService) GetOnlineAppVer(ctx context.Context, appId string) (entity.AppVersion, error) { return as.appRepo.GetOnlineAppVer(ctx, appId) } func (as *AppService) GetLatestReviewAppVer(ctx context.Context, appId string) (entity.AppVersion, error) { return as.appRepo.GetLatestReviewAppVer(ctx, appId) } func (as *AppService) GetMaxSeqAppVer(ctx context.Context, appId string) (entity.AppVersion, error) { return as.appRepo.GetMaxSeqAppVer(ctx, appId) } func (as *AppService) GetPubAppVer(ctx context.Context, appId string) (entity.AppVersion, error) { return as.appRepo.GetLatestPubAppVer(ctx, appId) } func (as *AppService) GetAllPublishedVerList(ctx context.Context, appId string) ([]entity.AppVersion, int, error) { return as.appRepo.GetAllPublishedVerList(ctx, appId) } func (as *AppService) GetBuildInfo(ctx context.Context, req apiproto.GetBuildAppInfoReq, sdkKey string) (*pb.BuildAppInfo, *utility.SvrRsp) { switch req.Type { case entity.BuildInfoTypeTrial: //获取体验版小程序详情 return as.GetTrialInfo(ctx, req.CodeId, sdkKey) case entity.BuildInfoTypeTemporary, entity.BuildInfoTypeRomoteDebug: //获取ide临时小程序详情 return as.getTempAppBuildInfo(ctx, req.CodeId) case entity.BuildInfoTypeDevelopment: return as.GetDevInfo(ctx, req.CodeId, sdkKey) default: return nil, utility.DefaultSvrRsp().SetLoc(http.StatusBadRequest, utility.FS_PARAM_ERR) } } func (as *AppService) GetTrialInfo(ctx context.Context, codeId, sdkKey string) (*pb.BuildAppInfo, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() buildInfo := new(pb.BuildAppInfo) info, err := as.buildRepo.GetInfoById(ctx, codeId) if err != nil { log.Errorf("GetTrialInfo get info err:%s", err.Error()) if repository.NotFound(err) { return nil, rsp.SetLoc(http.StatusNotFound, utility.FS_NOT_FOUND) } return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if info.Source != entity.APP_BUILD_SOURCE_TRIAL { log.Errorf("GetTrialInfo id is not a trial info:[%s]", codeId) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_NOT_TRIAL_INFO) } appInfo, err := as.appRepo.GetAppInfo(ctx, info.AppID) if err != nil { log.Errorf("GetTrialInfo GetAppVerInfo err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if appInfo.IsForbidden == 1 { return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_IS_FORBIDDEN) } groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appInfo.GroupID) if err != nil { log.Errorf("GetTrialInfo GetGroupInfoByUserId err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } // 获取开发者信息 //developerInfo, err := client.GetDeveloperInfo(ctx, appVerInfo.DeveloperID) //if err != nil { // log.Errorf("GetDeveloperInfo err:%s", err.Error()) // return nil, rsp.SetLoc(gin.H{}, http.StatusInternalServerError, common.FS_SERVER_ERR) //} //status := avs.account.getAccountStatus(groupInfo, developerInfo) if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("GetTrialInfo get info organ info invalid,code id:%s", codeId) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("GetTrialInfo get info organ info invalid,code id:%s", codeId) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } domainInfo, err := hCaller.GetAppDomainByOrganId(ctx, groupInfo.GroupID) if err != nil { log.Errorf("GetTrialInfo ger domain info err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //支付信息过期校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { appStatus, err := as.CheckIdStatus(ctx, appInfo.AppID) if err != nil { log.Errorf("CheckIdStatus err:%s,appId:%s", err.Error(), appInfo.AppID) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if appStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("check appid purch status no ok ") return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_PAY_EXPIRE) } } log.Debugf("get group id:%s,sdkKey:%s", appInfo.GroupID, sdkKey) inWhiteList := utility.InArry(sdkKey, config.WhiteSDKArry) if !inWhiteList { bindingInfo, err := as.bindingRepo.GetInfoBySdkKeyOrganId(ctx, appInfo.GroupID, sdkKey) if err != nil { log.Errorf("GetInfoBySdkKeyOrganId err:%s", err.Error()) if repository.NotFound(err) { return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_BIND_NOT_FOUND) } return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if bindingInfo.CooperateStatus.Value != entity.StBindValid { log.Errorf("GetTrialInfo binding bind invalid,binding info:%+v", bindingInfo) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_COOPERATION_TERMINATED) } //支付信息校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { bindStatus, err := as.CheckIdStatus(ctx, bindingInfo.BindingID) if err != nil { log.Errorf("CheckIdStatus err:%s,bindingId:%s", err.Error(), bindingInfo.BindingID) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if bindStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("binding id pay check no ok ") return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_BIND_PAY_EXPIRE) } } appAssBind := false for _, v := range bindingInfo.AppInfos { if v.AppID == appInfo.AppID { appAssBind = true } } if !appAssBind { log.Errorf("GetTrialInfo sdk key not ass binding,appId:[%s]", appInfo.AppID) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appInfo.AppTag) > 0 { for _, v := range appInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } buildInfo.CodeId = info.Id buildInfo.CoreDescription = appInfo.CoreDescription buildInfo.Created = info.Created buildInfo.CreatedBy = info.CreatedBy err, errCode, customData := ConvertModelCustomDataToPb(ctx, info.GroupID, info.CustomData, domainInfo, "cache") if err != nil { log.Errorf("ConvertModelCustomDataToPb err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, errCode) } buildInfo.CustomData = customData buildInfo.CustomData.DetailDescription = appInfo.CustomData.DetailDescription buildInfo.GroupId = info.GroupID buildInfo.GroupName = groupInfo.GroupName buildInfo.Logo = appInfo.Logo buildInfo.Name = appInfo.Name buildInfo.Version = info.Version buildInfo.IsTemp = false buildInfo.NeedCrt = domainInfo.NeedCrt buildInfo.AppId = info.AppID buildInfo.AppTag = appTagArr buildInfo.PrivacySettingType = int32(appInfo.PrivacySettingType) buildInfo.ProjectType = int32(appInfo.ProjectType) buildInfo.DeveloperStatus = int32(getAccountStatus(groupInfo)) //buildInfoCacheByte, _ = json.Marshal(buildInfo) //avs.rc.Set(ctx, avs.getTrialInfoCacheKey(codeId), string(buildInfoCacheByte), config.Cfg.RedisTrialExpireTime) wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, info.AppID) if err == nil { buildInfo.WechatLoginInfo = ConvertWechatLoginInfoToPb(wechatLoginInfo) //return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } return buildInfo, rsp } func (as *AppService) GetDevInfo(ctx context.Context, codeId, sdkKey string) (*pb.BuildAppInfo, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() buildInfo := new(pb.BuildAppInfo) //buildInfoCacheByte, err := avs.rc.GetBytes(ctx, avs.getDevInfoCacheKey(codeId)) //if err == nil { // if err = json.Unmarshal(buildInfoCacheByte, buildInfo); err == nil { // log.Infof("GetDevInfo from cache ...") // return buildInfo, rsp.SetLoc(gin.H{}, http.StatusOK, common.OK) // } //} info, err := as.buildRepo.GetInfoById(ctx, codeId) if err != nil { log.Errorf("GetDevInfo get info err:%s", err.Error()) if repository.NotFound(err) { return nil, rsp.SetLoc(http.StatusNotFound, utility.FS_NOT_FOUND) } return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } appInfo, err := as.appRepo.GetAppInfo(ctx, info.AppID) if err != nil { log.Errorf("GetDevInfo GetAppVerInfo err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if appInfo.IsForbidden == 1 { return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_IS_FORBIDDEN) } groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appInfo.GroupID) if err != nil { log.Errorf("GetDevInfo GetGroupInfoByUserId err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //// 获取开发者信息 //developerInfo, err := client.GetDeveloperInfo(ctx, appVerInfo.DeveloperID) //if err != nil { // log.Errorf("GetDeveloperInfo err:%s", err.Error()) // return nil, rsp.SetLoc(gin.H{}, http.StatusInternalServerError, common.FS_SERVER_ERR) //} //status := avs.account.getAccountStatus(groupInfo, developerInfo) if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("GetDevInfo get info organ info invalid,code id:%s", codeId) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("GetDevInfo get info organ info invalid,code id:%s", codeId) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } //if !client.OrganStatusIsValid(groupInfo.ReviewStatus) { // log.Errorf("GetDevInfo get info organ info invalid,code id:%s", codeId) // return nil, rsp.SetLoc(gin.H{}, http.StatusForbidden, common.FS_ORGAN_STATUS_INVALID) //} //支付信息过期校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { appStatus, err := as.CheckIdStatus(ctx, appInfo.AppID) if err != nil { log.Errorf("CheckIdStatus err:%s,appId:%s", err.Error(), appInfo.AppID) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if appStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("check appid purch status no ok ") return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_PAY_EXPIRE) } } domainInfo, err := hCaller.GetAppDomainByOrganId(ctx, appInfo.GroupID) if err != nil { log.Errorf("InternalGetAppVerInfo ger domain info err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } log.Debugf("get group id:%s,sdkKey:%s", appInfo.GroupID, sdkKey) inWhiteList := utility.InArry(sdkKey, config.WhiteSDKArry) if !inWhiteList { bindingInfo, err := as.bindingRepo.GetInfoBySdkKeyOrganId(ctx, appInfo.GroupID, sdkKey) if err != nil { log.Errorf("GetInfoBySdkKeyOrganId err:%s", err.Error()) if repository.NotFound(err) { return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_BIND_NOT_FOUND) } return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if bindingInfo.CooperateStatus.Value != entity.StBindValid { log.Errorf("GetDevInfo binding bind invalid,binding info:%+v", bindingInfo) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_COOPERATION_TERMINATED) } //支付信息校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { bindStatus, err := as.CheckIdStatus(ctx, bindingInfo.BindingID) if err != nil { log.Errorf("CheckIdStatus err:%s,bindingId:%s", err.Error(), bindingInfo.BindingID) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } if bindStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("binding id pay check no ok ") return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_BIND_PAY_EXPIRE) } } appAssBind := false for _, v := range bindingInfo.AppInfos { if v.AppID == appInfo.AppID { appAssBind = true } } if !appAssBind { log.Errorf("GetDevInfo sdk key not ass binding,appId:[%s]", appInfo.AppID) return nil, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appInfo.AppTag) > 0 { for _, v := range appInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } buildInfo.CodeId = info.Id buildInfo.CoreDescription = appInfo.CoreDescription buildInfo.Created = info.Created buildInfo.CreatedBy = info.CreatedBy err, errCode, customData := ConvertModelCustomDataToPb(ctx, info.GroupID, info.CustomData, domainInfo, "cache") if err != nil { log.Errorf("ConvertModelCustomDataToPb err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, errCode) } buildInfo.CustomData = customData buildInfo.CustomData.DetailDescription = appInfo.CustomData.DetailDescription buildInfo.GroupId = info.GroupID buildInfo.GroupName = groupInfo.GroupName buildInfo.Logo = appInfo.Logo buildInfo.Name = appInfo.Name buildInfo.Version = info.Version buildInfo.AppId = info.AppID buildInfo.IsTemp = false buildInfo.NeedCrt = domainInfo.NeedCrt buildInfo.DeveloperStatus = int32(getAccountStatus(groupInfo)) buildInfo.AppTag = appTagArr buildInfo.PrivacySettingType = int32(appInfo.PrivacySettingType) buildInfo.ProjectType = int32(appInfo.ProjectType) //buildInfoCacheByte, _ = json.Marshal(buildInfo) //avs.rc.Set(ctx, avs.getDevInfoCacheKey(codeId), string(buildInfoCacheByte), config.Cfg.RedisTrialExpireTime) wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, info.AppID) if err == nil { buildInfo.WechatLoginInfo = ConvertWechatLoginInfoToPb(wechatLoginInfo) //return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } return buildInfo, rsp } type GetRuleEngineVerPubListRspItem struct { Version int `json:"version"` VersionStr string `json:"versionStr"` } type VerToDescItem struct { Version int `json:"version"` Desc string `json:"desc"` } type GetRuleEngineVerPubListRsp struct { VerList []GetRuleEngineVerPubListRspItem `json:"verList"` //大于等于MaxPubVer的序列号列表 NowPubVer GetRuleEngineVerPubListRspItem `json:"nowPubVer"` //当前上架版本 MaxPubVer GetRuleEngineVerPubListRspItem `json:"maxPubVer"` //已发布、已下架、审核通过三种状态里面的最大版本号 VerToDesc []VerToDescItem `json:"verToDesc"` //序列号到版本描述的映射 } func (as *AppService) GetRuleEngineVerPubList(ctx context.Context, appId string) (interface{}, *utility.SvrRsp) { rspData := GetRuleEngineVerPubListRsp{} rsp := utility.DefaultSvrRsp() pubVer, err := as.appRepo.GetOnlineAppVer(ctx, appId) if err != nil { if repository.NotFound(err) { rspData.NowPubVer = GetRuleEngineVerPubListRspItem{Version: -1, VersionStr: ""} } else { log.Errorf("GetOnlineAppVer err:%s", err.Error()) return gin.H{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } rspData.NowPubVer.Version = pubVer.Sequence rspData.NowPubVer.VersionStr = pubVer.Version maxVerSeq := 0 latestPubVer, err := as.appRepo.GetLatestPubAppVer(ctx, appId) if err != nil { if repository.NotFound(err) { rspData.MaxPubVer.Version = 0 rspData.VerList = make([]GetRuleEngineVerPubListRspItem, 0) } else { log.Errorf("GetLatestPubAppVer err:%s", err.Error()) return gin.H{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } maxVerSeq = latestPubVer.Sequence rspData.MaxPubVer.Version = latestPubVer.Sequence rspData.MaxPubVer.VersionStr = latestPubVer.Version permitPubList, err := as.appRepo.GetAllPermitGrayPubVers(ctx, appId, maxVerSeq) if err != nil { log.Errorf("GetAllPermitGrayPubVers err:%s", err.Error()) return gin.H{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } for _, v := range permitPubList { item := GetRuleEngineVerPubListRspItem{ Version: v.Sequence, VersionStr: v.Version, } rspData.VerList = append(rspData.VerList, item) } //获取版本号对应的版本说明 type VerToDescTemp struct { Sequence int `bson:"sequence"` CustomData map[string]interface{} `bson:"customData"` } verList, _, err := as.appRepo.GetAllVers(ctx, appId) if err != nil { log.Errorf("GetAllVers err:%s", err.Error()) return gin.H{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } for _, v := range verList { item := VerToDescItem{} item.Version = v.Sequence item.Desc = v.CustomData.VersionDescription rspData.VerToDesc = append(rspData.VerToDesc, item) } log.Infof("GetRuleEngineVerPubList rsp:%+v", rspData) return rspData, rsp } type ListAppsReq struct { PullType string PageNo int PageSize int SearchText string SortType string UserId string GroupId string IsDev bool } func (as *AppService) DevListApps(ctx context.Context, req *ListAppsReq) (int, []entity.App, error) { groupInfo, err := hCaller.GetGroupInfoByUserId(ctx, req.UserId) if err != nil { log.Errorf("DevListApps GetGroupInfoByUserId err:%s", err.Error()) return 0, nil, err } total, list, err := as.appRepo.ListApps(ctx, groupInfo.GroupID, req.PageNo, req.PageSize, req.SearchText, req.SortType, req.PullType) if err != nil { if repository.NotFound(err) { log.Infof("DevListApps empty!") return 0, []entity.App{}, nil } return 0, nil, err } return total, list, err } func (as *AppService) AdminListApps(ctx context.Context, req *ListAppsReq) (int, []entity.App, error) { total, list, err := as.appRepo.ListApps(ctx, req.GroupId, req.PageNo, req.PageSize, req.SearchText, req.SortType, req.PullType) if err != nil { if repository.NotFound(err) { log.Infof("DevListApps empty!") return 0, []entity.App{}, nil } return 0, nil, err } return total, list, err } func (as *AppService) AdminListPubApps(ctx context.Context, req *ListAppsReq) (int, []entity.AppVersion, error) { list, total, err := as.appRepo.GetPublishedAppList(ctx, req.PageNo, req.PageSize, req.SearchText) if err != nil { if repository.NotFound(err) { log.Infof("DevListApps empty!") return 0, []entity.AppVersion{}, nil } return 0, nil, err } return total, list, err } type DevListAppsAndReviewsReq struct { ListType string `form:"listType"` GroupId string `form:"groupId"` AppId string `form:"appId"` Query string `form:"query"` Sort string `form:"sort"` SearchFields string `form:"searchFields"` SearchText string `form:"searchText"` PageSize int `form:"pageSize"` PageNo int `form:"pageNo"` ReviewsPageSize int `form:"reviewsPageSize"` ReviewsPageNo int `form:"reviewsPageNo"` } type DevListAppsAndReviewsRsp struct { Total int `json:"total"` List []AppsAndReviewRspItem `json:"list"` } type ReviewsRsp struct { Total int `json:"total"` List []ReviewsRspItem `json:"list"` } type AppsAndReviewRspItem struct { AppId string `json:"appId"` Name string `json:"name"` Logo string `json:"logo"` Version string `json:"version"` Status string `json:"status"` ReviewTotal int `json:"reviewTotal"` ReviewList []ReviewsRspItem `json:"reviewList"` } type ReviewsRspItem struct { Sequence int `json:"sequence"` Status string `json:"status"` Version string `json:"version"` } func (as *AppService) ListAppAndReviews(ctx context.Context, appId string, pageNo, pageSize int) (interface{}, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() total, appVers, err := as.appRepo.ListAppVersByAppId(ctx, appId, pageNo, pageSize) if err != nil { log.Errorf("ListAppVers err:%s", err.Error()) return gin.H{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } rspData := ReviewsRsp{} rspData.List = make([]ReviewsRspItem, 0) for _, v := range appVers { reviewInfo := ReviewsRspItem{} reviewInfo.Status = v.Status.Value reviewInfo.Sequence = v.Sequence reviewInfo.Version = v.Version rspData.List = append(rspData.List, reviewInfo) } rspData.Total = total return rspData, rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) GetAppsByAppIds(ctx context.Context, appIds []string) ([]entity.App, error) { return as.appRepo.GetAppsByAppIds(ctx, appIds) } func (as *AppService) GetAppsToBinding(ctx context.Context, req apiproto.ListAppsToBindReq) (int, []entity.App, error) { return as.appRepo.GetAppsToBinding(ctx, req.BindingId, req.PageNo, req.PageSize, req.SearchText) } func (as *AppService) GetLinkAppsByBindingID(ctx context.Context, bindingId string, pageNo, pageSize int, searchText string) (int, []entity.App, error) { return as.appRepo.GetLinkAppsByBindingId(ctx, bindingId, pageNo, pageSize, searchText) } func (as *AppService) GetLinkAppsBySDKKey(ctx context.Context, sdkKey string, pageNo, pageSize int) (int, []entity.App, error) { return as.appRepo.GetLinkAppsBySDKKey(ctx, sdkKey, pageNo, pageSize) } func (as *AppService) AdminGetLinkApps(ctx context.Context, searchText string, pageNo, pageSize int) (int, interface{}, error) { return as.appRepo.AdminGetLinkApps(ctx, pageNo, pageSize, searchText) } func (as *AppService) AdminGetAppReviews(ctx context.Context, req apiproto.AdminGetAppReviewsReq) (int, []entity.AppVersion, error) { return as.appRepo.GetAppReviews(ctx, req) } func (as *AppService) UpdateGrayPubStatus(ctx context.Context, appId string, seq int, status bool) error { return as.appRepo.UpdateGrayStatus(ctx, appId, seq, status) } func (as *AppService) GetAppInfo(ctx context.Context, appId string) (entity.App, error) { return as.appRepo.GetAppInfo(ctx, appId) } func (as *AppService) ListAppVer(ctx context.Context, appId string, pageNo, pageSize int) (int, []entity.AppVersion, error) { return as.appRepo.ListAppVersByAppId(ctx, appId, pageNo, pageSize) } func (as *AppService) AdminListAppVer(ctx context.Context, pageNo, pageSize int, searchText, t string, groupId string) (int, []entity.AppVersion, error) { return as.appRepo.ListAppVers(ctx, pageNo, pageSize, searchText, t, groupId) } func (as *AppService) UpdateBuildInfo(ctx context.Context, c *gin.Context, userId string, req apiproto.UpdateAppInfoReq) error { accountInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("UpdateBuildInfo err:%s", err.Error()) return err } oper := accountInfo.Account reqFrom := c.GetHeader("C-Open-Api") if reqFrom != "" { req.Username = reqFrom oper = reqFrom } info := entity.AppBuildInfo{ Id: bson.NewObjectId().Hex(), BuildInfoId: req.BuildInfoId, AppID: req.AppId, Source: entity.APP_BUILD_SOURCE_BUILD, Version: req.UpInfo.Version, //VersionDescription: req.UpInfo.CustomData.VersionDescription, GroupID: accountInfo.OrganId, UserId: req.UserId, Created: utils.GetNowMs(), CreatedBy: req.Username, CustomData: req.UpInfo.CustomData, Status: true, StartParams: entity.AppStartParams{}, } info.CustomData.Developer = oper err = as.buildRepo.Insert(ctx, info) if err != nil { log.Errorf("insert build info err:%s", err.Error()) return err } //操作日志 logExp := make(map[string]interface{}) go hCaller.AddOperateLog(c, info.GroupID, kafka.GenContent(kafka.APP_EDIT_INFO_LOG, req.UpInfo.Version, info.AppID), logExp, oper) return nil } type GetAppClassPerRspItem struct { AppClass string `json:"appClass"` AppClassName string `json:"appClassName"` Count int `json:"count"` } type GetAppClassPerRsp struct { List []GetAppClassPerRspItem `json:"list"` } func (as *AppService) GetAppClassPer(ctx context.Context, status string) (*GetAppClassPerRsp, error) { rspList, err := as.appRepo.GetAppClassPer(ctx, status) if err != nil { return nil, err } rspData := GetAppClassPerRsp{} rspData.List = make([]GetAppClassPerRspItem, 0) for _, v := range rspList { item := GetAppClassPerRspItem{ AppClass: v.Class, Count: v.Count, } if len(v.Name) > 0 { item.AppClassName = v.Name[0] } rspData.List = append(rspData.List, item) } return &rspData, nil } type GetGrayStatisticsVerListRspListItem struct { PubTime int64 `json:"pub_time"` UnPubTime int64 `json:"un_pub_time"` Version int `json:"version"` VersionStr string `json:"version_str"` } type GetGrayStatisticsVerListRsp struct { Total int `json:"total"` List []GetGrayStatisticsVerListRspListItem `json:"list"` } func (as *AppService) GetGrayStatisticsVerList(ctx context.Context, appId string, ver int, beginTime, endTime int64) (GetGrayStatisticsVerListRsp, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() num, verInfoList, err := as.appRepo.GetGrayStatisticsVerList(ctx, appId, ver, beginTime, endTime) if err != nil { log.Errorf("GetGrayStatisticsVerList err:%s", err.Error()) if repository.NotFound(err) { return GetGrayStatisticsVerListRsp{Total: 0, List: make([]GetGrayStatisticsVerListRspListItem, 0)}, rsp } return GetGrayStatisticsVerListRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } log.Debugf("GetGrayStatisticsVerList num:%d,err:%+v,ver list:%+v", num, err, verInfoList) rspData := GetGrayStatisticsVerListRsp{ List: make([]GetGrayStatisticsVerListRspListItem, 0), } for _, v := range verInfoList { item := GetGrayStatisticsVerListRspListItem{} item.PubTime = v.PublishedStatus.LastUpdated item.UnPubTime = v.UnpublishedStatus.LastUpdated item.Version = v.Sequence item.VersionStr = v.Version rspData.List = append(rspData.List, item) } rspData.Total = num return rspData, rsp } type InternalGetAppVerInfoRsp struct { AppID string `json:"appId"` Name string `json:"name"` Sequence int `json:"sequence"` AppClass string `json:"appClass"` AppTag []string `json:"appTag"` AppType string `json:"appType"` Status proto.AppRspStatus `json:"status"` DeveloperID string `json:"developerId"` DeveloperStatus int `json:"developerStatus"` GroupID string `json:"groupId"` GroupName string `json:"groupName"` Created int64 `json:"created"` CreatedBy string `json:"createdBy"` CustomData proto.AppRspCustomData `json:"customData"` Version string `json:"version"` CorporationID string `json:"corporationId"` CoreDescription string `json:"coreDescription"` Logo string `json:"logo"` GroupStatus int `json:"groupStatus,omitempty"` //todo:目前在缓存中,会返回给客户 InGrayRelease bool `json:"inGrayRelease"` //是否在灰度发布中 IsTemp bool `json:"isTemp"` NeedCrt bool `json:"needCrt"` WechatLoginInfo proto.WechatLoginInfo `json:"wechatLoginInfo"` PrivacySettingType int `json:"privacySettingType"` ProjectType int `json:"projectType"` } func (as *AppService) OpenApiGetAppVerInfo(ctx context.Context, appId string, sequence int, sdkVer string) (InternalGetAppVerInfoRsp, *utility.SvrRsp) { log.Infof("OpenApiGetAppVerInfo appId:%s,sequence:%d,sdkver:%s", appId, sequence, sdkVer) rsp := utility.DefaultSvrRsp() tempRspInfo, err := as.getTempAppInfo(ctx, appId, sequence) log.Debugf("getTempAppInfo rsp:%+v,err:%+v", tempRspInfo, err) if err == nil { return tempRspInfo, rsp } //if sequence != 0 { // appVerCacheRspInfo, err := as.openApiGetAppVerInfoFromCache(ctx, appId, sequence, sdkVer) // if err == nil { // return appVerCacheRspInfo, http.StatusOK, common.OK // } //} return as.openApiGetAppVerInfoNoCache(ctx, appId, sequence, sdkVer) } func (as *AppService) getTempAppBuildInfo(ctx context.Context, codeId string) (*pb.BuildAppInfo, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() tempRspInfo, err := as.getTempAppInfo(ctx, codeId, 1) log.Infof("getTempAppInfo rsp:%+v,err:%+v", tempRspInfo, err) if err != nil { log.Errorf("getTempAppInfo err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } appInfo, err := as.appRepo.GetAppInfo(ctx, tempRspInfo.AppID) if err != nil && !NotFound(err) { log.Errorf("GetTrialInfo GetAppInfo err:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appInfo.AppTag) > 0 { for _, v := range appInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } buildInfo := new(pb.BuildAppInfo) buildInfo.CodeId = codeId buildInfo.CoreDescription = tempRspInfo.CoreDescription buildInfo.Created = tempRspInfo.Created buildInfo.CreatedBy = tempRspInfo.CreatedBy buildInfo.CustomData = ConvertRpcCustomDataToPb(tempRspInfo.CustomData) buildInfo.CustomData.AppRuntimeDomain = new(pb.AppRuntimeDomain) buildInfo.GroupId = tempRspInfo.GroupID buildInfo.GroupName = tempRspInfo.GroupName buildInfo.Logo = tempRspInfo.Logo buildInfo.Name = tempRspInfo.Name buildInfo.Version = tempRspInfo.Version buildInfo.IsTemp = true buildInfo.NeedCrt = tempRspInfo.NeedCrt buildInfo.AppId = tempRspInfo.AppID buildInfo.AppTag = appTagArr buildInfo.PrivacySettingType = int32(appInfo.PrivacySettingType) buildInfo.ProjectType = int32(tempRspInfo.ProjectType) wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, tempRspInfo.AppID) if err == nil { buildInfo.WechatLoginInfo = ConvertWechatLoginInfoToPb(wechatLoginInfo) //return nil, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } return buildInfo, rsp.SetLoc(http.StatusOK, utility.OK) } func (as *AppService) getTempAppInfo(ctx context.Context, appId string, seq int) (InternalGetAppVerInfoRsp, error) { rspInfo := InternalGetAppVerInfoRsp{} //首先判断是否在临时表中 appTempInfo, err := as.tempAppRepo.GetInfoByAppIdAndSeq(ctx, appId, seq) if err != nil { return rspInfo, err } rspInfo = InternalGetAppVerInfoRsp{ AppID: appTempInfo.AppID, Name: appTempInfo.Name, Sequence: appTempInfo.Sequence, AppClass: appTempInfo.AppClass, AppType: appTempInfo.AppType, Status: proto.AppRspStatus{ Value: appTempInfo.Status.Value, Reason: appTempInfo.Status.Reason, LastUpdated: appTempInfo.Status.LastUpdated, ModifiedBy: appTempInfo.Status.ModifiedBy, }, DeveloperID: appTempInfo.DeveloperID, GroupID: appTempInfo.GroupID, GroupName: "", Created: appTempInfo.Created, CreatedBy: appTempInfo.CreatedBy, Version: appTempInfo.Version, CoreDescription: appTempInfo.CoreDescription, Logo: appTempInfo.Logo, ProjectType: appTempInfo.ProjectType, } rspInfo.CustomData.DetailDescription = appTempInfo.CustomData.DetailDescription rspInfo.CustomData.VersionDescription = appTempInfo.CustomData.VersionDescription rspInfo.CustomData.AppRuntimeDomain.Business.Domains = []string{} // = domainData.Business rspInfo.CustomData.AppRuntimeDomain.Service.Request = []string{} // = domainData.Service rspInfo.CustomData.AppRuntimeDomain.Service.Socket = []string{} rspInfo.CustomData.AppRuntimeDomain.Service.Download = []string{} rspInfo.CustomData.AppRuntimeDomain.Service.Upload = []string{} rspInfo.CustomData.AppRuntimeDomain.Whitelist.Domains = []string{} // = domainData.Whitelist rspInfo.CustomData.AppRuntimeDomain.Blacklist.Domains = []string{} rspInfo.CustomData.SourceFile = make([]proto.RspCustomDataSourceFile, 0) if len(appTempInfo.CustomData.SourceFile) > 0 { temp := appTempInfo.CustomData.SourceFile[0] item := proto.RspCustomDataSourceFile{} item.SourceFileUrl = "" item.FileMd5 = temp.FileMd5 item.Url = temp.Url item.UploadDate = temp.UploadDate item.Name = temp.Name item.BasicPackVer = temp.BasicPackVer item.Packages = convertPackages2(temp.EncryptPackages) rspInfo.CustomData.SourceFile = append(rspInfo.CustomData.SourceFile, item) } rspInfo.IsTemp = true rspInfo.NeedCrt = false wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, appId) if err == nil { rspInfo.WechatLoginInfo = *wechatLoginInfo //return rspInfo, errors.New("get wechatLoginInfo err") } return rspInfo, nil } func (as *AppService) openApiGetAppVerInfoFromCache(ctx context.Context, appId string, sequence int, sdkVer string) (InternalGetAppVerInfoRsp, error) { return InternalGetAppVerInfoRsp{}, nil //verCache := cache.NewAppVerCache() //cacheInfoByte, err := verCache.Get(ctx, avs.genOpenApiCacheKey(appId, sequence)) //if err != nil { // log.Warnf("cache get app ver info err:[%s],app id:[%s],seq:[%d]", err.Error(), appId, sequence) // return nil, err //} ////走缓存 //log.Debugf("AppVerService OpenApiGetAppVerInfo in cache ...") //cacheRspInfo := OpenApiAppVerCacheInfo{} //err = json.Unmarshal(cacheInfoByte, &cacheRspInfo) //if err != nil { // return nil, err //} // //rspInfo := InternalGetAppVerInfoRsp{ // AppID: cacheRspInfo.AppID, // Name: cacheRspInfo.Name, // Sequence: cacheRspInfo.Sequence, // AppClass: cacheRspInfo.AppClass, // AppType: cacheRspInfo.AppType, // Status: cacheRspInfo.Status, // DeveloperID: cacheRspInfo.DeveloperID, // DeveloperStatus: cacheRspInfo.DeveloperStatus, // GroupID: cacheRspInfo.GroupID, // GroupName: cacheRspInfo.GroupName, // Created: cacheRspInfo.Created, // CreatedBy: cacheRspInfo.CreatedBy, // Version: cacheRspInfo.Version, // CorporationID: cacheRspInfo.CorporationID, // CoreDescription: cacheRspInfo.CoreDescription, // Logo: cacheRspInfo.Logo, // InGrayRelease: cacheRspInfo.InGrayRelease, //} // //err, _, customData := ConvertModelCustomDataToRpc(ctx, avs, cacheRspInfo.GroupID, cacheRspInfo.CustomData, &cacheRspInfo.DomainData, sdkVer) //if err != nil { // log.Errorf("openApiGetAppVerInfoFromCache ConvertModelCustomDataToRpc err:[%s]", err.Error()) // return nil, err //} //rspInfo.CustomData = *customData //rspInfo.IsTemp = false //rspInfo.NeedCrt = cacheRspInfo.DomainData.NeedCrt //return &rspInfo, nil } func (as *AppService) openApiGetAppVerInfoNoCache(ctx context.Context, appId string, sequence int, sdkVer string) (InternalGetAppVerInfoRsp, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() if sequence == 0 { return as.GetInDevApp(ctx, appId, sdkVer) } appVer, err := as.appRepo.GetAppVerInfo(ctx, appId, sequence) if err != nil { log.Errorf("InternalGetAppVerInfo get appVer info err:%s", err.Error()) if repository.NotFound(err) { return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusNotFound, utility.FS_APP_SEQUENCE_NOT_FOUND) } return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } //校验企业的状态 groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appVer.GroupID) log.Infof("get groupInfo error:%+v,groupInfo:%+v", err, groupInfo) if err != nil { log.Errorf("InternalGetAppVerInfo ger group info err:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("InternalGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_COOPERATION_TERMINATED) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("InternalGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_COOPERATION_TERMINATED) } } //获取域名 domainData, err := hCaller.GetDomainInfoByOrganId(ctx, appVer.GroupID) if err != nil { log.Errorf("InternalGetAppVerInfo ger domain info err:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_DOMAIN_INFO_ERROR) } appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("as.appRepo.GetAppInfo err:%s", err.Error()) if repository.NotFound(err) { log.Errorf("get appVer not found!") return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appVer.AppTag) > 0 { for _, v := range appVer.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } log.Debugln("AppTag:", appTagArr) rspInfo := InternalGetAppVerInfoRsp{ AppID: appVer.AppID, Name: appVer.Name, Sequence: appVer.Sequence, AppClass: appVer.AppClass, AppTag: appTagArr, AppType: appVer.AppType, Status: proto.AppRspStatus{ Value: appVer.Status.Value, Reason: appVer.Status.Reason, LastUpdated: appVer.Status.LastUpdated, ModifiedBy: appVer.Status.ModifiedBy, }, DeveloperID: appVer.DeveloperID, GroupID: appVer.GroupID, GroupName: groupInfo.GroupName, Created: appVer.Created, CreatedBy: appVer.CreatedBy, Version: appVer.Version, CorporationID: appVer.CorporationID, CoreDescription: appVer.CoreDescription, Logo: appVer.Logo, InGrayRelease: appVer.InGrayRelease, PrivacySettingType: appInfo.PrivacySettingType, ProjectType: appInfo.ProjectType, } err, errCode, customData := ConvertModelCustomDataToRpc(ctx, appVer.GroupID, appVer.CustomData, domainData, sdkVer) if err != nil { log.Errorf("openApiGetAppVerInfoFromCache ConvertModelCustomDataToRpc err:[%s]", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, errCode) } status := getAccountStatus(groupInfo) rspInfo.CustomData = *customData rspInfo.GroupStatus = groupInfo.ReviewStatus rspInfo.IsTemp = false rspInfo.NeedCrt = domainData.NeedCrt rspInfo.DeveloperStatus = status wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, appId) if err == nil { rspInfo.WechatLoginInfo = *wechatLoginInfo //return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } log.Debugf("rsp info:%+v", rspInfo) return rspInfo, rsp } //兼容之前sequence为0的情况 func (as *AppService) GetInDevApp(ctx context.Context, appId, sdkVer string) (InternalGetAppVerInfoRsp, *utility.SvrRsp) { rsp := utility.DefaultSvrRsp() app, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("openApiGetAppVerInfoNoCache GetAppInfo err:%,appId:[%]", err.Error(), appId) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } buildInfo, err := as.buildRepo.GetLatestInfoByAppId(ctx, appId) if err != nil { log.Errorf("openApiGetAppVerInfoNoCache GetLatestInfoByAppId err:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } log.Debugf("GetInDevApp buildInfo:%+v", buildInfo) //校验企业的状态 groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, app.GroupID) log.Infof("get groupInfo error:%+v,groupInfo:%+v", err, groupInfo) if err != nil { log.Errorf("InternalGetAppVerInfo ger group info err:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("InternalGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_COOPERATION_TERMINATED) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("InternalGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_COOPERATION_TERMINATED) } } //获取域名 domainData, err := hCaller.GetDomainInfoByOrganId(ctx, app.GroupID) if err != nil { log.Errorf("InternalGetAppVerInfo ger domain info err:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_DOMAIN_INFO_ERROR) } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(app.AppTag) > 0 { for _, v := range app.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } rspInfo := InternalGetAppVerInfoRsp{ AppID: app.AppID, Name: app.Name, Sequence: app.Sequence, AppClass: app.AppClass, AppType: app.AppType, Status: proto.AppRspStatus{ Value: app.Status.Value, Reason: app.Status.Reason, LastUpdated: app.Status.LastUpdated, ModifiedBy: app.Status.ModifiedBy, }, DeveloperID: app.DeveloperID, GroupID: app.GroupID, GroupName: groupInfo.GroupName, Created: app.Created, CreatedBy: app.CreatedBy, Version: buildInfo.Version, CorporationID: app.GroupID, CoreDescription: app.CoreDescription, Logo: app.Logo, InGrayRelease: false, AppTag: appTagArr, PrivacySettingType: app.PrivacySettingType, ProjectType: app.ProjectType, } err, errCode, customData := ConvertModelCustomDataToRpc(ctx, app.GroupID, buildInfo.CustomData, domainData, sdkVer) if err != nil { log.Errorf("openApiGetAppVerInfoFromCache ConvertModelCustomDataToRpc err:[%s]", err.Error()) return InternalGetAppVerInfoRsp{}, rsp.SetLoc(http.StatusInternalServerError, errCode) } status := getAccountStatus(groupInfo) rspInfo.CustomData = *customData rspInfo.GroupStatus = groupInfo.ReviewStatus rspInfo.IsTemp = false rspInfo.NeedCrt = domainData.NeedCrt rspInfo.DeveloperStatus = status log.Debugf("rsp info:%+v", rspInfo) return rspInfo, rsp } func (as *AppService) UpExpire(ctx context.Context, appId string, expire int64) *utility.SvrRsp { rsp := utility.DefaultSvrRsp() err := as.appRepo.UpdateExpire(ctx, appId, expire) if err != nil { log.Errorf("AppService UpExpire err:%s", err.Error()) return rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } /*err = as.appRepo.UpdateExpireAppVersion(ctx, appId, 0, 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) } type RuntimeGetAppResponse struct { AppID string `json:"appId" bson:"appId"` Name string `json:"name" bson:"name"` Sequence int `json:"sequence" bson:"sequence"` AppClass string `json:"appClass" bson:"appClass"` AppTag []string `json:"appTag" bson:"appTag"` AppType string `json:"appType" bson:"appType"` DeveloperID string `json:"developerId" bson:"developerId"` DeveloperStatus int `json:"developerStatus" bson:"developerStatus"` GroupID string `json:"groupId" bson:"groupId"` GroupName string `json:"groupName" bson:"groupName"` Created int64 `json:"created" bson:"created"` CreatedBy string `json:"createdBy" bson:"createdBy"` CustomData proto.AppRspCustomData `json:"customData" bson:"customData"` Version string `json:"version" bson:"version"` CorporationID string `json:"corporationId" bson:"corporationId"` CoreDescription string `json:"coreDescription" bson:"coreDescription"` Logo string `json:"logo" bson:"logo"` Status proto.AppRspStatus `json:"status" bson:"status"` InGrayRelease bool `json:"inGrayRelease" bson:"inGrayRelease"` //是否在灰度发布中 IsTemp bool `json:"isTemp"` NeedCrt bool `json:"needCrt"` //是否需要校验域名证书 WechatLoginInfo proto.WechatLoginInfo `json:"wechatLoginInfo"` PrivacySettingType int `json:"privacySettingType"` ProjectType int `json:"projectType"` } func (as *AppService) RuntimeGetPubAppInfo(ctx context.Context, sdkKey, appId, sdkVer string) (RuntimeGetAppResponse, *utility.SvrRsp) { resp := &RuntimeGetAppResponse{} rsp := utility.DefaultSvrRsp() inWhiteList := utility.InArry(sdkKey, config.WhiteSDKArry) //未命中缓存 start := time.Now() log.Infof("RuntimeGetPubAppInfo from cache no match ... ") appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("RuntimeGetPubAppInfo GetAppInfo err:%s", err.Error()) if repository.NotFound(err) { return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusNotFound, utility.FS_APP_ID_NOT_FOUND) } return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if appInfo.IsForbidden == 1 { return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_IS_FORBIDDEN) } app, err := as.appRepo.GetOnlineAppVer(ctx, appId) if err != nil { if repository.NotFound(err) { log.Errorf("RuntimeGetPubAppInfo get info app status invalid,appId:%s", appId) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_SERVICE_UNAVAILABLE) } return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } log.Debugf("RuntimeGetPubAppInfo online app:%+v", app) appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appInfo.AppTag) > 0 { for _, v := range appInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } //支付信息过期校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { appStatus, err := as.CheckIdStatus(ctx, appId) if err != nil { log.Errorf("CheckIdStatus err:%s,appId:%s", err.Error(), appId) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if appStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("check purch status no ok ") return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_PAY_EXPIRE) } } //获取机构信息 groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, app.GroupID) if err != nil { log.Errorf("Failed to call GetGroupInfoByUserId: %v", err) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } status := getAccountStatus(groupInfo) if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("group review status no ok ") return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("group review status no ok ") return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } //获取域名信息 domainData, err := hCaller.GetAppDomainByOrganId(ctx, app.GroupID) if err != nil { log.Errorf("Failed to call GetDomainInfo: %v", err) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } //应用状态信息校验 if !inWhiteList { //首先判断sdkKey是否存在 var bindingInfo *entity.Binding bindingInfo, err = as.bindingRepo.GetBindingByGroupIdAndSdkKey(ctx, app.GroupID, sdkKey) if err != nil { log.Errorf("GetBindingByGroupIdAndSdkKey err:%s", err.Error()) if repository.NotFound(err) { return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_SIGNATURE_SDKKEY_INVAILD) } return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if bindingInfo.CooperateStatus.Value != entity.StBindValid { log.Errorf("binding coop stats valid,appId:%s,sdkKey:%s", appId, sdkKey) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_COOPERATION_TERMINATED) } for _, v := range bindingInfo.BundleInfos { if v.SDKKey == sdkKey && v.IsForbidden == 1 { log.Errorf("bundleInfo is forbidden", bindingInfo) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } } isAppAssBind := false for _, v := range bindingInfo.AppInfos { if v.AppID == appId { isAppAssBind = true } } if !isAppAssBind { log.Errorf("app id not ass binding,appId:%s,sdkKey:%s", appId, sdkKey) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } //支付信息校验 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { bindStatus, err := as.CheckIdStatus(ctx, bindingInfo.BindingID) if err != nil { log.Errorf("CheckIdStatus err:%s,bindingId:%s", err.Error(), bindingInfo.BindingID) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if bindStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("binding pay check no ok,bingdingId:%s", bindingInfo.BindingID) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_BIND_PAY_EXPIRE) } } } if GetLicenseValid() != LICENSE_IS_VALID { log.Errorf("license valid no ok ... ") return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_LICENSE_INVALID_ERR) } //返回数据 err = covertAppToRsp(ctx, &app, resp, sdkVer, domainData) if err != nil { log.Errorf("covertAppToRsp err:%s", err.Error()) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } resp.GroupName = groupInfo.GroupName resp.DeveloperStatus = status wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, appId) if err == nil { resp.WechatLoginInfo = *wechatLoginInfo //return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } resp.AppTag = appTagArr resp.PrivacySettingType = appInfo.PrivacySettingType resp.ProjectType = appInfo.ProjectType log.Infof("resp:%v", resp) fmt.Println("RuntimeGetPubAppInfo get app no cache time consum:", time.Since(start)) return *resp, rsp.SetLoc(http.StatusOK, utility.OK) } //type RuleEngineGetAppVerInfoRsp struct { // AppID string `json:"appId"` // Name string `json:"name"` // Sequence int `json:"sequence"` // AppClass string `json:"appClass"` // AppType string `json:"appType"` // DeveloperID string `json:"developerId"` // DeveloperStatus int `json:"developerStatus"` // GroupID string `json:"groupId"` // GroupName string `json:"groupName"` // Created int64 `json:"created"` // CreatedBy string `json:"createdBy"` // CustomData proto.AppRspCustomData `json:"customData"` // Version string `json:"version"` // CorporationID string `json:"corporationId"` // CoreDescription string `json:"coreDescription"` // Logo string `json:"logo"` // Status proto.AppRspStatus `json:"status"` // InGrayRelease bool `json:"inGrayRelease"` //是否在灰度发布中 // IsTemp bool `json:"isTemp"` // NeedCrt bool `json:"needCrt"` //} func (as *AppService) RuleEngineGetAppVerInfo(ctx context.Context, appId string, sequence int, sdkKey, sdkVer string) (RuntimeGetAppResponse, *utility.SvrRsp) { //appVerCache := cache.NewAppVerCache() //appVerCacheInfoByte, err := appVerCache.Get(ctx, avs.genRuleEngineCacheKey(appId, sequence)) //if err == nil { // log.Infof("RuleEngineGetAppVerInfo in cache ...") // appVerInfo := RuleEngineAppVerCacheInfo{} // err = json.Unmarshal(appVerCacheInfoByte, &appVerInfo) // if err == nil { // //判断是否关联 // if _, ok := appVerInfo.BindStatus[sdkKey]; ok { // rsp, err := avs.covertCacheToRuleEngineRsp(ctx, &appVerInfo, sdkVer) // if err != nil { // log.Errorf("covertCacheToRuleEngineRsp err:%s", err.Error()) // return nil, http.StatusInternalServerError, common.FS_SYSTEM_CALL // } // return rsp, http.StatusOK, common.OK // } // } //} //未命中缓存 resp := RuntimeGetAppResponse{} rsp := utility.DefaultSvrRsp() //首先校验licesne if GetLicenseValid() != LICENSE_IS_VALID { log.Errorf("RuleEngineGetAppVerInfo get info license invalid,sdkKey:%s,appId:%s,sequence:%d", sdkKey, appId, sequence) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_LICENSE_INVALID_ERR) } appVer, err := as.appRepo.GetAppVerInfo(ctx, appId, sequence) if err != nil { log.Errorf("GetAppVerInfo err:%s", err.Error()) if repository.NotFound(err) { return resp, rsp.SetLoc(http.StatusNotFound, utility.FS_APP_SEQUENCE_NOT_FOUND) } return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } //校验企业的状态,非法状态不放入缓存 log.Infof("get group info id:%s", appVer.GroupID) groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appVer.GroupID) log.Infof("get groupInfo error:%+v,groupInfo:%+v", err, groupInfo) if err != nil { log.Errorf("RuleEngineGetAppVerInfo ger group info err:%s", err.Error()) return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_GROUP_FAILED) } status := getAccountStatus(groupInfo) if config.Cfg.IsUatEnv() { if !hCaller.UatOrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("RuleEngineGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } else { if !hCaller.OrganStatusIsValid(groupInfo.ReviewStatus) { log.Errorf("RuleEngineGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_ORGAN_STATUS_INVALID) } } //if !avs.isOrganValid(groupInfo.ReviewStatus) { // log.Errorf("RuleEngineGetAppVerInfo group ReviewStatus invalid,status:%v", groupInfo.ReviewStatus) // return nil, http.StatusForbidden, common.FS_ORGAN_STATUS_INVALID //} inWhiteList := utility.InArry(sdkKey, config.WhiteSDKArry) if !inWhiteList { //校验应用关联状态,非法状态不放入缓存 binds, err := as.bindingRepo.GetBindingByGroupIdAndSdkKey(ctx, appVer.GroupID, sdkKey) if err != nil { log.Errorf("GetBindingByGroupIdAndSdkKey err:%s,GroupID:%s,sdkKey:%s", err.Error(), appVer.GroupID, sdkKey) if repository.NotFound(err) { return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_SIGNATURE_SDKKEY_INVAILD) } return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_DB_ERR) } if binds.CooperateStatus.Value != entity.StBindValid { log.Errorf("RuleEngineGetAppVerInfo CooperateStatus invalid:%s", binds.CooperateStatus.Value) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_COOPERATION_TERMINATED) } for _, v := range binds.BundleInfos { if v.SDKKey == sdkKey && v.IsForbidden == 1 { log.Errorf("bundleInfo is forbidden", binds) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } } isAppAssBinding := false for _, v := range binds.AppInfos { if v.AppID == appId { isAppAssBinding = true } } if !isAppAssBinding { log.Errorf("RuleEngineGetAppVerInfo get binding info no ass app,appId:%s,sdkKey:%s", appId, sdkKey) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_NOT_ASS_BIND) } //校验应用支付状态 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { bindStatus, err := as.CheckIdStatus(ctx, binds.BindingID) if err != nil { log.Errorf("RuleEngineGetAppVerInfo get bind id pay status err:%s", err.Error()) return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if bindStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("GetGrayAppInfo get info bind pay status invaild,bind id:%s", binds.BindingID) return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_BIND_PAY_EXPIRE) } } } //校验小程序的上架状态 if appVer.Status.Value != entity.StPublished && !appVer.InGrayRelease { log.Errorf("RuleEngineGetAppVerInfo appVer status invalid:%s", appVer.Status.Value) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_SERVICE_UNAVAILABLE) } appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("RuleEngineGetAppVerInfo GetAppInfo err:%s", err.Error()) if repository.NotFound(err) { return resp, rsp.SetLoc(http.StatusNotFound, utility.FS_APP_ID_NOT_FOUND) } return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if appInfo.IsForbidden == 1 { return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_IS_FORBIDDEN) } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SERVER_ERR) } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagArr := make([]string, 0) if len(appInfo.AppTag) > 0 { for _, v := range appInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagArr = append(appTagArr, tag.Name) } } } } //校验支付状态 if config.Cfg.OpenPurchAuth && config.Cfg.IsUatEnv() { //先校验小程序 appStatus, err := as.CheckIdStatus(ctx, appId) if err != nil { log.Errorf("RuleEngineGetAppVerInfo get app id pay status err:%s", err.Error()) return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } if appStatus == httpcall.PAY_ID_STATUS_EXPIRE { log.Errorf("RuleEngineGetAppVerInfo get info app pay status invaild,appId:%s", appId) return resp, rsp.SetLoc(http.StatusForbidden, utility.FS_APP_PAY_EXPIRE) } } //获取域名 domainData, err := hCaller.GetDomainInfoByOrganId(ctx, appVer.GroupID) if err != nil { log.Errorf("InternalGetAppVerInfo ger domain info err:%s", err.Error()) return resp, rsp.SetLoc(http.StatusInternalServerError, utility.FS_GET_DOMAIN_INFO_ERROR) } err = covertAppToRsp(ctx, &appVer, &resp, sdkVer, domainData) if err != nil { log.Errorf("covertAppToRsp err:%s", err.Error()) return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } resp.DeveloperStatus = status resp.GroupName = groupInfo.GroupName resp.PrivacySettingType = appInfo.PrivacySettingType resp.ProjectType = appInfo.ProjectType resp.AppTag = appTagArr wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, appId) if err == nil { resp.WechatLoginInfo = *wechatLoginInfo //return RuntimeGetAppResponse{}, rsp.SetLoc(http.StatusInternalServerError, utility.FS_SYSTEM_CALL) } return resp, rsp } func (as *AppService) CheckIdStatus(ctx context.Context, id string) (int, error) { return httpcall.PAY_ID_STATUS_USING, nil /*switch config.Cfg.ReqType { //case "grpc": // return grpcClient.PurchasingGetIdStatus(ctx, id) default: status, _, err := hCaller.PayCheckIdStatus(ctx, id) return status, err }*/ } func (as *AppService) BatchAppsByIdentity(ctx context.Context, sdkKey string, req *apiproto.BatchAppsByIdentityReq) *pb.BatchAppsByIdentityRsp { var ( rsp = new(pb.BatchAppsByIdentityRsp) ) rsp.Data = new(pb.BatchAppsByIdentityRsp_DATA) rsp.Data.AppList = make([]*pb.BatchAppsByIdentityRsp_AppListItem, 0) rsp.Result = new(pb.CommonResult) //判断sdkKey是否存在 sdkExi, err := as.bindingRepo.SdkKeyExi(ctx, sdkKey) if err != nil { utility.MakeGrpcCommonResult(http.StatusInternalServerError, utility.FS_SYSTEM_CALL, &rsp.Result) return rsp } if !sdkExi { utility.MakeGrpcCommonResult(http.StatusInternalServerError, utility.FS_BIND_NOT_FOUND, &rsp.Result) return rsp } for _, item := range req.Apps { rspAppListItem := as.getOneAppByIdentity(ctx, req.IdentityType, item.AppId, item.Identity, sdkKey) rsp.Data.AppList = append(rsp.Data.AppList, rspAppListItem) } utility.MakeGrpcCommonResult(http.StatusOK, utility.OK, &rsp.Result) return rsp } func (as *AppService) IdentityAppsCheck(ctx context.Context, sdkKey string, req *apiproto.IdentityAppsCheckReq) *pb.IdentityAppsCheckRsp { var ( rsp = new(pb.IdentityAppsCheckRsp) ) rsp.Data = new(pb.IdentityAppsCheckRsp_DATA) rsp.Data.AppList = make([]*pb.IdentityAppsCheckRsp_AppListItem, 0) rsp.Result = new(pb.CommonResult) //判断sdkKey是否存在 sdkExi, err := as.bindingRepo.SdkKeyExi(ctx, sdkKey) if err != nil { utility.MakeGrpcCommonResult(http.StatusInternalServerError, utility.FS_SYSTEM_CALL, &rsp.Result) return rsp } if !sdkExi { utility.MakeGrpcCommonResult(http.StatusInternalServerError, utility.FS_BIND_NOT_FOUND, &rsp.Result) return rsp } //判断一个小程序identity是否存在 //todo 加个缓存处理 for _, a := range req.Apps { rspAppListItem := as.getOneAppCheckResult(ctx, a.AppId, a.Identity, req.IdentityType, sdkKey) rsp.Data.AppList = append(rsp.Data.AppList, rspAppListItem) } utility.MakeGrpcCommonResult(http.StatusOK, utility.OK, &rsp.Result) return rsp } func (as *AppService) getOneAppCheckResult(ctx context.Context, appId, identity, identityType, sdkKey string) (rspAppListItem *pb.IdentityAppsCheckRsp_AppListItem) { rspAppListItem = &pb.IdentityAppsCheckRsp_AppListItem{ Errcode: utility.OK, Error: utility.GetErrMsg(utility.OK), Data: &pb.IdentityAppsCheckRsp_AppListItem_AppListItemData{AppId: appId, Identity: identity, IdentityValid: false}, } defer func() { rspAppListItem.Error = utility.GetErrMsg(rspAppListItem.Errcode) }() //cacheInfo, err := e.erc.GetAppCheckValid(ctx, appId, identity, sdkKey) //if err == nil { // log.Debugf("getOneAppCheckResult from cache,info:%+v", cacheInfo) // rspAppListItem.Data.IdentityValid = cacheInfo.IdentityValid // rspAppListItem.Errcode = cacheInfo.Errcode // return rspAppListItem //} //defer func() { //if rspAppListItem.Errcode != utility.FS_SYSTEM_CALL { //setCacheInfo := &AppCheckCacheInfo{IdentityValid: rspAppListItem.Data.IdentityValid, Errcode: rspAppListItem.Errcode} //log.Debugf("set app check cache info:%+v", cacheInfo) //if err = e.erc.SetAppCheckValid(ctx, appId, identity, sdkKey, setCacheInfo); err != nil { // log.Errorf("SetAppCheckValid err:%s", err.Error()) //} //} //}() appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("get app info err:%s", err.Error()) rspAppListItem.Errcode = utility.FS_SYSTEM_CALL if repository.NotFound(err) { rspAppListItem.Errcode = utility.FS_APP_ID_NOT_FOUND } return rspAppListItem } log.Debugf("get app info:%+v", appInfo) //判断该小程序是否可用 if appInfo.Status.Value != entity.StPublished { log.Errorf("app info status invalid,sdkKey:[%s],appInfo:%+v", sdkKey, appInfo) return rspAppListItem } //判断企业状态 organInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appInfo.GroupID) if err != nil { log.Errorf("get group info err:%s", err.Error()) rspAppListItem.Errcode = utility.FS_SYSTEM_CALL return rspAppListItem } else { if !hCaller.JudgeGroupStatusValid(organInfo.ReviewStatus) { log.Errorf("gropu status invalid,sdkKey:[%s],appId:[%s]", sdkKey, appId) rspAppListItem.Errcode = utility.FS_ORGAN_STATUS_INVALID return rspAppListItem } } //判断是否关联 bindingInfo, err := as.bindingRepo.GetInfoBySdkKeyOrganId(ctx, appInfo.GroupID, sdkKey) if err != nil { log.Errorf("get binging info err:%s", err.Error()) rspAppListItem.Errcode = utility.FS_SYSTEM_CALL if repository.NotFound(err) { rspAppListItem.Errcode = utility.FS_BIND_NOT_FOUND } return rspAppListItem } else { if bindingInfo.CooperateStatus.Value == entity.StBindInvalid { log.Errorf("binding info coop value invalid:%+v,sdkKey:[%s]", bindingInfo, sdkKey) rspAppListItem.Errcode = utility.FS_COOPERATION_TERMINATED return rspAppListItem } if !repository.IsAssAppId(bindingInfo, appId) { log.Errorf("binding not ass the appid,sdkKey:[%s],appId:[%s]", sdkKey, appId) rspAppListItem.Errcode = utility.FS_APP_NOT_ASS_BIND return rspAppListItem } } //判断版本状态 appVers, err := as.appRepo.GetAppVerLimitByIdentity(ctx, identityType, appId, identity, config.Cfg.CheckAppVerLimit) if err != nil { rspAppListItem.Errcode = utility.FS_SYSTEM_CALL if repository.NotFound(err) { rspAppListItem.Errcode = utility.FS_IDENTITY_NOT_FOUND_ERR } return rspAppListItem } else { if len(appVers) == 0 { rspAppListItem.Errcode = utility.FS_IDENTITY_NOT_FOUND_ERR return rspAppListItem } rspAppListItem.Data.IdentityValid = as.AppVerIsValid(appVers) } return rspAppListItem } func (as *AppService) getOneAppByIdentity(ctx context.Context, t, appId, identity, sdkKey string) *pb.BatchAppsByIdentityRsp_AppListItem { rspItem := &pb.BatchAppsByIdentityRsp_AppListItem{ Errcode: utility.OK, Error: utility.GetErrMsg(utility.OK), AppId: appId, Identity: identity, AppInfo: nil, ExternalAppStatus: "", } defer func() { rspItem.Error = utility.GetErrMsg(rspItem.Errcode) }() appVers, err := as.appRepo.GetAppVerLimitByIdentity(ctx, t, appId, identity, config.Cfg.CheckAppVerLimit) if err != nil { rspItem.Errcode = utility.FS_SYSTEM_CALL if repository.NotFound(err) { rspItem.Errcode = utility.FS_IDENTITY_NOT_FOUND_ERR } return rspItem } if len(appVers) == 0 { rspItem.Errcode = utility.FS_IDENTITY_NOT_FOUND_ERR return rspItem } //从获取到的三个版本列表中取得一个合适的版本 appVer := as.GetConcreteVer(appVers) if appVer == nil { rspItem.Errcode = utility.FS_IDENTITY_NOT_FOUND_ERR return rspItem } //判断企业状态 organInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appVer.GroupID) if err != nil { rspItem.Errcode = utility.FS_SYSTEM_CALL return rspItem } else { if !hCaller.JudgeGroupStatusValid(organInfo.ReviewStatus) { rspItem.Errcode = utility.FS_ORGAN_STATUS_INVALID return rspItem } } //判断是否关联 bindingInfo, err := as.bindingRepo.GetInfoBySdkKeyOrganId(ctx, appVer.GroupID, sdkKey) log.Debugf("get binding info:%+v", bindingInfo) if err != nil { log.Errorf("get binging info err:%s", err.Error()) rspItem.Errcode = utility.FS_SYSTEM_CALL if repository.NotFound(err) { rspItem.Errcode = utility.FS_BIND_NOT_FOUND } return rspItem } else { if bindingInfo.CooperateStatus.Value == entity.StBindInvalid { rspItem.Errcode = utility.FS_COOPERATION_TERMINATED return rspItem } if !repository.IsAssAppId(bindingInfo, appId) { rspItem.Errcode = utility.FS_APP_NOT_ASS_BIND return rspItem } } rspItem.AppInfo = new(pb.AppInfoRspData) as.tool.CovertAppVerToAppRspData(appVer, rspItem.AppInfo) //custom 包装 domainInfo, err := hCaller.GetAppDomainByOrganId(ctx, appVer.GroupID) //域名 if err != nil { log.Errorf("get domain err:%s", err.Error()) } else { as.tool.PackDomainToAppRspCustom(rspItem.AppInfo, domainInfo) } rspItem.AppInfo.CustomData.MenuInfo = nil //菜单 apiData, err := hCaller.GetApiList(ctx, appVer.GroupID) //api管理 if err != nil { log.Errorf("get api list err:%s", err.Error()) } else { as.tool.PackApiInfoToAppRspCustom(rspItem.AppInfo, &apiData) } rspItem.AppInfo.GroupName = organInfo.GroupName //企业名称 rspItem.ExternalAppStatus = as.getAppVerExternalStatus(appVer.Status.Value, appVer.UnpublishedStatus.Type) //做一个状态的转换 //放入缓存 //e.erc.SetAppVerCacheInfo(ctx, appId, identity, &ExternalAppVerCacheInfo{AppInfo: rspItem.AppInfo, ExternalStatus: rspItem.ExternalAppStatus}) return rspItem } func (as *AppService) GetConcreteVer(appVers []entity.AppVersion) *entity.AppVersion { if len(appVers) == 0 { return nil } appVer := appVers[0] for _, v := range appVers { if v.Status.Value == entity.StPublished { appVer = v break } if v.Status.Value == entity.StUnpublished && v.UnpublishedStatus.Type == entity.TypeUnpublishedDueToNewSeq { appVer = v break } } return &appVer } func (as *AppService) getAppVerExternalStatus(statusValue, unPubType string) string { //做一个状态的转换 result := "" switch statusValue { case entity.StInDevelopment: result = AppExternalStatusInDevelopment case entity.StPublishing: result = AppExternalStatusPublishing case entity.StPublishWithdrawed: result = AppExternalStatusPublishWithdrawed case entity.StPublishApproved: result = AppExternalStatusPublishApproved case entity.StPublishRejected: result = AppExternalStatusPublishRejected case entity.StPublished: result = AppExternalStatusPublished case entity.StUnpublished: switch unPubType { case entity.TypeUnpublishedByDev: result = AppExternalStatusUnpublishedByDev case entity.TypeUnpublishedByAdmin: result = AppExternalStatusUnpublishedByAdmin case entity.TypeUnpublishedDueToNewSeq: result = AppExternalStatusUnpublishedByNewSeq } } return result } /* * 第一优先级:AppID 为已上架 ,则可继续使用;如下架则全部不允许使用 * 第二优先级: * 当AppID上架的情况下,MD5对应 已上架 / 系统下架,则允许继续使用; * 如对应状态为在途(审核中/审核已撤销)的,则向下轮询3个序列号,如果3个序列号中包含 已上架/系统下架,则允许使用;如3个序列号均为在途状态,则返回不可用 * 如为其他状态(不在上述内容内),则返回不可用 */ func (as *AppService) AppVerIsValid(appVers []entity.AppVersion) bool { valid := false for _, appVerInfo := range appVers { if appVerInfo.Status.Value == entity.StPublishing || appVerInfo.Status.Value == entity.StPublishWithdrawed { continue } //首先判断该版本是否可用 if appVerInfo.Status.Value != entity.StPublished && appVerInfo.Status.Value != entity.StUnpublished { log.Errorf("app ver info invalid,app ver:%+v", appVerInfo) valid = false break } log.Debugf("get app ver info status:%+v", appVerInfo.Status) //判断该版本下架方式:被运营端下架、被机构端下架、新版本下架 if appVerInfo.Status.Value == entity.StUnpublished { if appVerInfo.UnpublishedStatus.Type == entity.TypeUnpublishedDueToNewSeq { valid = true break } } if appVerInfo.Status.Value == entity.StPublished { valid = true break } } log.Debugf("valid:[%v],appvers:%v", valid, appVers) return valid } func (as *AppService) GenOfflinePackageInfo(ctx context.Context, appId string, seq int, userId string) (string, error) { userInfo, err := hCaller.GetAccountInfo(ctx, userId) if err != nil { log.Errorf("GenOfflinePackageInfo GetDeveloperInfo err:%s", err.Error()) return "", err } appVerInfo, err := as.appRepo.GetAppVerInfo(ctx, appId, seq) if err != nil { log.Errorf("GenOfflinePackageInfo db err:%s", err.Error()) return "", err } if userInfo.OrganId != appVerInfo.GroupID { log.Errorf("GenOfflinePackageInfo organ id no match app ver info group id") return "", errors.New("group id not match") } //文件生成 if len(appVerInfo.CustomData.SourceFile) == 0 { log.Errorf("GenOfflinePackageInfo CustomData.SourceFile empty!") return "", errors.New("db info err") } //miniprogram.json groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appVerInfo.GroupID) if err != nil { log.Errorf("get group info err:%s", err.Error()) return "", err } miniprogramInfo := covertAppVerToRuleEngineRsp(&appVerInfo) //获取域名 domainData, err := hCaller.GetDomainInfoByOrganId(ctx, appVerInfo.GroupID) if err != nil { log.Errorf("InternalGetAppVerInfo ger domain info err:%s", err.Error()) return "", err } err, _, customData := ConvertModelCustomDataToRpc(ctx, appVerInfo.GroupID, appVerInfo.CustomData, domainData, "cache") if err != nil { log.Errorf("covertCacheInfoToRsp ConvertModelCustomDataToRpc err:[%s]", err.Error()) return "", err } wechatLoginInfo, err := hCaller.GetWeChatLoginInfo(ctx, appId) if err != nil { log.Errorf("covertCacheInfoToRsp ConvertModelCustomDataToRpc err:[%s]", err.Error()) return "", err } miniprogramInfo.CustomData = *customData miniprogramInfo.GroupName = groupInfo.GroupName //附加 miniprogramInfo.NeedCrt = domainData.NeedCrt miniprogramInfo.WechatLoginInfo = *wechatLoginInfo sourceFile := appVerInfo.CustomData.SourceFile[0] miniprogramJsonRsp := gin.H{ "error": "OK", "errcode": "", "data": miniprogramInfo, } dir := path.Join("/opt/finclip-offline-packages/", bson.NewObjectId().Hex()) fileDir := path.Join(dir, appVerInfo.AppID) err = os.MkdirAll(fileDir, os.ModePerm) if err != nil { log.Errorf("mkdir err:%s", err.Error()) return "", err } defer os.RemoveAll(dir) miniprogramJsonFileName := path.Join(fileDir, "miniprogram.json") log.Debugf("file dir:%s", fileDir) miniprogramJsonFile, err := os.OpenFile(miniprogramJsonFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { log.Errorf("open file err:%s", err.Error()) return "", err } defer miniprogramJsonFile.Close() miniprogramJsonByte, _ := json.Marshal(miniprogramJsonRsp) _, err = miniprogramJsonFile.Write(miniprogramJsonByte) if err != nil { log.Errorf("write file err:%s", err.Error()) return "", err } var fileList = make([]string, 0) fileList = append(fileList, miniprogramJsonFileName) log.Debugf("sourceFile:%+v", sourceFile) if len(sourceFile.EncryptPackages) > 0 { //分包 //分包小程序存储位置 splitPackFileDir := path.Join(fileDir, "miniprogram") log.Debugf("splitPackFileDir:%s", splitPackFileDir) err = os.Mkdir(splitPackFileDir, os.ModePerm) if err != nil { log.Errorf("mkdir splitPackFileDir err:%s", err.Error()) return "", err } //下载多个包 splitPackFileList := make([]string, 0) for _, p := range sourceFile.EncryptPackages { tempList := strings.Split(p.FileUrl, "/") fileBody, err := hCaller.DownloadByNetdiskId(ctx, tempList[len(tempList)-1]) if err != nil { log.Errorf("download file err:%s", err.Error()) return "", err } fName := path.Join(splitPackFileDir, p.Filename) tempFile, err := os.Create(fName) if err != nil { log.Errorf("create splitPackFileDir err:%s", err.Error()) return "", err } _, err = tempFile.Write(fileBody) if err != nil { log.Errorf("tempFile write err:%s", err.Error()) return "", err } tempFile.Close() splitPackFileList = append(splitPackFileList, fName) } //压缩之后再删除源文件 miniprogramZipFileName := path.Join(fileDir, "miniprogram.zip") err = ZipList(splitPackFileList, miniprogramZipFileName) if err != nil { log.Errorf("splitPackFileDir zip err:%s", err.Error()) return "", err } err = os.RemoveAll(splitPackFileDir) if err != nil { log.Errorf("splitPackFileDir remove err:%s", err.Error()) return "", err } fileList = append(fileList, miniprogramZipFileName) } else { //整包 var fileUrl = sourceFile.SourceFileUrl if sourceFile.EncryptedUrl != "" { fileUrl = sourceFile.EncryptedUrl } if fileUrl == "" { log.Errorf("file url empty,appId:[%s],sequence:[%d]", appId, seq) return "", errors.New("db info err") } fileBody, err := hCaller.DownloadByNetdiskId(ctx, getFileId(fileUrl)) if err != nil { log.Errorf("download file err:%s", err.Error()) return "", err } appFileName := path.Join(fileDir, "app.zip") //appFileName := path.Join(fileDir, "miniprogram.zip") appFile, err := os.OpenFile(appFileName, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { log.Errorf("one packege open err:%s", err.Error()) return "", err } _, err = appFile.Write(fileBody) appFile.Close() if err != nil { log.Errorf("one packege write file err:%s", err.Error()) return "", err } //再将小程序包压缩为miniprogram.zip miniprogramZipFileName := path.Join(fileDir, "miniprogram.zip") err = ZipList([]string{appFileName}, miniprogramZipFileName) if err != nil { log.Errorf("zip app file err:%s", err.Error()) return "", err } os.Remove(appFileName) fileList = append(fileList, miniprogramZipFileName) } encryptPwd := utils.GenMd5("miniprogram" + appVerInfo.AppID) log.Debugf("encryptPwd:%s", encryptPwd) encryptFileName := fileDir + ".zip" //err = EncryptZip(fileDir, encryptFileName, encryptPwd) err = EncryptList(fileList, encryptFileName, encryptPwd) if err != nil { log.Errorf("EncryptZip err:%s", err.Error()) return "", err } encryptFile, err := os.Open(encryptFileName) if err != nil { log.Errorf("open file err:%s", err.Error()) return "", err } resultUrl, err := hCaller.Upload(ctx, appVerInfo.AppID+".zip", encryptFile, false) if err != nil { log.Errorf("upload err:%s", err.Error()) return "", err } log.Debugf("upload id:%s", resultUrl) return getFileId(resultUrl), nil } func (as *AppService) GetAppClassList(ctx context.Context) ([]entity.CItem, error) { appClassList, err := as.appRepo.GetAppClassList(ctx) if err != nil { return make([]entity.CItem, 0), err } return appClassList, err } func (as *AppService) GetAppTagList(ctx context.Context) ([]entity.TagItem, error) { appTagList, err := as.appRepo.GetAppTagList(ctx) if err != nil { return make([]entity.TagItem, 0), err } return appTagList, err } func (as *AppService) SavePrivacySetting(ctx context.Context, req apiproto.PrivacySettingReq) error { info := entity.PrivacySettingInfo{} info.AppId = req.AppId /*userMessageTypeObj:=entity.UserMessageTypeObj{} userMessageTypeObj.UserMes=req.UserMessageType.UserMes userMessageTypeObj.LocationMes=req.UserMessageType.LocationMes userMessageTypeObj.Microphone=req.UserMessageType.Microphone userMessageTypeObj.Camera=req.UserMessageType.Camera userMessageTypeObj.EquipmentMes=req.UserMessageType.EquipmentMes userMessageTypeObj.AddressBook=req.UserMessageType.AddressBook userMessageTypeObj.PhotoAlbum=req.UserMessageType.PhotoAlbum userMessageTypeObj.Calendar=req.UserMessageType.Calendar userMessageTypeObj.OperationLog=req.UserMessageType.OperationLog userMessageTypeObj.Bluetooth=req.UserMessageType.Bluetooth userMessageTypeObj.Others=req.UserMessageType.Others*/ info.CommitType = req.CommitType info.UserMessageType = utility.InterfaceToJsonString(req.UserMessageType) info.SdkMessage = utility.InterfaceToJsonString(req.SdkMessage) info.ContactInfoEmail = req.ContactInfo.Email info.ContactInfoPhone = req.ContactInfo.Phone info.ContactInfoWeChat = req.ContactInfo.WeChat info.ContactInfoOther = req.ContactInfo.Other info.AdditionalDocName = req.AdditionalDocName info.AdditionalDocNetDiskId = req.AdditionalDocNetDiskId info.IsFirstSave = false info.AdditionalDocContent = req.AdditionalDocContent info.FixedStorageTime = req.FixedStorageTime info.EffectiveTime = time.Now().UnixNano() / 1e6 info.CreateTime = time.Now().UnixNano() / 1e6 info.UpdateTime = time.Now().UnixNano() / 1e6 total, err := as.prviacySettingRepo.Count(ctx, req.AppId) if err != nil { log.Errorf("PrviacySettingRepo Count err:%s", err.Error()) return err } if total > 0 { err := as.prviacySettingRepo.UpdateInfo(ctx, info) if err != nil { log.Errorf("PrviacySettingRepo insert err:%s", err.Error()) return err } } else { err := as.prviacySettingRepo.Insert(ctx, info) if err != nil { log.Errorf("PrviacySettingRepo insert err:%s", err.Error()) return err } } appInfo, err := as.appRepo.GetAppInfo(ctx, req.AppId) if err != nil { log.Errorf("as.appRepo.GetAppVerInfo err:%s", err.Error()) if repository.NotFound(err) { log.Errorf("DevPublishApp get appVer not found!") return err } } appInfo.PrivacySettingType = req.CommitType err = as.appRepo.UpdateApp(ctx, appInfo) if err != nil { log.Errorf("UpdateAppIsPrivacySetting repo err:%s", err.Error()) return err } return nil } type GetPrivacySettingInfoRsp struct { AppId string `json:"appId"` CommitType int `json:"commitType"` //提交类型 //1:本小程序开发者承诺并保证,未以任何方式处理用户的任何信息。如后续有处理用户信息,会及时更新《小程序隐私保护指引》 2:本小程序处理了用户信息,将如实填写并及时更新用户信息处理情况 UserMessageType entity.UserMessageTypeObj `json:"userMessageType"` //用户使用类型 SdkMessage []entity.SdkMessageInfoObj `json:"sdkMessage"` //sdk信息 ContactInfo entity.ContactInfoObj `json:"contactInfo"` //联系方式 FixedStorageTime int `json:"fixedStorageTime"` //固定存储时间 IsShortestTime bool `json:"isShortestTime"` //是否是最短时间 AdditionalDocName string `json:"additionalDocName"` //补充文档名称 AdditionalDocContent string `json:"additionalDocContent"` //补充文档内容 AdditionalDocNetDiskId string `json:"additionalDocNetDiskId"` //补充文档网盘id IsFirstSave bool `json:"isFirstSave"` EffectiveTime int64 `json:"effectiveTime"` CreateTime int64 `json:"createTime"` UpdateTime int64 `json:"updateTime"` } func (as *AppService) GetPrivacySettingInfo(ctx context.Context, appId string) (GetPrivacySettingInfoRsp, error) { rsp := GetPrivacySettingInfoRsp{} item, err := as.prviacySettingRepo.GetInfoByAppId(ctx, appId) if err != nil { log.Errorf("PrviacySettingRepo insert err:%s", err.Error()) if NotFound(err) { rsp.IsFirstSave = true return rsp, nil } return rsp, err } rsp.AppId = item.AppId rsp.FixedStorageTime = item.FixedStorageTime rsp.IsShortestTime = item.IsShortestTime var userMessageTypeObj entity.UserMessageTypeObj json.Unmarshal([]byte(item.UserMessageType), &userMessageTypeObj) rsp.UserMessageType = userMessageTypeObj var sdkMessage []entity.SdkMessageInfoObj json.Unmarshal([]byte(item.SdkMessage), &sdkMessage) rsp.SdkMessage = sdkMessage rsp.CommitType = item.CommitType rsp.ContactInfo.Phone = item.ContactInfoPhone rsp.ContactInfo.Email = item.ContactInfoEmail rsp.ContactInfo.WeChat = item.ContactInfoWeChat rsp.ContactInfo.Other = item.ContactInfoOther rsp.AdditionalDocNetDiskId = item.AdditionalDocNetDiskId rsp.AdditionalDocName = item.AdditionalDocName rsp.IsFirstSave = item.IsFirstSave rsp.AdditionalDocContent = item.AdditionalDocContent rsp.EffectiveTime = item.EffectiveTime rsp.CreateTime = item.CreateTime rsp.UpdateTime = item.UpdateTime return rsp, nil } func (as *AppService) DelPrivacySettingInfo(ctx context.Context, appId string) error { err := as.prviacySettingRepo.DelInfoByAppId(ctx, appId) if err != nil { log.Errorf("PrviacySettingRepo DelInfoByAppId err:%s", err.Error()) return err } appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Errorf("as.appRepo.GetAppVerInfo err:%s", err.Error()) return err } appInfo.PrivacySettingType = 1 err = as.appRepo.UpdateApp(ctx, appInfo) if err != nil { log.Errorf("UpdateAppIsPrivacySetting repo err:%s", err.Error()) return err } return nil } type InternalGetPrivacySettingInfoRsp struct { AppId string `json:"appId"` AppName string `json:"appName"` OrganName string `json:"organName"` CommitType int `json:"commitType"` //提交类型 //1:本小程序开发者承诺并保证,未以任何方式处理用户的任何信息。如后续有处理用户信息,会及时更新《小程序隐私保护指引》 2:本小程序处理了用户信息,将如实填写并及时更新用户信息处理情况 UserMessageType entity.UserMessageTypeObj `json:"userMessageType"` //用户使用类型 SdkMessage []entity.SdkMessageInfoObj `json:"sdkMessage"` //sdk信息 ContactInfo entity.ContactInfoObj `json:"contactInfo"` //联系方式 FixedStorageTime int `json:"fixedStorageTime"` //固定存储时间 IsShortestTime bool `json:"isShortestTime"` //是否是最短时间 AdditionalDocName string `json:"additionalDocName"` //补充文档名称 AdditionalDocNetDiskId string `json:"additionalDocNetDiskId"` //补充文档网盘id AdditionalDocContent string `json:"additionalDocContent"` //补充文档内容 IsFirstSave bool `json:"isFirstSave"` EffectiveTime int64 `json:"effectiveTime"` CreateTime int64 `json:"createTime"` UpdateTime int64 `json:"updateTime"` } func (as *AppService) InternalGetPrivacySettingInfo(ctx context.Context, appId string) (InternalGetPrivacySettingInfoRsp, error) { rsp := InternalGetPrivacySettingInfoRsp{} /*appVerInfo, err := as.appRepo.GetOnlineAppVer(ctx, appId) if err != nil { log.Debugf("getApp GetOnlineAppVer err:%s", err.Error()) if !NotFound(err) { log.Errorf("getApp err:%s", err.Error()) return rsp, err } }*/ appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Debugf("getApp err:%s", err.Error()) if !NotFound(err) { log.Errorf("getApp err:%s", err.Error()) return rsp, err } } groupInfo, err := hCaller.GetGroupInfoByGroupId(ctx, appInfo.GroupID) log.Infof("get groupInfo error:%+v,groupInfo:%+v", err, groupInfo) if err != nil { log.Errorf("InternalGetAppVerInfo ger group info err:%s", err.Error()) return rsp, err } item, err := as.prviacySettingRepo.GetInfoByAppId(ctx, appId) if err != nil { log.Errorf("PrviacySettingRepo insert err:%s", err.Error()) return rsp, err } rsp.AppName = appInfo.Name rsp.OrganName = groupInfo.GroupName rsp.AppId = item.AppId rsp.FixedStorageTime = item.FixedStorageTime rsp.IsShortestTime = item.IsShortestTime var userMessageTypeObj entity.UserMessageTypeObj json.Unmarshal([]byte(item.UserMessageType), &userMessageTypeObj) rsp.UserMessageType = userMessageTypeObj var sdkMessage []entity.SdkMessageInfoObj json.Unmarshal([]byte(item.SdkMessage), &sdkMessage) rsp.SdkMessage = sdkMessage rsp.CommitType = item.CommitType rsp.AdditionalDocContent = item.AdditionalDocContent rsp.ContactInfo.Phone = item.ContactInfoPhone rsp.ContactInfo.Email = item.ContactInfoEmail rsp.ContactInfo.WeChat = item.ContactInfoWeChat rsp.ContactInfo.Other = item.ContactInfoOther rsp.AdditionalDocNetDiskId = item.AdditionalDocNetDiskId rsp.AdditionalDocName = item.AdditionalDocName rsp.IsFirstSave = item.IsFirstSave rsp.EffectiveTime = item.EffectiveTime rsp.CreateTime = item.CreateTime rsp.UpdateTime = item.UpdateTime return rsp, nil } type InternalGetAppSearchDataInfoRsp struct { AppId string `json:"appId"` //小程序Id GroupID string `json:"groupId"` Resource string `json:"resource"` //小程序源码地址 AppName string `json:"appName"` //小程序名称 OrganName string `json:"organName"` //机构名称 AppDesc string `json:"appDesc"` //小程序简介 SdkKeys []string `json:"sdkKeys"` //sdk关联列表 AppTag string `json:"appTag"` AppClass string `json:"appClass"` } func (as *AppService) InternalGetAppSearchDataInfo(ctx context.Context, appId string) (InternalGetAppSearchDataInfoRsp, error) { rsp := InternalGetAppSearchDataInfoRsp{} appInfo, err := as.appRepo.GetAppInfo(ctx, appId) if err != nil { log.Debugf("getApp GetAppInfo err:%s", err.Error()) if !NotFound(err) { log.Errorf("getApp err:%s", err.Error()) return rsp, err } } appVerInfo, err := as.appRepo.GetOnlineAppVer(ctx, appId) if err != nil { log.Debugf("getApp GetOnlineAppVer err:%s", err.Error()) if !NotFound(err) { log.Errorf("getApp err:%s", err.Error()) return rsp, err } } appTagInfo, err := hCaller.GetAppTagConfigInfo(ctx) if err != nil { log.Errorln("appTagInfo error:%s", err.Error()) return rsp, err } //log.Debugln("appTagInfo:", appTagInfo.Data.AppTag) appTagStr := "" if len(appVerInfo.AppTag) > 0 { log.Debugln("AppTag:", appVerInfo.AppTag) for _, v := range appVerInfo.AppTag { for _, tag := range appTagInfo.Data.AppTag { if v == tag.Key { appTagStr += tag.Name + "," log.Debugln("appTagStr", appTagStr) } } } if len(appTagStr) > 0 { appTagStr = appTagStr[0 : len(appTagStr)-1] } } appClassStr := "" if len(appVerInfo.AppTag) > 0 { for _, v := range appTagInfo.Data.AppClass { if v.Key == appVerInfo.AppClass { appClassStr = v.Name } } } bindRepo := impl.InitBindingRepo() result, err := bindRepo.GetAllAssBinds(ctx, appId) if err != nil { log.Errorf("notifySpiderPubApp err:%s", err.Error()) return rsp, err } var sdkKeyListMap = make(map[string]bool, 0) var sdkKeyList = make([]string, 0) for _, v := range result { for _, sdkKeyInfo := range v.BundleInfos { if sdkKeyInfo.IsForbidden == 0 { if _, ok := sdkKeyListMap[sdkKeyInfo.SDKKey]; !ok { sdkKeyListMap[sdkKeyInfo.SDKKey] = true } } } } for k, _ := range sdkKeyListMap { sdkKeyList = append(sdkKeyList, k) } rsp.AppId = appInfo.AppID rsp.GroupID = appVerInfo.GroupID rsp.Resource = appVerInfo.CustomData.SourceFile[0].SourceFileUrl rsp.AppName = appInfo.Name rsp.AppDesc = appVerInfo.CoreDescription rsp.AppTag = appTagStr rsp.AppClass = appClassStr rsp.SdkKeys = sdkKeyList return rsp, nil } type AppObject struct { AppId string `json:"appId"` //小程序Id AppName string `json:"appName"` //小程序名称 Logo string `json:"logo"` } type InternalGetAppInfoBySearchTextRsp struct { AppInfo []AppObject `json:"appInfo"` } func (as *AppService) InternalGetAppInfoBySearchText(ctx context.Context, searchText string) (InternalGetAppInfoBySearchTextRsp, error) { rsp := InternalGetAppInfoBySearchTextRsp{} result, err := as.appRepo.GetAppsBySearchText(ctx, searchText) if err != nil { log.Debugf("getApp GetAppsBySearchText err:%s", err.Error()) return rsp, err } for _, v := range result { item := AppObject{} item.AppId = v.AppID item.Logo = v.Logo item.AppName = v.Name rsp.AppInfo = append(rsp.AppInfo, item) } return rsp, nil } func EncryptZip(src, dst, passwd string) error { zipfile, err := os.Create(dst) if err != nil { return err } defer zipfile.Close() archive := ezip.NewWriter(zipfile) defer archive.Close() err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if err != nil { return err } header, err := ezip.FileInfoHeader(info) if err != nil { return err } header.Name = strings.TrimPrefix(path, filepath.Dir(src)+"/") //if info.IsDir() { // header.Name += "/" //} else { // header.Method = zip.Deflate //} // 设置密码 header.Method = zip.Deflate header.SetPassword(passwd) writer, err := archive.CreateHeader(header) if err != nil { return err } if !info.IsDir() { file, err := os.Open(path) if err != nil { return err } defer file.Close() _, err = io.Copy(writer, file) } return err }) archive.Flush() return err } func Zip(pathToZip, destinationPath string) error { destinationFile, err := os.Create(destinationPath) if err != nil { return err } myZip := zip.NewWriter(destinationFile) err = filepath.Walk(pathToZip, func(filePath string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if err != nil { return err } relPath := strings.TrimPrefix(filePath, filepath.Dir(pathToZip)) zipFile, err := myZip.Create(relPath) if err != nil { return err } fsFile, err := os.Open(filePath) if err != nil { return err } _, err = io.Copy(zipFile, fsFile) if err != nil { return err } return nil }) if err != nil { return err } err = myZip.Close() if err != nil { return err } return nil } func ZipList(fileList []string, destinationPath string) error { fmt.Println(fileList) destinationFile, err := os.Create(destinationPath) if err != nil { return err } myZip := zip.NewWriter(destinationFile) for _, fileName := range fileList { f, err := os.Open(fileName) if err != nil { return err } fInfo, err := f.Stat() if err != nil { return err } if fInfo.IsDir() { return fmt.Errorf("file:[%s] is dir", fileName) } _, name := filepath.Split(fileName) zipFile, err := myZip.Create(name) if err != nil { return err } fsFile, err := os.Open(fileName) if err != nil { return err } _, err = io.Copy(zipFile, fsFile) if err != nil { return err } } err = myZip.Close() if err != nil { return err } return nil } func EncryptList(fileList []string, dst, passwd string) error { fmt.Println(fileList) zipfile, err := os.Create(dst) if err != nil { return err } defer zipfile.Close() archive := ezip.NewWriter(zipfile) defer archive.Close() for _, fileName := range fileList { fmt.Println("fileName:", fileName) f, err := os.Open(fileName) if err != nil { return err } fInfo, err := f.Stat() if err != nil { return err } if fInfo.IsDir() { return fmt.Errorf("file:[%s] is dir", fileName) } header, err := ezip.FileInfoHeader(fInfo) if err != nil { return err } _, name := filepath.Split(fileName) header.Name = name fmt.Println("header.Name:", header.Name) header.Method = zip.Deflate header.SetPassword(passwd) writer, err := archive.CreateHeader(header) if err != nil { return err } file, err := os.Open(fileName) if err != nil { return err } _, err = io.Copy(writer, file) file.Close() } archive.Flush() return err } func getFileId(fileUrl string) string { tempList := strings.Split(fileUrl, "/") return tempList[len(tempList)-1] }