Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions modules/prebid/ortb2blocking/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,21 @@ type BtypeActionOverride struct {
type Battr struct {
ActionOverrides BattrActionOverride `json:"action_overrides"`
AllowedBannerAttrForDeals []int `json:"allowed_banner_attr_for_deals"`
AllowedVideoAttrForDeals []int `json:"allowed_video_attr_for_deals"`
AllowedAudioAttrForDeals []int `json:"allowed_audio_attr_for_deals"`
BlockedBannerAttr []int `json:"blocked_banner_attr"`
BlockedVideoAttr []int `json:"blocked_video_attr"`
BlockedAudioAttr []int `json:"blocked_audio_attr"`
EnforceBlocks bool `json:"enforce_blocks"`
}

type BattrActionOverride struct {
AllowedBannerAttrForDeals []ActionOverride `json:"allowed_banner_attr_for_deals"`
AllowedVideoAttrForDeals []ActionOverride `json:"allowed_video_attr_for_deals"`
AllowedAudioAttrForDeals []ActionOverride `json:"allowed_audio_attr_for_deals"`
BlockedBannerAttr []ActionOverride `json:"blocked_banner_attr"`
BlockedVideoAttr []ActionOverride `json:"blocked_video_attr"`
BlockedAudioAttr []ActionOverride `json:"blocked_audio_attr"`
EnforceBlocks []ActionOverride `json:"enforce_blocks"`
}

Expand Down
184 changes: 152 additions & 32 deletions modules/prebid/ortb2blocking/hook_bidderrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,22 @@ func updateBType(
return imp.Banner != nil && len(imp.Banner.BType) > 0
}

attributes.bType, messages, err = findImpressionOverrides(payload, actionOverrides, btype, checkAttrExistence)
overrides, messages, err := findImpressionOverrides(payload, actionOverrides, btype, checkAttrExistence)
result.Warnings = mergeStrings(result.Warnings, messages...)
if err != nil {
return fmt.Errorf("failed to get override for imp.*.banner.btype: %s", err)
} else if len(attributes.bType) > 0 {
mutation := bTypeMutation(attributes.bType)
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "btype")
}

// Filter to only apply to impressions with Banner objects
if len(overrides) > 0 {
filteredOverrides := filterByMediaType(payload, overrides, func(imp openrtb2.Imp) bool {
return imp.Banner != nil
})
if len(filteredOverrides) > 0 {
mutation := createBTypeMutation(filteredOverrides)
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "btype")
}
attributes.bType = overrides
}

return nil
Expand All @@ -167,21 +176,91 @@ func updateBAttr(
changeSet *hookstage.ChangeSet[hookstage.BidderRequestPayload],
) (err error) {
var messages []string
battr := cfg.Attributes.Battr.BlockedBannerAttr
actionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedBannerAttr
checkAttrExistence := func(imp openrtb2.Imp) bool {

bannerBattr := cfg.Attributes.Battr.BlockedBannerAttr
bannerActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedBannerAttr
bannerCheckAttrExistence := func(imp openrtb2.Imp) bool {
return imp.Banner != nil && len(imp.Banner.BAttr) > 0
}

attributes.bAttr, messages, err = findImpressionOverrides(payload, actionOverrides, battr, checkAttrExistence)
result.Warnings = mergeStrings(result.Warnings, messages...)
bannerOverrides, bannerMessages, err := findImpressionOverrides(payload, bannerActionOverrides, bannerBattr, bannerCheckAttrExistence)
messages = append(messages, bannerMessages...)
if err != nil {
return fmt.Errorf("failed to get override for imp.*.banner.battr: %s", err)
} else if len(attributes.bAttr) > 0 {
mutation := bAttrMutation(attributes.bAttr)
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "battr")
}

// Apply banner battr only to impressions that have Banner objects
if len(bannerOverrides) > 0 {
filteredBannerOverrides := filterByMediaType(payload, bannerOverrides, func(imp openrtb2.Imp) bool {
return imp.Banner != nil
})
if len(filteredBannerOverrides) > 0 {
mutation := createBAttrMutation(filteredBannerOverrides, "banner")
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "battr")
}
}

// Video battr
videoBattr := cfg.Attributes.Battr.BlockedVideoAttr
videoActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedVideoAttr
videoCheckAttrExistence := func(imp openrtb2.Imp) bool {
return imp.Video != nil && len(imp.Video.BAttr) > 0
}

videoOverrides, videoMessages, err := findImpressionOverrides(payload, videoActionOverrides, videoBattr, videoCheckAttrExistence)
messages = append(messages, videoMessages...)
if err != nil {
return fmt.Errorf("failed to get override for imp.*.video.battr: %s", err)
}

// Apply video battr only to impressions that have Video objects
if len(videoOverrides) > 0 {
filteredVideoOverrides := filterByMediaType(payload, videoOverrides, func(imp openrtb2.Imp) bool {
return imp.Video != nil
})
if len(filteredVideoOverrides) > 0 {
mutation := createBAttrMutation(filteredVideoOverrides, "video")
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "video", "battr")
}
}

