github.com/prebid/prebid-server@v0.275.0/config/events.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	validator "github.com/asaskevich/govalidator"
     9  )
    10  
    11  // VASTEventElement indicates valid VAST event element
    12  type VASTEventElement string
    13  
    14  const (
    15  	ImpressionVASTElement             VASTEventElement = "impression"
    16  	TrackingVASTElement               VASTEventElement = "tracking"
    17  	ClickTrackingVASTElement          VASTEventElement = "clicktracking"
    18  	CompanionClickThroughVASTElement  VASTEventElement = "companionclickthrough"
    19  	ErrorVASTElement                  VASTEventElement = "error"
    20  	NonLinearClickTrackingVASTElement VASTEventElement = "nonlinearclicktracking"
    21  )
    22  
    23  var vastEventElementMap = map[VASTEventElement]struct{}{
    24  	ImpressionVASTElement:             {},
    25  	TrackingVASTElement:               {},
    26  	ClickTrackingVASTElement:          {},
    27  	CompanionClickThroughVASTElement:  {},
    28  	ErrorVASTElement:                  {},
    29  	NonLinearClickTrackingVASTElement: {},
    30  }
    31  
    32  // TrackingEventType indicates quartile events
    33  type TrackingEventType string
    34  
    35  const (
    36  	Start         TrackingEventType = "start"
    37  	FirstQuartile TrackingEventType = "firstQuartile"
    38  	MidPoint      TrackingEventType = "midPoint"
    39  	ThirdQuartile TrackingEventType = "thirdQuartile"
    40  	Complete      TrackingEventType = "complete"
    41  )
    42  
    43  var trackingEventTypeMap = map[TrackingEventType]struct{}{
    44  	Start:         {},
    45  	FirstQuartile: {},
    46  	MidPoint:      {},
    47  	ThirdQuartile: {},
    48  	Complete:      {},
    49  }
    50  
    51  // VASTEvent indicates the configurations required for injecting VAST event trackers within
    52  // VAST XML
    53  type VASTEvent struct {
    54  	CreateElement     VASTEventElement  `mapstructure:"create_element" json:"create_element"`
    55  	Type              TrackingEventType `mapstructure:"type" json:"type"`
    56  	ExcludeDefaultURL bool              `mapstructure:"exclude_default_url" json:"exclude_default_url"`
    57  	URLs              []string          `mapstructure:"urls" json:"urls"`
    58  }
    59  
    60  // Events indicates the various types of events to be captured typically for injecting tracker URLs
    61  // within the VAST XML
    62  // Don't enable this feature. It is still under developmment. Please follow https://github.com/prebid/prebid-server/issues/1725 for more updates
    63  type Events struct {
    64  	Enabled    *bool       `mapstructure:"enabled" json:"enabled"`
    65  	DefaultURL string      `mapstructure:"default_url" json:"default_url"`
    66  	VASTEvents []VASTEvent `mapstructure:"vast_events" json:"vast_events,omitempty"`
    67  }
    68  
    69  // validate verifies the events object  and returns error if at least one is invalid.
    70  func (e Events) validate(errs []error) []error {
    71  	if e.IsEnabled() {
    72  		if !isValidURL(e.DefaultURL) {
    73  			return append(errs, errors.New("Invalid events.default_url"))
    74  		}
    75  		err := validateVASTEvents(e.VASTEvents)
    76  		if err != nil {
    77  			return append(errs, err)
    78  		}
    79  	}
    80  	return errs
    81  }
    82  
    83  // validateVASTEvents verifies the all VASTEvent objects and returns error if at least one is invalid.
    84  func validateVASTEvents(events []VASTEvent) error {
    85  	if events != nil {
    86  		for i, event := range events {
    87  			if err := event.validate(); err != nil {
    88  				return fmt.Errorf(err.Error(), i, i)
    89  			}
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  // validate validates event object and  returns error if at least one is invalid
    96  func (e VASTEvent) validate() error {
    97  	if !e.CreateElement.isValid() {
    98  		return fmt.Errorf("Invalid events.vast_events[%s].create_element", "%d")
    99  	}
   100  	validType := e.Type.isValid()
   101  
   102  	if e.isTrackingEvent() && !validType {
   103  		var ele []string
   104  		for k := range vastEventElementMap {
   105  			ele = append(ele, string(k))
   106  		}
   107  		return fmt.Errorf("Missing or Invalid events.vast_events[%s].type. Valid values are %v", "%d", strings.Join(ele, ", "))
   108  	}
   109  	if validType && !e.isTrackingEvent() {
   110  		return fmt.Errorf("events.vast_events[%s].type is not applicable for create element '%s'", "%d", e.CreateElement)
   111  	}
   112  	for i, url := range e.URLs {
   113  		if !isValidURL(url) {
   114  			return fmt.Errorf("Invalid events.vast_events[%s].urls[%d]", "%d", i)
   115  		}
   116  	}
   117  	// ensure at least one valid url exists when default URL to be excluded
   118  	if e.ExcludeDefaultURL && len(e.URLs) == 0 {
   119  		return fmt.Errorf("Please provide at least one valid URL in events.vast_events[%s].urls or set events.vast_events[%s].exclude_default_url=false", "%d", "%d")
   120  	}
   121  
   122  	return nil // no errors
   123  }
   124  
   125  // isValid checks create_element has valid value
   126  // if value is value returns true, otherwise false
   127  func (element VASTEventElement) isValid() bool {
   128  	// validate create element
   129  	if _, ok := vastEventElementMap[element]; ok {
   130  		return true
   131  	}
   132  	return false
   133  }
   134  
   135  // isValid checks if valid type is provided (case-sensitive)
   136  func (t TrackingEventType) isValid() bool {
   137  	_, valid := trackingEventTypeMap[t]
   138  	return valid
   139  }
   140  
   141  // isValidURL validates the event URL
   142  func isValidURL(eventURL string) bool {
   143  	return validator.IsURL(eventURL) && validator.IsRequestURL(eventURL)
   144  }
   145  
   146  // isTrackingEvent returns true if event object contains event.CreateElement == "tracking"
   147  func (e VASTEvent) isTrackingEvent() bool {
   148  	return e.CreateElement == TrackingVASTElement
   149  }
   150  
   151  // IsEnabled function returns the value of events.enabled field
   152  func (e Events) IsEnabled() bool {
   153  	return e.Enabled != nil && *e.Enabled
   154  }