Repository: zhiyuancui/Creative-AIGC-Suite Branch: master Commit: 31fd7b455c60 Files: 34 Total size: 54.2 KB Directory structure: gitextract_u35ah_ff/ ├── .gitignore ├── LICENSE ├── README.md ├── app/ │ ├── application/ │ │ ├── consts.go │ │ ├── initclient.go │ │ ├── rpc.go │ │ └── tcc.go │ └── initclient.go ├── application/ │ ├── .gitkeep │ └── service/ │ ├── campaign/ │ │ ├── brief.go │ │ ├── util.go │ │ └── validation.go │ ├── global_framework/ │ │ ├── add_on.go │ │ └── service_package.go │ └── util.go ├── biz/ │ └── fsm/ │ ├── callback/ │ │ ├── charging_callback.go │ │ ├── notification_callback.go │ │ ├── order_logging_callback.go │ │ └── rpc_callback.go │ └── factory/ │ ├── bfsm_factory.go │ ├── callback.go │ ├── config.go │ └── trigger.go ├── build.sh ├── db/ │ └── custom/ │ ├── collaboration_campaign_info.go │ └── collaboration_partner_campaign.go ├── domain/ │ └── campaign/ │ ├── campaign_aggregate/ │ │ ├── entity/ │ │ │ └── campaign.go │ │ └── repository/ │ │ └── brief.go │ └── service/ │ ├── campaign_impl.go │ ├── init.go │ └── service.go ├── go.mod ├── go.sum └── rpc/ └── bc_rpc.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /bin/ .idea/ *.iml ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Memo Chou Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## Creative AIGC Suite ### Summary Creativity is a crucial factor in the success of streaming media, and advancements in Generative AI are making content creation more accessible, efficient, and seamless. These innovations empower creators to produce meaningful content at scale. Generative AI refers to AI-powered systems and models that generate new content—such as audio, images, text, and videos—also known as AI-Generated Content (AIGC). This project features the latest Generative AI products, capabilities, and solutions to help your clients and partners elevate creative productivity. ### What is Creative AIGC Suite? Creative AIGC Suite is a powerful suite of generative AI solutions designed to enhance your content creation journey. From scriptwriting to video production and asset optimization, Creative AIGC Suite streamlines every step, making content creation effortless and efficient—helping businesses produce impactful content that drives success. Built specifically for branded content, Creative AIGC Suite empowers brands to: * Democratize creativity – Simplifying the creative process from concept to execution, making high-quality content creation more accessible. * Maximize efficiency – Leveraging generative AI to scale content production, enable hyper-personalization, and facilitate continuous iteration. * Unlock strategic insights – Going beyond content generation to identify cultural and industry trends, extract campaign learnings, and refine creative strategies for better decision-making. ### Creative AI Assistant Creative Assistant is a virtual assistant designed to collaborate intelligently with to shape creative direction. Drawing from extensive creative expertise, it provides valuable insights, inspiration, script generation and refinement, best practices, and tailored solution recommendations—empowering users to produce high-quality, impactful content with ease. ### Creative Studio Creative Studio is an AI-powered video generation platform that transforms minimal user input into high-quality videos in minutes. Easily convert product information or a URL into a compelling video, enhance storytelling with a digital avatar narrating your script, and expand your reach by localizing content through AI-driven translation and dubbing capabilities. ### Build ```shell script ./build.sh ``` ## License [MIT](LICENSE) ================================================ FILE: app/application/consts.go ================================================ package app ================================================ FILE: app/application/initclient.go ================================================ package app import ( "gorm.io/gorm" ) var ( RedisCli *redis.Client CreativeDBCli *gorm.DB EsCli *es.Client //DynamicConfigGetter = &DynamicConfig{} NotificationSendProducer eventbus.Producer RmqProducer *rocket.Producer ) func InitClients() { //initRedis() //// initEs() initCreativeDB() initProducer() initRocketMQ() //initRPC() //initTCC() } func initCreativeDB() { var err error dbConfig := &ServiceConf.CreativeDB CreativeDBCli, err = mysql.NewClient(dbConfig) if err != nil { panic(err) } } func initRocketMQ() { var err error RmqProducer, err = rocket.NewProducer(&ServiceConf.TTCXNotificationProducer) if err != nil { panic(err) } } func initProducer() { var err error if !strings.IsBlank(ServiceConf.NotificationSendProducer.EventName) && !env.IsBoe() { NotificationSendProducer, err = eventbus2.NewProducer(&ServiceConf.NotificationSendProducer) if err != nil { panic(err) } } } func CloseProducer() { if NotificationSendProducer != nil { _ = NotificationSendProducer.Close() } } ================================================ FILE: app/application/rpc.go ================================================ package app var () func initRPC() { } ================================================ FILE: app/application/tcc.go ================================================ package app // //import ( // "code.byted.org/gopkg/confx" //) // //func initTCC() { // err := confx.Init(DynamicConfigGetter) // if err != nil { // panic(err) // } //} // //type DynamicConfig struct{} ================================================ FILE: app/initclient.go ================================================ package app import ( "gorm.io/gorm" ) var ( RedisCli *redis.Client CreativeDBCli *gorm.DB EsCli *es.Client DynamicConfigGetter = &DynamicConfig{} ) func InitClients() { initRedis() initEs() initCreativeDB() initProducer() initRPC() initTCC() } func initRedis() { var err error RedisCli, err = redis.NewClient(&ServiceConf.Redis) if err != nil { panic(err) } } func initDB() { var err error dbConfig := &ServiceConf.CreativeDB CreativeDBCli, err = mysql.NewClient(dbConfig) if err != nil { panic(err) } } func initProducer() { var err error if !strings.IsBlank(ServiceConf.NotificationSendProducer.EventName) && !env.IsBoe() { NotificationSendProducer, err = eventbus2.NewProducer(&ServiceConf.NotificationSendProducer) if err != nil { panic(err) } } } func CloseProducer() { if NotificationSendProducer != nil { _ = NotificationSendProducer.Close() } } ================================================ FILE: application/.gitkeep ================================================ ================================================ FILE: application/service/campaign/brief.go ================================================ package campaign import ( "context" "sort" "strconv" "time" ) func ClientDraftCampaignDetail(ctx context.Context, aioClientID int64, campaignID int64) (resp *rpcClientCampaignDraftDetailResp, err error) { resp = &rpcClientCampaignDraftDetailResp{BaseResp: base.NewBaseResp()} if aioClientID == 0 || campaignID == 0 { err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "Invalid input").WithStack() return } briefModel, err := custom.GetCampaignDraftByID(ctx, campaignID, aioClientID) if err != nil { logs.CtxError(ctx, "fail to get campaign draft of campaign id %d with err: %+v", campaignID, err) err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "Invalid input").WithStack() return } campaignInfo, err := service.ConvertBriefModelToCampaignResp(ctx, briefModel, nil) if err != nil { err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to convert").WithStack() return } resp.SetCampaignInfo(campaignInfo) return } func ClientCreateCampaignDraft(ctx context.Context, req *rpcClientCreateCampaignDraftReq) (resp *rpcClientCreateCampaignDraftResp, err error) { resp = &rpcClientCreateCampaignDraftResp{BaseResp: base.NewBaseResp()} if req.GetCampaignInfo() == nil { logs.CtxError(ctx, "campaign draft info is null") err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "empty campaign").WithStack() return } req.GetCampaignInfo().SetBriefID(nil) req.GetCampaignInfo().SetCampaignID(nil) briefID, ttoCampaignID, updatedAt, err := ClientCreateUpdateCampaignDraft(ctx, req.GetCampaignInfo(), req.GetParam(), req.GetAioClientID(), req.GetCoreUserID()) if err != nil { err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to create draft").WithStack() return } resp.SetBriefID(briefID) resp.SetCampaignID(ttoCampaignID) resp.SetUpdatedAt(updatedAt.Unix()) return } func ClientUpdateCampaignDraft(ctx context.Context, req *rpcClientUpdateCampaignDraftReq) (resp *rpcClientUpdateCampaignDraftResp, err error) { resp = &rpcClientUpdateCampaignDraftResp{BaseResp: base.NewBaseResp()} briefID, ttoCampaignID, updatedAt, err := ClientCreateUpdateCampaignDraft(ctx, req.GetCampaignInfo(), req.GetParam(), req.GetAioClientID(), req.GetCoreUserID()) if err != nil { err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to update draft").WithStack() return } resp.SetBriefID(briefID) resp.SetCampaignID(ttoCampaignID) resp.SetUpdatedAt(updatedAt.Unix()) return } func ClientCreateUpdateCampaignDraft(ctx context.Context, campaign *rpcCampaignInfo, param *common_param.ClientCommonParam, aioClientID int64, coreUserID int64) (briefID int64, ttoCampaignID int64, updatedAt time.Time, err error) { campaign.SetAioClientID(&aioClientID) campaign.SetCoreUserID(&coreUserID) //TODO: wrap to separate method if len(campaign.CampaignName) == 0 { err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "invalid brief").WithStack() return } var createCampaign = campaign.GetCampaignID() == 0 if campaign.GetCampaignID() != 0 { existingBrief, err := custom.GetCampaignDraftByID(ctx, campaign.GetCampaignID(), campaign.GetAioClientID()) if err == nil { createCampaign = false campaign.SetBriefID(gptr.Of(existingBrief.ID)) } } briefModel := service.ConvertCampaignEntityToBriefModel(ctx, campaign, param) q := query.Session(clients.LegoDBCli) err = q.Transaction(func(tx *query.Query) error { if createCampaign { ttoCampaignID, err = RPC.ClientCreateCampaignDraft(ctx, campaign, param.IsTest) if err != nil { logs.CtxError(ctx, "fail to create campaign in tto with err: %+v", err) err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to create/update tto campaign draft").WithStack() return err } briefModel.TtoCampaignID = ttoCampaignID } else { ttoCampaignID = briefModel.TtoCampaignID err = RPC.ClientUpdateCampaignDraft(ctx, briefModel.TtoCampaignID, campaign, param.IsTest) if err != nil { logs.CtxError(ctx, "fail to create campaign in tto with err: %+v", err) err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to create/update tto campaign draft").WithStack() return err } } err = custom.CreateUpdateCampaignDraft(ctx, tx, briefModel) if err != nil { logs.CtxError(ctx, "fail to update/create brief with err: %+v", err) err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to update/create brief").WithStack() return err } err = RPC.InnerUpdatetCampaign(ctx, aioClientID, briefModel.TtoCampaignID, nil, &briefModel.ID, nil, &briefModel.OrderName, nil) if err != nil { logs.CtxError(ctx, "fail to sync campaign %d in tto, err: %+v", briefModel.TtoCampaignID, err) err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to sync tto campaign draft").WithStack() return err } return nil }) if err != nil { return } briefModel, err = custom.GetCampaignDraftByBriefID(ctx, briefModel.ID) if err != nil { updatedAt = time.Now() } else { updatedAt = briefModel.UpdatedAt } return briefModel.ID, ttoCampaignID, updatedAt, nil } func ClientSubmitCampaign(ctx context.Context, req *rpcClientSubmittCampaignReq) (resp *rpcClientSubmittCampaignResp, err error) { resp = &rpcClientSubmittCampaignResp{BaseResp: base.NewBaseResp()} brief, err := custom.GetCampaignDraftByID(ctx, req.GetCampaignID(), req.GetAioClientID()) if err != nil { err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "Invalid input").WithStack() return } campaign, err := service.ConvertBriefModelToCampaignResp(ctx, brief, nil) if err != nil { return } if !service.CheckCampaignKeyField(ctx, campaign) { err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "Invalid input").WithStack() return } orderID, isTest, err := handlers.SubmitTTOCampaign(ctx, brief.ID, req.GetCoreUserID(), req.GetCouponID(), 0, true, req.Param.GetIsTest()) if err != nil && orderID == 0 { err = errors.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, "fail to submit campaign").WithStack() return } resp.SettOrderID(orderID) resp.SetIsTest(isTest) resp.SetCampaignID(brief.TtoCampaignID) return } func ClientCampaignIndustries(ctx context.Context) (resp *rpcClientCampaignIndustriesResp, err error) { resp = &rpcClientCampaignIndustriesResp{BaseResp: base.NewBaseResp()} industryConf := clients.DynamicConfigGetter.IndustryConf() var industries []*rpcIndustryConfig for _, item := range industryConf.FirstIndustries { industry := rpcIndustryConfig{ IndustryID: item.IndustryID, } industries = append(industries, &industry) } resp.SetIndustries(industries) return } func ClientCampaignLanguages(ctx context.Context, req *rpcClientCampaignLanguagesReq) (resp *rpcClientCampaignLanguagesResp, err error) { resp = &rpcClientCampaignLanguagesResp{BaseResp: base.NewBaseResp()} partnerInfos, err := RPC.PartnerGetProfileInfoList(ctx, req.GetRegion(), req.Param.GetIsTest(), 1, 1000) if err != nil { logs.CtxError(ctx, "[ClientCampaignLanguages], failed to get partner infos from es. error: %v", err) return } var languageMap = make(map[string]bool) for _, partner := range partnerInfos { if partner.FormData == nil || len(partner.FormData.CreativeSupportedLanguages) == 0 { continue } for _, language := range partner.FormData.CreativeSupportedLanguages { languageMap[language] = true } } var allLanguagesSupported []string for language := range languageMap { allLanguagesSupported = append(allLanguagesSupported, language) } sort.Strings(allLanguagesSupported) resp.SetLanguages(allLanguagesSupported) return } func ClientCampaignMarkets(ctx context.Context, req *rpcClientCampaignMarketsReq) (resp *rpcClientCampaignMarketsResp, err error) { resp = &rpcClientCampaignMarketsResp{BaseResp: base.NewBaseResp()} if req.GetRegion() == "" { return } rpcResp, err := rpc.GetBriefSupportedMarkets(ctx, req.GetRegion(), req.Param.GetIsTest()) if err != nil { return } markets := []*rpcSupportedRegionAndMarkets{} for _, item := range rpcResp.GetSupportedMarkets() { market := rpcSupportedRegionAndMarkets{ SupportedRegion: item.GetSupportedRegion(), Markets: item.GetMarkets(), } markets = append(markets, &market) } resp.SetSupportedMarkets(markets) return } func ClientCampaignAdvertiserInfo(ctx context.Context, req *rpcClientCampaignAdvertiserInfoReq) (resp *rpcClientCampaignAdvertiserInfoResp, err error) { resp = &rpcClientCampaignAdvertiserInfoResp{BaseResp: base.NewBaseResp()} if req.GetCoreUserID() == 0 { err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "Invalid input").WithStack() return } advAllowedInfo, isAllowed, err := qualification.IsAdvQualified(ctx, req.GetCoreUserID()) if err != nil { return } advList := []model.tAdvAccountInfo{} resp.SetRegion(gptr.Of("Unknown")) resp.SetIsWhitelisted(gptr.Of(false)) if isAllowed { advList, err = account.GetClientAdvInfo(ctx, req.GetCoreUserID(), req.GetNeedCouponInfo(), true, isAllowed, advAllowedInfo.Region) resp.SetRegion(&advAllowedInfo.Region) resp.SetIsWhitelisted(gptr.Of(true)) if err != nil { return } } else { advList, err = account.GetClientAdvInfo(ctx, req.GetCoreUserID(), req.GetNeedCouponInfo(), true, isAllowed, "") if err != nil { return } } if err = setIsJBPCoupon(ctx, advList); err != nil { return } if err = setCanSubmitSubscription(ctx, advList, req.GetCoreUserID()); err != nil { return } res := []*rpctAdvAccountInfo{} supportedRegions := []string{} for _, item := range advList { advInfo := rpctAdvAccountInfo{ Id: item.ID, Name: item.Name, HasCoupon: conv.BoolPtr(item.HasCoupon), IncentiveType: conv.Int32Ptr(int32(item.IncentiveType)), BaseRegion: conv.StringPtr(item.BaseRegion), IsJBP: conv.BoolPtr(item.IsJBP), CanSubmitSubscription: conv.BoolPtr(item.CanSubmitSubscription), } supportedRegions = append(supportedRegions, item.BaseRegion) res = append(res, &advInfo) } resp.SetSupportedGARegion(gslice.Uniq(supportedRegions)) resp.SetAccountInfo(res) return } func setIsJBPCoupon(ctx context.Context, advList []model.tAdvAccountInfo) error { advIDs := gslice.Map(advList, func(info model.tAdvAccountInfo) int64 { advID, err := strconv.ParseInt(info.ID, 10, 64) if err != nil { logs.CtxError(ctx, "parse AdvID error: %+v", err) } return advID }) advToCoupon := make(map[string][]*t.CreativeCoupon) for _, subAdvIDs := range gslice.Chunk(advIDs, 100) { couponMap, err := rpc.MGetAdvCouponList(ctx, subAdvIDs) if err != nil { return err } for key, value := range couponMap { advToCoupon[strconv.FormatInt(key, 10)] = value } } for i, adv := range advList { advList[i].IsJBP = len(advToCoupon[adv.ID]) > 0 } return nil } func setCanSubmitSubscription(ctx context.Context, advList []model.tAdvAccountInfo, coreUserId int64) error { GARegions := clients.DynamicConfigGetter.FeatureGARegions()["subscription"] allowedIdMap, err := rpc.GetAllObjectIdsInAllowList(ctx, core.AllowListModuleType_tGeneralModule, core.AllowListEntityType_Subscription, 0) if err != nil { logs.CtxError(ctx, "[CheckUserInAllowList] get all users in allowList for subscription failed, err: [%+v]", err) return bizerr.ErrInternalError } var baseRegion string advertiserInfo, _, err := qualification.IsAdvQualified(ctx, coreUserId) if err != nil { return err } for i, adv := range advList { if advertiserInfo != nil { baseRegion = advertiserInfo.Region } else { baseRegion = adv.BaseRegion } if gslice.Contains(GARegions, baseRegion) { advList[i].CanSubmitSubscription = true } else if _, ok := allowedIdMap[adv.ID]; ok { advList[i].CanSubmitSubscription = true } } return nil } func ClientRecommendPartner(ctx context.Context, req *rpcClientRecommendPartnerReq) (resp *rpcClientRecommendPartnerResp, err error) { resp = &rpcClientRecommendPartnerResp{BaseResp: base.NewBaseResp()} var ( recommendPartnerInfos []params.PartnerProfile preSelectedPartnerInfo *params.PreSelectedPartnerProfile ) if req.GetCampaignInfo() != nil && req.GetCampaignInfo().GettOrderID() != 0 { logs.CtxInfo(ctx, "[ClientRecommendPartner] advertiser reselect partner for campaign %d", req.GetCampaignInfo().CampaignID) orderID := req.GetCampaignInfo().GettOrderID() recommendPartnerInfos, preSelectedPartnerInfo, err = match_algo.GetRecommendProfilerImpl(ctx, orderID, false) if err != nil { logs.CtxError(ctx, "fail to get recommend partner for campaign %d with err: %+v", req.GetCampaignInfo().CampaignID, err) return } if preSelectedPartnerInfo != nil { resp.SetSelectedPartnerInfo(service.ConvertToSelectPartnerProfile(preSelectedPartnerInfo)) } resp.SetRecommendPartnerInfo(service.ConvertToPartnerProfile(recommendPartnerInfos)) return } if req.CampaignInfo == nil || req.CampaignInfo.Region == nil || req.CampaignInfo.AdvertiserID == nil || req.CampaignInfo.GetServicePackageID() == 0 || len(req.CampaignInfo.GetTargetMarkets()) == 0 || req.CampaignInfo.IndustryCategory == nil || len(req.CampaignInfo.Objective) == 0 || len(req.CampaignInfo.CreativeLanguages) == 0 { err = errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "Invalid input").WithStack() return } if req.CampaignInfo.GetRegion() == "CNOB" { return } addOnIds := []int64{} for _, item := range req.CampaignInfo.AddOns { addOnIds = append(addOnIds, item.GetId()) } objectives := []int64{} for _, item := range req.CampaignInfo.Objective { objectives = append(objectives, int64(item)) } formData := &core.BriefFormData{ AdvertiserId: req.CampaignInfo.AdvertiserID, TargetMarkets: req.CampaignInfo.TargetMarkets, CreativeLanguage: req.CampaignInfo.CreativeLanguages, ServicePackageId: req.CampaignInfo.ServicePackageID, IndustryCategory: req.CampaignInfo.IndustryCategory, Objective: objectives, SelectedPartnerId: req.CampaignInfo.SelectedPartnerID, } logs.CtxInfo(ctx, "[ClientRecommendPartner] ClientRecommendPartner request: [%+v]", req) recommendPartnerInfos, preSelectedPartnerInfo, err = match_algo.GetTTORecommendPartnersFromBriefImpl(ctx, false, addOnIds, req.GetIsFunded(), req.GetPreSelectedPartnerID(), req.GetCoreUserID(), req.Param.GetIsTest(), req.CampaignInfo.GetRegion(), formData) if err != nil { return } if preSelectedPartnerInfo != nil { resp.SetSelectedPartnerInfo(service.ConvertToSelectPartnerProfile(preSelectedPartnerInfo)) } resp.SetRecommendPartnerInfo(service.ConvertToPartnerProfile(recommendPartnerInfos)) return } ================================================ FILE: application/service/campaign/util.go ================================================ package campaign import ( "context" "code.byted.org/ad/creative_one_partner_business/domain/campaign/campaign_aggregate/entity" "code.byted.org/ad/creative_one_partner_business/kitex_gen/ad/creative_one/partner_business" ) func ConvertCampaignInfoToNewEntity(ctx context.Context, campaignInfo *partner_business.CampaignInfo, AIOClientID int64) (campaignEntity entity.ICampaignEntity, err error) { return nil, nil } func ConvertCampaignEntityToDTO(ctx context.Context, campaignEntity entity.ICampaignEntity) (campaignInfo *partner_business.CampaignInfo, err error) { return nil, nil } ================================================ FILE: application/service/campaign/validation.go ================================================ package campaign import ( "context" ) func CheckAIOAccountStatus(ctx context.Context, aioAccountID int64, accountType client.AccountType) error { account, err := rpc.GetClientInfo(ctx, aioAccountID) if err != nil { logs.CtxError(ctx, "failed to get info for account id: %v", aioAccountID) return err } if account.GetAccountType() != accountType { return errors.NewEMPErrorWithMsg(creative_one.CommonParamCheckError, "AIO account type does not match expected account type") } return nil } func GetAIOAccount(ctx context.Context, aioAccountID int64) (account *client.AIOAccount, err error) { account, err = rpc.GetClientInfo(ctx, aioAccountID) if err != nil { logs.CtxError(ctx, "failed to get info for account id: %v", aioAccountID) return nil, err } return } ================================================ FILE: application/service/global_framework/add_on.go ================================================ package global_framework import ( "context" ) func ClientUpdateAddOns(ctx context.Context, req ClientUpdateTTCXCampaignAddonReq) (resp CommonEmptyResp, err error) { } func ClientValidateAddOns(ctx context.Context, req ClientValidateAddonReq) (resp CommonEmptyResp, err error) { } func ClientCampaignAddOns(ctx context.Context, req ClientCampaignAddonReq) (resp ClientCampaignAddonResp, err error) { } ================================================ FILE: application/service/global_framework/service_package.go ================================================ package global_framework import ( "context" ) func ClientCampaignServicePackages(ctx context.Context, req *partner_business.ClientCampaignServicePackageReq) (resp *partner_business.ClientCampaignServicePackageResp, err error) { resp = &partner_business.ClientCampaignServicePackageResp{BaseResp: base.NewBaseResp()} servicePackages, err := rpc.GetBriefAvailableSPV2s( ctx, req.BriefRegion, req.CoreUserID, req.SelectedAdvertiserID, conv.BoolPtr(false), req.IsSubscription, req.IndustryType) if err != nil { return } isJBP, err := ttcxrpc.IsJBPAdvertiser(ctx, req.GetSelectedAdvertiserID()) if err != nil { return } if isJBP && !gslice.Contains(clients.DynamicConfigGetter.JBPVCPDisableMinimumSpendRegion(), req.BriefRegion) { for _, pck := range append(servicePackages.NetNewPackages, servicePackages.RemixPackages...) { pck.MinSpend = 0 pck.SubscriptionMinSpend = gptr.Of(0.0) pck.OriginalMinSpend = gptr.Of(0.0) pck.AffiliatedMediaFee = gptr.Of(0.0) } for header, pcks := range servicePackages.GetServicePackages() { for _, pck := range pcks { pck.MinSpend = 0 pck.SubscriptionMinSpend = gptr.Of(0.0) pck.OriginalMinSpend = gptr.Of(0.0) pck.AffiliatedMediaFee = gptr.Of(0.0) if header == "net_new_packages" || header == "remix_packages" { pck.Price = 0 } } } } servicePackageMap := map[string][]*partner_business.ServicePackageCardInfo{} for key, value := range servicePackages.ServicePackages { servicePackageList := []*partner_business.ServicePackageCardInfo{} for _, item := range value { servicePackageList = append(servicePackageList, service.ConvertServicePackageCardInfo(item)) } servicePackageMap[key] = servicePackageList } maps := &partner_business.BriefAvailableSPV2sRespMaps{ HeaderMap: map[string]*partner_business.PackageHeaderDesc{}, PackageMap: map[string][]string{}, BusinessTypeDescMap: map[string]*partner_business.BusinessTypeDesc{}, } if servicePackages.Maps != nil { maps.SetPackageMap(servicePackages.GetMaps().PackageMap) headerMap := map[string]*partner_business.PackageHeaderDesc{} businessTypeDescMap := map[string]*partner_business.BusinessTypeDesc{} if servicePackages.GetMaps().HeaderMap != nil { for key, value := range servicePackages.Maps.HeaderMap { headerMap[key] = service.ConvertPackageHeaderDesc(value) } } if servicePackages.GetMaps().BusinessTypeDescMap != nil { for key, value := range servicePackages.Maps.BusinessTypeDescMap { businessTypeDescMap[key] = &partner_business.BusinessTypeDesc{ TitleDesc: value.TitleDesc, ContentDesc: value.ContentDesc, DisclaimerDesc: value.DisclaimerDesc, StartingPrice: value.StartingPrice, CrossedOutPrice: value.CrossedOutPrice, Currency: value.Currency, } } } maps.SetHeaderMap(headerMap) maps.SetBusinessTypeDescMap(businessTypeDescMap) } resp.SetServicePackages(servicePackageMap) resp.SetMaps(maps) return } ================================================ FILE: application/service/util.go ================================================ package service import ( "context" basicJSON "encoding/json" ) func ConvertBriefModelToCampaignEntity(ctx context.Context, brief *BriefDraft) (campaignInfo *CampaignInfo, err error) { } func ConvertCampaignEntityToBriefModel(ctx context.Context, campaignInfo *CampaignInfo, param *ClientCommonParam) (brief *ttcxmodel.BriefDraft) { } // OverwriteFields overwrites the fields of target with the same fields of source func OverwriteFields(ctx context.Context, target interface{}, source interface{}) error { logs.CtxDebug(ctx, "OverwriteFields, target: %v, source: %v", target, source) if source == nil { return nil } sourceData, err := basicJSON.Marshal(source) if err != nil { logs.CtxError(ctx, "overwrite fields failed. unable to marshal the source, err: %v", err) return err } err = basicJSON.Unmarshal(sourceData, target) if err != nil { logs.CtxError(ctx, "overwrite fields failed. unable to unmarshal the target, err: %v", err) return err } return nil } ================================================ FILE: biz/fsm/callback/charging_callback.go ================================================ package callback func ApproveCallbackAfterTran(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) if err := rpc.CreateChargingTicketForPartnerCampaign(ctx, campaignEntity); err != nil { transitionCtx.Cancel(err) logs(ctx, "CallbackAfterTran error=%v partnerCampaign=%+v", err, campaignEntity) } err := NotifyClientCampaignCompleted(ctx, campaignEntity) if err != nil { logs(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) } } ================================================ FILE: biz/fsm/callback/notification_callback.go ================================================ package callback import ( "context" ) func ClientCampaignCompleted(ctx context.Context, campaignEntity entity.ICampaignEntity) error { //Email Notification placeHolder := eventbus.TTONotificationPlaceHolder{ ClientName: gptr.Of(campaignEntity.GetDemanderName()), ProjectName: gptr.Of(campaignEntity.GetName()), CampaignID: gptr.Of(campaignEntity.GetCampaignID()), PartnerName: gptr.Of(campaignEntity.GetPartnerName()), } err := eventbus.SendEmailNotification(ctx, eventbus.REVIEW_PARTNER_CLIENT_EMAIL_NOTIFICATION, campaignEntity.GetCampaignID(), campaignEntity.GetAIOClientID(), placeHolder) if err != nil { logs.CtxError(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) return err } return nil } func ClientCampaignCompletedCallBack(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) err := NotifyClientCampaignCompleted(ctx, campaignEntity) if err != nil { logs.CtxError(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) } } func ClientPartnerCompleteCampaign(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) //Email Notification placeHolder := eventbus.TTONotificationPlaceHolder{ ClientName: gptr.Of(campaignEntity.GetDemanderName()), ProjectName: gptr.Of(campaignEntity.GetName()), CampaignID: gptr.Of(campaignEntity.GetCampaignID()), PartnerName: gptr.Of(campaignEntity.GetPartnerName()), } err := eventbus.SendEmailNotification(ctx, eventbus.PARTNER_COMPLETE_CAMPAIGN_CLIENT_EMAIL_NOTIFICATION, campaignEntity.GetCampaignID(), campaignEntity.GetAIOClientID(), placeHolder) if err != nil { logs.CtxError(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) } } func ClientPartnerAcceptInvite(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) //Email Notification placeHolder := eventbus.TTONotificationPlaceHolder{ ClientName: gptr.Of(campaignEntity.GetDemanderName()), ProjectName: gptr.Of(campaignEntity.GetName()), CampaignID: gptr.Of(campaignEntity.GetCampaignID()), PartnerName: gptr.Of(campaignEntity.GetPartnerName()), } err := eventbus.SendEmailNotification(ctx, eventbus.PARTNER_ACCEPT_ASSIGN_CLIENT_EMAIL_NOTIFICATION, campaignEntity.GetCampaignID(), campaignEntity.GetAIOClientID(), placeHolder) if err != nil { logs.CtxError(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) } } func NotifyClientPartnerRejectInvite(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) //Email Notification placeHolder := eventbus.TTONotificationPlaceHolder{ ClientName: gptr.Of(campaignEntity.GetDemanderName()), ProjectName: gptr.Of(campaignEntity.GetName()), CampaignID: gptr.Of(campaignEntity.GetCampaignID()), PartnerName: gptr.Of(campaignEntity.GetPartnerName()), } err := eventbus.SendEmailNotification(ctx, eventbus.PARTNER_DENY_ASSIGN_CLIENT_EMAIL_NOTIFICATION, campaignEntity.GetCampaignID(), campaignEntity.GetAIOClientID(), placeHolder) if err != nil { logs.CtxError(ctx, "fail to send tto email notification for %d with err: %+v", campaignEntity.GetCampaignID(), err) } } ================================================ FILE: biz/fsm/callback/order_logging_callback.go ================================================ package callback import ( "context" ) func CreateTTCXOrderLog(ctx context.Context, campaignEntity entity.ICampaignEntity) error { return order_dal.CreateOrderLogModel(ctx, campaignEntity.GetTTCXOrderID(), campaignEntity.GetOperatorID(), campaignEntity.GetUserRole(), campaignEntity.GetTTCXOperationType(), campaignEntity.GetPreviousStatus(), int(campaignEntity.GetCampaignStatus()), campaignEntity.GetContent(), model.CustomInfo{}, campaignEntity.GetIsTest()) } ================================================ FILE: biz/fsm/callback/rpc_callback.go ================================================ package callback func RollbackCoupon(transitionCtx *bfsm.TransitionCtx) { ctx := transitionCtx.Ctx args := transitionCtx.Args campaignEntity := args[1].(entity.ICampaignEntity) payment := campaignEntity.GetCampaignPayment() if payment == nil { logs.CtxError(ctx, "missing payment information for campaign %d", campaignEntity.GetCampaignID()) return } err := rpc.RollbackCoupon(ctx, payment.GetCouponID(), 1, campaignEntity.GetOperatorID()) if err != nil { logs.CtxError(ctx, "rollback coupon %d with error: %v", payment.GetCouponID(), err) } } ================================================ FILE: biz/fsm/factory/bfsm_factory.go ================================================ package factory const MatchParamsKey = "matchParams" // MatchParamsVal condition 判断条件,以map 传入,key 指定未`matchParams` type MatchParamsVal struct { IsClientSelect bool NeedPartnerInvoice bool } func NewPartnerCampaignBFSM(agent entity.IAgentEntity) (FSM *bfsm.FSM, err error) { FSM, err = bfsm.NewFSM(agentBase, agent.GetCampaignStatus().String()) if err != nil { return } return } ================================================ FILE: biz/fsm/factory/callback.go ================================================ package factory import ( "context" ) func SaveAndUpdateCampaignAndStatus(transitionCtx *bfsm.TransitionCtx) { args := transitionCtx.Args ctx := args[0].(context.Context) campaignEntity := args[1].(entity.AgentEntity) var err error defer func() { if err != nil { transitionCtx.Err = err } else { logs(ctx, "[SaveAndUpdateCampaignAndStatus] common after trans callback") //Create TTCX Legacy Order Log if campaignEntity.GetOperatorID() != 0 && campaignEntity.GetTTCXOperationType() != 0 { err = callback.CreateTTCXOrderLog(ctx, campaignEntity) if err != nil { logs(ctx, "[SaveAndUpdateCampaignAndStatus] create order log fail, err is %+v", err) } } } }() if campaignEntity.GetRequestID() == 0 { // 初始化创建的case id, err := idgenerator.NewIdLong2(ctx) if err != nil { transitionCtx.Err = err logs(ctx, "[SaveAndUpdateCampaignAndStatus] generate campaign id fail, err is %+v", err) return } campaignEntity.SetTTCXOrderID(int64(id)) } err = setCampaignStatus(campaignEntity, transitionCtx) if err != nil { logsError(ctx, "[SaveAndUpdateCampaignAndStatus] set campaign status err: %+v", err) return } err = repository.CampaignRepo.CreateUpdateCampaign(ctx, campaignEntity) return } func setCampaignStatus(campaignEntity entity.AgentEntity, transitionCtx *bfsm.TransitionCtx) (err error) { if transitionCtx == nil { // TODO: 错误码 err = errors.NewEmpErrorWithStack(creative_one.CommonParamCheckError) return } args := transitionCtx.Args ctx := args[0].(context.Context) dstStatus, err := collaboration.PartnerCampaignStatusFromString(transitionCtx.Dst) if err != nil { return } srcStatus, err := collaboration.PartnerCampaignStatusFromString(transitionCtx.Src) if err != nil { return } logsInfo(ctx, "[setCampaignStatus] set campaign product_domain status, product_domain id: %v, src status: %v, dst status: %v", campaignEntity.GetCampaignID(), srcStatus, dstStatus) campaignEntity.SetCampaignStatus(dstStatus) campaignEntity.SetPreviousStatus(int(srcStatus)) return } ================================================ FILE: biz/fsm/factory/config.go ================================================ package factory const AgentBase = "agent_base" var CreatorAgentFsmConfig = map[string]bfsm.BizDesc{ AgentBase: { CommonDstCallback: SaveAndUpdateCampaignAndStatus, TransDescList: []bfsm.TransDesc{ { Src: []string{collaboration.CreatorAgentStatus_ClientSelectingPartner.String(), collaboration.CreatorAgentStatus_PSOAssignPartner.String()}, Event: partner_business.CampaignOperationEvent_ClientCancelCampaign.String(), BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_Cancelled.String(), AfterTransCallback: callback.RollbackCoupon, }, }, }, { Src: []string{collaboration.CreatorAgentStatus_PartnerReviewingAssignment.String()}, Event: partner_business.CampaignOperationEvent_PartnerAcceptInvitation.String(), //partner approve BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_PartnerMakingProduct.String(), AfterTransCallback: callback.NotifyClientPartnerAcceptInvite, }, }, }, { Src: []string{collaboration.CreatorAgentStatus_PartnerReviewingAssignment.String()}, Event: partner_business.CampaignOperationEvent_PartnerRejectInvitation.String(), //partner reject BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ClientSelectingPartner.String(), Condition: "matchParams.IsClientSelect", AfterTransCallback: callback.NotifyClientPartnerRejectInvite, }, { Dst: collaboration.CreatorAgentStatus_PSOAssignPartner.String(), Condition: "!matchParams.IsClientSelect", AfterTransCallback: callback.NotifyClientPartnerRejectInvite, }, }, }, { Src: []string{collaboration.CreatorAgentStatus_PartnerMakingProduct.String(), collaboration.CreatorAgentStatus_ProductUpload.String()}, Event: partner_business.CampaignOperationEvent_PartnerUploadCreatives.String(), BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ProductUpload.String(), }, }, }, { Src: []string{collaboration.CreatorAgentStatus_ClientConfirmingProduct.String()}, Event: partner_business.CampaignOperationEvent_PartnerUploadCreatives.String(), BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ClientConfirmingProduct.String(), }, }, }, { Src: []string{collaboration.CreatorAgentStatus_ProductComplete.String()}, Event: partner_business.CampaignOperationEvent_PartnerUploadCreatives.String(), BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ProductComplete.String(), }, }, }, { Src: []string{collaboration.CreatorAgentStatus_ProductUpload.String()}, Event: partner_business.CampaignOperationEvent_PartnerCompleteCampaign.String(), BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ClientConfirmingProduct.String(), AfterTransCallback: callback.NotifyClientPartnerCompleteCampaign, }, }, }, { Src: []string{collaboration.CreatorAgentStatus_ClientConfirmingProduct.String()}, Event: partner_business.CampaignOperationEvent_ClientRejectCompletion.String(), //partner complete order BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ProductUpload.String(), AfterTransCallback: nil, }, }, }, { Src: []string{collaboration.CreatorAgentStatus_ClientConfirmingProduct.String()}, Event: partner_business.CampaignOperationEvent_ClientCompleteCampaign.String(), //partner complete order BeforeTransCallback: nil, SrcCallback: nil, Matchers: []bfsm.Matcher{ { Dst: collaboration.CreatorAgentStatus_ProductComplete.String(), Condition: "!matchParams.NeedPartnerInvoice", AfterTransCallback: callback.NotifyClientCampaignCompletedCallBack, }, { Dst: collaboration.CreatorAgentStatus_ProductComplete.String(), Condition: "matchParams.NeedPartnerInvoice", AfterTransCallback: callback.CreatorAgentApproveCallbackAfterTran, }, }, }, }, }, } ================================================ FILE: biz/fsm/factory/trigger.go ================================================ package trigger import ( "context" ) func TransferCampaignWorkFlow(ctx context.Context, agentEntity entity.IAgentEntity, matchParams map[string]interface{}, params ...interface{}) (valid bool, err error) { fsm, err := factory.NewPartnerCampaignBFSM(campaignEntity) if err != nil { return } callbackParams := []interface{}{ctx, campaignEntity} callbackParams = append(callbackParams, params...) err = fsm.Fire(ctx, campaignEntity.GetCampaignOperationEvent().String(), matchParams, callbackParams...) if err != nil { return } valid = true return } ================================================ FILE: build.sh ================================================ #!/usr/bin/env bash RUN_NAME="ad.creative_one.partner_business" mkdir -p output/bin output/conf cp script/* output/ cp conf/* output/conf/ chmod +x output/bootstrap.sh if [ "$IS_SYSTEM_TEST_ENV" != "1" ]; then go build -o output/bin/${RUN_NAME} else go test -c -covermode=set -o output/bin/${RUN_NAME} -coverpkg=./... fi ================================================ FILE: db/custom/collaboration_campaign_info.go ================================================ package custom import ( "context" ) func CreateUpdateCampaign(ctx context.Context, campaignModel *model.CollaborationCampaignInfo) error { if campaignModel.ID == 0 { campaignID, err := idgenerator.NewIdLong2(ctx) if err != nil { logs.CtxError(ctx, "CreateUpdateCampaign id generate fail, err is %+v", err) return err } campaignModel.ID = int64(campaignID) } return query.CreativeSession(ctx).CollaborationCampaignInfo.WithContext(ctx).Save(campaignModel) } func GetCampaignByIDWithClient(ctx context.Context, campaignID int64, AIOClientID int64) (campaignModel *model.CollaborationCampaignInfo, err error) { if AIOClientID == 0 { return GetCampaignByIDWithoutClient(ctx, campaignID) } q := query.CreativeSession(ctx).CollaborationCampaignInfo return q.WithContext(ctx).Where(q.ID.Eq(campaignID)).Where(q.AioClientID.Eq(AIOClientID)).First() } func GetCampaignByIDWithoutClient(ctx context.Context, campaignID int64) (campaignModel *model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo return q.WithContext(ctx).Where(q.ID.Eq(campaignID)).First() } func MGetCampaignByIDs(ctx context.Context, campaignIDs []int64) (campaignModel []*model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo return q.WithContext(ctx).Where(q.ID.In(campaignIDs...)).Find() } func DeleteCampaignByID(ctx context.Context, campaignID int64) (err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo _, err = q.WithContext(ctx).Where(q.ID.Eq(campaignID)).Unscoped().Delete() return } func GetCampaignListWithPageByCondition(ctx context.Context, campaignID *int64, AIOClientID *int64, matchMode *collaboration.MatchMode, seatType *collaboration.SeatType, statusList []int32) (campaignModelList []*model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo search := q.WithContext(ctx) if campaignID != nil { search = search.Where(q.ID.Eq(*campaignID)) } if AIOClientID != nil { search = search.Where(q.AioClientID.Eq(*AIOClientID)) } if matchMode != nil { search = search.Where(q.MatchingMode.Eq(matchMode)) } if seatType != nil { search = search.Where(q.SeatType.Eq(int32(*seatType))) } if len(statusList) != 0 { search = search.Where(q.Status.In(statusList...)) } return search.Find() } func GetCampaignCountGroupByStatus(ctx context.Context, aioClientID int64, matchingMode *collaboration.MatchMode, groupStatus []int32) (ret map[collaboration.CampaignStatus]int32, err error) { type result struct { Status int32 Total int32 } q := query.CreativeSession(ctx).CollaborationCampaignInfo rows, err := q.WithContext(ctx).Select(q.Status, q.ID.Count()).Group(q.Status). Where(q.AioClientID.Eq(aioClientID)). Where(q.MatchingMode.Eq(matchingMode)). Where(q.Status.In(groupStatus...)).Rows() if err != nil { return nil, err } ret = make(map[collaboration.CampaignStatus]int32) for rows.Next() { var r result err = rows.Scan(&r.Status, &r.Total) if err != nil { return nil, err } ret[collaboration.CampaignStatus(r.Status)] = r.Total } return } func GetCampaignIDsByPage(ctx context.Context, page, limit int32) ([]int64, error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo rows, err := q.WithContext(ctx).Where(q.ID.Gt(0)).Order(q.ID).Limit(int(limit)).Offset(int((page - 1) * limit)).Find() if err != nil { return nil, err } campaignIDs := make([]int64, 0, len(rows)) for _, row := range rows { campaignIDs = append(campaignIDs, row.ID) } return campaignIDs, nil } func GetEUSolutionYCampaignsByPage(ctx context.Context, euCountries []string, page, limit int) (campaigns []*model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo rows, _, err := q.WithContext(ctx). Where(q.SolutionType.Eq(gptr.Of(collaboration.SolutionType_SolutionY))). Where(q.CampaignCountry.In(euCountries...)). FindByPage((page-1)*limit, limit) if err != nil { return nil, err } campaigns = make([]*model.CollaborationCampaignInfo, 0, len(rows)) for _, row := range rows { campaigns = append(campaigns, row) } return } func GetSolutionXRunningOACCampaignsByPage(ctx context.Context, offset, limit int) (campaigns []*model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo campaigns, _, err = q.WithContext(ctx). Where(q.SolutionType.Eq(gptr.Of(collaboration.SolutionType_SolutionX))). Where(q.Status.Eq(int32(collaboration.CampaignStatus_Running))). Where(q.MatchingMode.Eq(gptr.Of(collaboration.MatchMode_DIAndOAC))). FindByPage(offset, limit) if err != nil { return nil, err } return campaigns, nil } //func IsCampaignExists(ctx context.Context, campaignID int64, aioClientID int64) (isExists bool, err error) { // q := query.CreativeSession(ctx).CollaborationCampaignInfo // // f := q.WithContext(ctx).Select(q.ID).Where(q.ID.Eq(campaignID)) // if aioClientID != 0 { // f = f.Where(q.AioClientID.Eq(aioClientID)) // } // ret, err := f.First() // if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { // log.V2.Error().With(ctx).Str("IsCampaignExists error").KV("ret", ret).Error(err).Emit() // err = error1.NewEMPErrorWithMsg(creative_one.CommonInternalSystemError, err.Error()).WithStack() // return // } // return ret != nil, nil //} func GetCampaignClientID(ctx context.Context, campaignID int64) int64 { q := query.CreativeSession(ctx).CollaborationCampaignInfo campaignModel, err := q.WithContext(ctx).Select(q.AioClientID).Where(q.ID.Eq(campaignID)).First() if err != nil { log.V2.Warn().With(ctx).Str("[GetCampaignClientID]error").Error(err).Emit() return 0 } return campaignModel.AioClientID } func ScanCampaignByCursor(ctx context.Context, campaignID int64, limit int) (campaigns []*model.CollaborationCampaignInfo, err error) { q := query.CreativeSession(ctx).CollaborationCampaignInfo return q.WithContext(ctx).Where(q.ID.Gte(campaignID)).Order(q.ID).Limit(limit).Find() } func UpdateCampaignDataCenter(ctx context.Context, campaignID int64, dataCenter common_param.DataCenter, write bool) error { if !write { log.V2.Warn().With(ctx).Str("[write=false]campaign update data center").KVs("campaign id", campaignID, "data center", dataCenter).Emit() return nil } q := query.CreativeSession(ctx).CollaborationCampaignInfo _, err := q.WithContext(ctx).Where(q.ID.Eq(campaignID)).Update(q.DataCenter, dataCenter) if err != nil { return err } return nil } ================================================ FILE: db/custom/collaboration_partner_campaign.go ================================================ package custom import ( "context" "database/sql/driver" "gorm.io/gen" ) func CreateUpdatePartnerCampaign(ctx context.Context, campaignModel *model.CollaborationPartnerCampaign) (err error) { if campaignModel.ID == 0 { opportunityID, err := idgenerator.NewIdLong2(ctx) if err != nil { logs.CtxError(ctx, "[CreateUpdatePartnerCampaign] id generate fail, err is %+v", err) return err } campaignModel.ID = int64(opportunityID) } return query.CreativeSession(ctx).CollaborationPartnerCampaign.WithContext(ctx).Save(campaignModel) } func BatchCreateUpdatePartnerCampaign(ctx context.Context, campaignModelList []*model.CollaborationPartnerCampaign) (err error) { for _, campaignModel := range campaignModelList { if campaignModel.ID == 0 { partnerCampaignID, err := idgenerator.NewIdLong2(ctx) if err != nil { logs.CtxError(ctx, "[CreateUpdatePartnerCampaign] id generate fail, err is %+v", err) return err } campaignModel.ID = int64(partnerCampaignID) } } return query.CreativeSession(ctx).CollaborationPartnerCampaign.WithContext(ctx).Save(campaignModelList...) } func GetPartnerCampaignByCampaignID(ctx context.Context, campaignID int64) (campaign *model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign return q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)).First() } func GetPartnerCampaignByID(ctx context.Context, id int64) (campaign *model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign return q.WithContext(ctx).Where(q.ID.Eq(id)).First() } func GetPartnerCampaignMapByIDs(ctx context.Context, ids []int64) (partnerCampaignMap map[int64]*model.CollaborationPartnerCampaign, err error) { if len(ids) == 0 { return map[int64]*model.CollaborationPartnerCampaign{}, nil } q := query.CreativeSession(ctx).CollaborationPartnerCampaign partnerCampaignList, err := q.WithContext(ctx).Where(q.ID.In(ids...)).Find() if err != nil { return nil, err } partnerCampaignMap = make(map[int64]*model.CollaborationPartnerCampaign, len(partnerCampaignList)) for _, partnerCampaign := range partnerCampaignList { partnerCampaignMap[partnerCampaign.ID] = partnerCampaign } return partnerCampaignMap, nil } func GetPartnerCampaignWithPartner(ctx context.Context, campaignID, partnerID int64) (campaign *model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign return q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)).Where(q.AioPartnerID.Eq(partnerID)).First() } func GetPartnerCampaignWithClient(ctx context.Context, campaignID, clientID int64) (campaign *model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign return q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)).Where(q.AioClientID.Eq(clientID)).First() } func GetPartnerCampaignWithPartnerAndClient(ctx context.Context, campaignID, partnerID, clientID int64) (campaign *model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign return q.WithContext(ctx). Where(q.CampaignID.Eq(campaignID)). Where(q.AioClientID.Eq(clientID)). Where(q.AioPartnerID.Eq(partnerID)). First() } func GetPartnerCampaignWithCampaignAndStatus(ctx context.Context, campaignID int64, statusList []collaboration.PartnerCampaignStatus) (parterCampaignList []*model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign filter := q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)) var statusFieldPtr []driver.Valuer for _, status := range statusList { statusFieldPtr = append(statusFieldPtr, &status) } if len(statusFieldPtr) > 0 { filter = filter.Where(q.Status.In(statusFieldPtr...)) } return filter.Find() } func GetPartnerCampaignByPartnerAndStatus(ctx context.Context, aioPartnerIds []int64, statusList []collaboration.PartnerCampaignStatus) (parterCampaignList []*model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign filter := q.WithContext(ctx).Where(q.AioPartnerID.In(aioPartnerIds...)) var statusFieldPtr []driver.Valuer for _, status := range statusList { statusFieldPtr = append(statusFieldPtr, &status) } if len(statusFieldPtr) > 0 { filter = filter.Where(q.Status.In(statusFieldPtr...)) } return filter.Find() } func SearchPartnerCampaignWithAcceptRate(ctx context.Context, campaignID int64, statusList []collaboration.PartnerCampaignStatus, acceptRate100kLt *int64, acceptRate100kGt *int64) (parterCampaignList []*model.CollaborationPartnerCampaign, err error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign filter := q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)) var statusFieldPtr []driver.Valuer for _, status := range statusList { statusFieldPtr = append(statusFieldPtr, &status) } if len(statusFieldPtr) > 0 { filter = filter.Where(q.Status.In(statusFieldPtr...)) } if acceptRate100kGt != nil { filter = filter.Where(q.AcceptRate100K.Gt(*acceptRate100kGt)) } if acceptRate100kLt != nil { filter = filter.Where(q.AcceptRate100K.Lt(*acceptRate100kLt)) } return filter.Find() } func ScanPartnerCampaignByCampaignID(ctx context.Context, campaignID int64) ([]*model.CollaborationPartnerCampaign, error) { q := query.CreativeSession(ctx).CollaborationPartnerCampaign batchSize := 200 result := make([]*model.CollaborationPartnerCampaign, 0, batchSize) totalResult := make([]*model.CollaborationPartnerCampaign, 0) err := q.WithContext(ctx).Where(q.CampaignID.Eq(campaignID)).FindInBatches(&result, batchSize, func(tx gen.Dao, batch int) error { totalResult = append(totalResult, result...) return nil }) return totalResult, err } func UpdatePartnerCampaignDataCenter(ctx context.Context, id int64, dataCenter common_param.DataCenter, write bool) error { if !write { log.V2.Warn().With(ctx).Str("[write=false]partner campaign update data center").KVs("partner campaign id", id, "data center", dataCenter).Emit() return nil } q := query.CreativeSession(ctx).CollaborationPartnerCampaign _, err := q.WithContext(ctx).Where(q.ID.Eq(id)).Update(q.DataCenter, dataCenter) if err != nil { return err } return nil } ================================================ FILE: domain/campaign/campaign_aggregate/entity/campaign.go ================================================ package entity type ICampaignEntity interface { } ================================================ FILE: domain/campaign/campaign_aggregate/repository/brief.go ================================================ package repository import ( "code.byted.org/ad/creative_one_partner_business/domain/campaign/campaign_aggregate/entity" "context" ) var ( BriefRepo BriefRepository ) type BriefRepository interface { CreateUpdateCampaignBrief(ctx context.Context, brief entity.ICampaignEntity) (err error) GetCampaignBriefDetail(ctx context.Context, brief entity.ICampaignEntity) (err error) } ================================================ FILE: domain/campaign/service/campaign_impl.go ================================================ package service import ( "code.byted.org/ad/creative_one_partner_business/domain/campaign/campaign_aggregate/entity" "context" ) type campaignDraftServiceImpl struct{} func (c *campaignDraftServiceImpl) CreateCampaignDraft(ctx context.Context, campaignDraftEntity entity.ICampaignEntity) (err error) { return } func (c *campaignDraftServiceImpl) UpdateCampaignDraft(ctx context.Context, campaignDraftEntity entity.ICampaignEntity) (err error) { return } func (c *campaignDraftServiceImpl) GetCampaignDraftDetail(ctx context.Context, campaignDraftID int64) (campaignDraftEntity entity.ICampaignEntity, err error) { return } ================================================ FILE: domain/campaign/service/init.go ================================================ package service var campaignDraftDomainService ICampaignDraftService func InitDomain() { campaignDraftDomainService = &campaignDraftServiceImpl{} } ================================================ FILE: domain/campaign/service/service.go ================================================ package service import ( "code.byted.org/ad/creative_one_partner_business/domain/campaign/campaign_aggregate/entity" "context" ) type ICampaignDraftService interface { CreateCampaignDraft(ctx context.Context, campaignDraftEntity entity.ICampaignEntity) (err error) UpdateCampaignDraft(ctx context.Context, campaignDraftEntity entity.ICampaignEntity) (err error) GetCampaignDraftDetail(ctx context.Context, campaignDraftID int64) (campaignDraftEntity entity.ICampaignEntity, err error) } func GetService() ICampaignDraftService { return campaignDraftDomainService } ================================================ FILE: go.mod ================================================ ================================================ FILE: go.sum ================================================ ================================================ FILE: rpc/bc_rpc.go ================================================ package rpc import ( "context" ) func GetBusinessCenterListInfo(ctx context.Context, userId int64) ([]*i18n_bc_rpc.BusinessCenterUserInfo, error) { reqCtx := &rpc.BaseContext{ UID: &userId, Source: 4, } req := &rpc.GetBusinessCenterListReq{ Context: reqCtx, Page: 1, Limit: 50, } logs.info(ctx, "GetBusinessCenterListReq req: %s", req) advResp, err := BcClient.GetBusinessCenterList(ctx, req) logs.info(ctx, "GetBusinessCenterListReq response: %+v", advResp) err = middleware.TransformError(advResp, err) if err != nil { logs.error(ctx, "[GetBusinessCenterListReq] get bc info error: %+v", err) return nil, errors.newError(err) } if len(advResp.BusinessCenterUserList) == 0 { logs.info(ctx, "uid [%d] doesn't have bc account", userId) return nil, nil } return advResp.BusinessCenterUserList, nil }