// Audio battr
audioBattr := cfg.Attributes.Battr.BlockedAudioAttr
audioActionOverrides := cfg.Attributes.Battr.ActionOverrides.BlockedAudioAttr
audioCheckAttrExistence := func(imp openrtb2.Imp) bool {
return imp.Audio != nil && len(imp.Audio.BAttr) > 0
}

audioOverrides, audioMessages, err := findImpressionOverrides(payload, audioActionOverrides, audioBattr, audioCheckAttrExistence)
messages = append(messages, audioMessages...)
if err != nil {
return fmt.Errorf("failed to get override for imp.*.audio.battr: %s", err)
}

// Apply audio battr only to impressions that have Audio objects
if len(audioOverrides) > 0 {
filteredAudioOverrides := filterByMediaType(payload, audioOverrides, func(imp openrtb2.Imp) bool {
return imp.Audio != nil
})
if len(filteredAudioOverrides) > 0 {
mutation := createBAttrMutation(filteredAudioOverrides, "audio")
changeSet.AddMutation(mutation, hookstage.MutationUpdate, "bidrequest", "imp", "audio", "battr")
}
}

// Store all attributes and merge messages
attributes.bAttr = make(map[string][]int)
for k, v := range bannerOverrides {
attributes.bAttr[k] = v
}
for k, v := range videoOverrides {
attributes.bAttr[k] = v
}
for k, v := range audioOverrides {
attributes.bAttr[k] = v
}

result.Warnings = mergeStrings(result.Warnings, messages...)
return nil
}

Expand All @@ -199,26 +278,6 @@ func updateCatTax(
changeSet.BidderRequest().CatTax().Update(attributes.catTax)
}

func bTypeMutation(bTypeByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] {
return mutationForImp(bTypeByImp, func(imp openrtb2.Imp, btype []int) openrtb2.Imp {
imp.Banner.BType = make([]openrtb2.BannerAdType, len(btype))
for i := range btype {
imp.Banner.BType[i] = openrtb2.BannerAdType(btype[i])
}
return imp
})
}

func bAttrMutation(bAttrByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] {
return mutationForImp(bAttrByImp, func(imp openrtb2.Imp, battr []int) openrtb2.Imp {
imp.Banner.BAttr = make([]adcom1.CreativeAttribute, len(battr))
for i := range battr {
imp.Banner.BAttr[i] = adcom1.CreativeAttribute(battr[i])
}
return imp
})
}

type impUpdateFunc func(imp openrtb2.Imp, values []int) openrtb2.Imp

func mutationForImp(
Expand Down Expand Up @@ -422,3 +481,64 @@ func validateCondition(conditions Conditions) error {
}
return nil
}

// filterByMediaType filters overrides to only include impressions with a specific media type
func filterByMediaType(
payload hookstage.BidderRequestPayload,
overrides map[string][]int,
mediaTypeExists func(imp openrtb2.Imp) bool,
) map[string][]int {
filtered := make(map[string][]int)

for _, imp := range payload.Request.Imp {
if values, exists := overrides[imp.ID]; exists && mediaTypeExists(imp) {
filtered[imp.ID] = values
}
}

return filtered
}

// createBAttrMutation creates a mutation function for a specific media type
func createBAttrMutation(bAttrByImp map[string][]int, mediaType string) hookstage.MutationFunc[hookstage.BidderRequestPayload] {
return func(payload hookstage.BidderRequestPayload) (hookstage.BidderRequestPayload, error) {
for i, imp := range payload.Request.Imp {
if values, ok := bAttrByImp[imp.ID]; ok && len(values) > 0 {
switch mediaType {
case "banner":
imp.Banner.BAttr = make([]adcom1.CreativeAttribute, len(values))
for j, attr := range values {
imp.Banner.BAttr[j] = adcom1.CreativeAttribute(attr)
}
case "video":
imp.Video.BAttr = make([]adcom1.CreativeAttribute, len(values))
for j, attr := range values {
imp.Video.BAttr[j] = adcom1.CreativeAttribute(attr)
}
case "audio":
imp.Audio.BAttr = make([]adcom1.CreativeAttribute, len(values))
for j, attr := range values {
imp.Audio.BAttr[j] = adcom1.CreativeAttribute(attr)
}
}
payload.Request.Imp[i] = imp
}
}
return payload, nil
}
}

func createBTypeMutation(bTypeByImp map[string][]int) hookstage.MutationFunc[hookstage.BidderRequestPayload] {
return func(payload hookstage.BidderRequestPayload) (hookstage.BidderRequestPayload, error) {
for i, imp := range payload.Request.Imp {
if values, ok := bTypeByImp[imp.ID]; ok && len(values) > 0 {
imp.Banner.BType = make([]openrtb2.BannerAdType, len(values))
for j, btype := range values {
imp.Banner.BType[j] = openrtb2.BannerAdType(btype)
}
payload.Request.Imp[i] = imp
}
}
return payload, nil
}
}
Loading
Loading