Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract FPD Merge To Separate Package #3533

Merged
merged 4 commits into from
Mar 11, 2024
Merged
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
170 changes: 27 additions & 143 deletions firstpartydata/first_party_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ package firstpartydata

import (
"encoding/json"
"errors"
"fmt"

"github.com/prebid/openrtb/v20/openrtb2"
jsonpatch "gopkg.in/evanphx/json-patch.v4"

"github.com/prebid/prebid-server/v2/errortypes"
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/ortb"
"github.com/prebid/prebid-server/v2/util/jsonutil"
"github.com/prebid/prebid-server/v2/ortb/merge"
"github.com/prebid/prebid-server/v2/util/ptrutil"
)

var (
ErrBadFPD = errors.New("invalid first party data ext")
)

const (
siteKey = "site"
appKey = "app"
Expand Down Expand Up @@ -195,42 +199,18 @@ func resolveUser(fpdConfig *openrtb_ext.ORTB2, bidRequestUser *openrtb2.User, gl
newUser.Data = openRtbGlobalFPD[userDataKey]
}
if fpdConfigUser != nil {
if err := mergeUser(newUser, fpdConfigUser); err != nil {
var err error
if newUser, err = merge.User(newUser, fpdConfigUser); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
}
}

return newUser, nil
}

func mergeUser(v *openrtb2.User, overrideJSON json.RawMessage) error {
*v = *ortb.CloneUser(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extGeo extMerger
ext.Track(&v.Ext)
if v.Geo != nil {
extGeo.Track(&v.Geo.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extGeo.Merge(); err != nil {
return err
}

return nil
}

func resolveSite(fpdConfig *openrtb_ext.ORTB2, bidRequestSite *openrtb2.Site, globalFPD map[string][]byte, openRtbGlobalFPD map[string][]openrtb2.Data, bidderName string) (*openrtb2.Site, error) {
var fpdConfigSite json.RawMessage

Expand Down Expand Up @@ -278,70 +258,22 @@ func resolveSite(fpdConfig *openrtb_ext.ORTB2, bidRequestSite *openrtb2.Site, gl
newSite.Content.Data = openRtbGlobalFPD[siteContentDataKey]
}
if fpdConfigSite != nil {
if err := mergeSite(newSite, fpdConfigSite, bidderName); err != nil {
var err error
if newSite, err = merge.Site(newSite, fpdConfigSite, bidderName); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
}
}
return newSite, nil
}

func mergeSite(v *openrtb2.Site, overrideJSON json.RawMessage, bidderName string) error {
*v = *ortb.CloneSite(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extPublisher, extContent, extContentProducer, extContentNetwork, extContentChannel extMerger
ext.Track(&v.Ext)
if v.Publisher != nil {
extPublisher.Track(&v.Publisher.Ext)
}
if v.Content != nil {
extContent.Track(&v.Content.Ext)
}
if v.Content != nil && v.Content.Producer != nil {
extContentProducer.Track(&v.Content.Producer.Ext)
}
if v.Content != nil && v.Content.Network != nil {
extContentNetwork.Track(&v.Content.Network.Ext)
}
if v.Content != nil && v.Content.Channel != nil {
extContentChannel.Track(&v.Content.Channel.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extPublisher.Merge(); err != nil {
return err
}
if err := extContent.Merge(); err != nil {
return err
}
if err := extContentProducer.Merge(); err != nil {
return err
}
if err := extContentNetwork.Merge(); err != nil {
return err
}
if err := extContentChannel.Merge(); err != nil {
return err
}

// Re-Validate Site
if v.ID == "" && v.Page == "" {
return &errortypes.BadInput{
Message: fmt.Sprintf("incorrect First Party Data for bidder %s: Site object cannot set empty page if req.site.id is empty", bidderName),
// Re-Validate Site
if newSite.ID == "" && newSite.Page == "" {
return nil, &errortypes.BadInput{
Message: fmt.Sprintf("incorrect First Party Data for bidder %s: Site object cannot set empty page if req.site.id is empty", bidderName),
}
}
}

return nil
return newSite, nil
}

func resolveApp(fpdConfig *openrtb_ext.ORTB2, bidRequestApp *openrtb2.App, globalFPD map[string][]byte, openRtbGlobalFPD map[string][]openrtb2.Data, bidderName string) (*openrtb2.App, error) {
Expand Down Expand Up @@ -394,66 +326,18 @@ func resolveApp(fpdConfig *openrtb_ext.ORTB2, bidRequestApp *openrtb2.App, globa
}

if fpdConfigApp != nil {
if err := mergeApp(newApp, fpdConfigApp); err != nil {
var err error
if newApp, err = merge.App(newApp, fpdConfigApp); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
}
}

return newApp, nil
}

func mergeApp(v *openrtb2.App, overrideJSON json.RawMessage) error {
*v = *ortb.CloneApp(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extPublisher, extContent, extContentProducer, extContentNetwork, extContentChannel extMerger
ext.Track(&v.Ext)
if v.Publisher != nil {
extPublisher.Track(&v.Publisher.Ext)
}
if v.Content != nil {
extContent.Track(&v.Content.Ext)
}
if v.Content != nil && v.Content.Producer != nil {
extContentProducer.Track(&v.Content.Producer.Ext)
}
if v.Content != nil && v.Content.Network != nil {
extContentNetwork.Track(&v.Content.Network.Ext)
}
if v.Content != nil && v.Content.Channel != nil {
extContentChannel.Track(&v.Content.Channel.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extPublisher.Merge(); err != nil {
return err
}
if err := extContent.Merge(); err != nil {
return err
}
if err := extContentProducer.Merge(); err != nil {
return err
}
if err := extContentNetwork.Merge(); err != nil {
return err
}
if err := extContentChannel.Merge(); err != nil {
return err
}

return nil
}

func buildExtData(data []byte) []byte {
res := make([]byte, 0, len(data)+len(`"{"data":}"`))
res = append(res, []byte(`{"data":`)...)
Expand Down
Loading
Loading