Skip to content

Commit f0b69af

Browse files
author
Michael Ng
authored
feat(config): Add missing config properties for events. (#65)
1 parent 5d0a545 commit f0b69af

File tree

9 files changed

+158
-59
lines changed

9 files changed

+158
-59
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,14 @@ client, err := optimizelyFactory.Client()
2828

2929
### Feature Rollouts
3030
```
31+
import (
32+
"github.com/optimizely/go-sdk/optimizely/client"
33+
"github.com/optimizely/go-sdk/optimizely/entities"
34+
)
35+
3136
user := entities.UserContext{
3237
ID: "optimizely end user",
33-
Attributes: entities.UserAttributes{
38+
Attributes: map[string]interface{}{
3439
"state": "California",
3540
"likes_donuts": true,
3641
},

optimizely/config/datafileprojectconfig/config.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type DatafileProjectConfig struct {
3333
anonymizeIP bool
3434
attributeKeyToIDMap map[string]string
3535
audienceMap map[string]entities.Audience
36+
attributeMap map[string]entities.Attribute
3637
botFiltering bool
3738
eventMap map[string]entities.Event
3839
experimentKeyToIDMap map[string]string
@@ -82,11 +83,14 @@ func NewDatafileProjectConfig(jsonDatafile []byte) (*DatafileProjectConfig, erro
8283
return nil, err
8384
}
8485

86+
attributeMap, attributeKeyToIDMap := mappers.MapAttributes(datafile.Attributes)
8587
experiments, experimentKeyMap := mappers.MapExperiments(datafile.Experiments)
8688
rolloutMap := mappers.MapRollouts(datafile.Rollouts)
8789
mergedAudiences := append(datafile.TypedAudiences, datafile.Audiences...)
8890
config := &DatafileProjectConfig{
8991
audienceMap: mappers.MapAudiences(mergedAudiences),
92+
attributeMap: attributeMap,
93+
attributeKeyToIDMap: attributeKeyToIDMap,
9094
experimentMap: experiments,
9195
experimentKeyToIDMap: experimentKeyMap,
9296
rolloutMap: rolloutMap,
@@ -117,6 +121,16 @@ func (c DatafileProjectConfig) GetFeatureByKey(featureKey string) (entities.Feat
117121
return entities.Feature{}, errors.New(errMessage)
118122
}
119123

124+
// GetAttributeByKey returns the attribute with the given key
125+
func (c DatafileProjectConfig) GetAttributeByKey(key string) (entities.Attribute, error) {
126+
if attributeID, ok := c.attributeKeyToIDMap[key]; ok {
127+
return c.attributeMap[attributeID], nil
128+
}
129+
130+
errMessage := fmt.Sprintf(`Attribute with key "%s" not found`, key)
131+
return entities.Attribute{}, errors.New(errMessage)
132+
}
133+
120134
// GetFeatureList returns an array of all the features
121135
func (c DatafileProjectConfig) GetFeatureList() (featureList []entities.Feature) {
122136
for _, feature := range c.featureMap {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package mappers
18+
19+
import (
20+
datafileEntities "github.com/optimizely/go-sdk/optimizely/config/datafileprojectconfig/entities"
21+
"github.com/optimizely/go-sdk/optimizely/entities"
22+
)
23+
24+
// MapAttributes maps the raw datafile attribute entities to SDK Attribute entities
25+
func MapAttributes(attributes []datafileEntities.Attribute) (attributeMap map[string]entities.Attribute, attributeKeyToIDMap map[string]string) {
26+
27+
attributeMap = make(map[string]entities.Attribute)
28+
attributeKeyToIDMap = make(map[string]string)
29+
for _, attribute := range attributes {
30+
_, ok := attributeMap[attribute.ID]
31+
if !ok {
32+
attributeMap[attribute.ID] = entities.Attribute{
33+
ID: attribute.ID,
34+
Key: attribute.Key,
35+
}
36+
attributeKeyToIDMap[attribute.Key] = attribute.ID
37+
}
38+
}
39+
return attributeMap, attributeKeyToIDMap
40+
}

optimizely/entities/attribute.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package entities
18+
19+
// Attribute contains the user attribute definition
20+
type Attribute struct {
21+
ID string
22+
Key string
23+
}

optimizely/event/events.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@ package event
22

33
// Context holds project-related contextual information about a UserEvent
44
type Context struct {
5-
Revision string `json:"revision"`
6-
AccountID string `json:"account_id"`
7-
ClientVersion string `json:"client_version"`
8-
ProjectID string `json:"project_id"`
9-
ClientName string `json:"client_name"`
10-
AnonymizeIP bool `json:"anonymize_ip"`
11-
BotFiltering bool `json:"bot_filtering"`
12-
attributeKeyToIDMap map[string]string `json:"attributeKeyToIdMap"`
5+
Revision string `json:"revision"`
6+
AccountID string `json:"account_id"`
7+
ClientVersion string `json:"client_version"`
8+
ProjectID string `json:"project_id"`
9+
ClientName string `json:"client_name"`
10+
AnonymizeIP bool `json:"anonymize_ip"`
11+
BotFiltering bool `json:"bot_filtering"`
1312
}
1413

1514
// UserEvent represents a user event
1615
type UserEvent struct {
17-
Timestamp int64 `json:"timestamp"`
16+
Timestamp int64 `json:"timestamp"`
1817
UUID string `json:"uuid"`
1918
EventContext Context
2019
VisitorID string
@@ -50,11 +49,11 @@ type LogEvent struct {
5049
event Batch
5150
}
5251

53-
// Context about the event to send in batch
52+
// Batch - Context about the event to send in batch
5453
type Batch struct {
55-
Revision string `json:"revision"`
56-
AccountID string `json:"account_id"`
57-
ClientVersion string `json:"client_version"`
54+
Revision string `json:"revision"`
55+
AccountID string `json:"account_id"`
56+
ClientVersion string `json:"client_version"`
5857
Visitors []Visitor `json:"visitors"`
5958
ProjectID string `json:"project_id"`
6059
ClientName string `json:"client_name"`

optimizely/event/factory.go

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ package event
22

33
import (
44
"errors"
5+
"fmt"
56
"strings"
67
"time"
78

9+
"github.com/optimizely/go-sdk/optimizely"
10+
811
guuid "github.com/google/uuid"
912
"github.com/optimizely/go-sdk/optimizely/entities"
13+
"github.com/optimizely/go-sdk/optimizely/logging"
1014
"github.com/optimizely/go-sdk/optimizely/utils"
1115
)
1216

17+
var efLogger = logging.GetLogger("EventFactory")
18+
1319
const impressionKey string = "campaign_activated"
14-
const clientKey string = "go-sdk"
15-
const clientVersion string = "1.0.0"
20+
const clientKey string = optimizely.ClientName
21+
const clientVersion string = optimizely.Version
1622
const attributeType = "custom"
1723
const specialPrefix = "$opt_"
1824
const botFilteringKey = "$opt_bot_filtering"
@@ -29,27 +35,26 @@ func makeTimestamp() int64 {
2935
}
3036

3137
// CreateEventContext creates and returns EventContext
32-
func CreateEventContext(projectID string, revision string, accountID string, anonymizeIP bool, botFiltering bool, attributeKeyToIDMap map[string]string) Context {
38+
func CreateEventContext(projectConfig optimizely.ProjectConfig) Context {
3339
context := Context{}
34-
context.ProjectID = projectID
35-
context.Revision = revision
36-
context.AccountID = accountID
40+
context.ProjectID = projectConfig.GetProjectID()
41+
context.Revision = projectConfig.GetRevision()
42+
context.AccountID = projectConfig.GetAccountID()
3743
context.ClientName = clientKey
3844
context.ClientVersion = clientVersion
39-
context.AnonymizeIP = anonymizeIP
40-
context.BotFiltering = botFiltering
41-
context.attributeKeyToIDMap = attributeKeyToIDMap
45+
context.AnonymizeIP = projectConfig.GetAnonymizeIP()
46+
context.BotFiltering = projectConfig.GetBotFiltering()
4247

4348
return context
4449
}
4550

46-
func createImpressionEvent(context Context, experiment entities.Experiment,
51+
func createImpressionEvent(projectConfig optimizely.ProjectConfig, experiment entities.Experiment,
4752
variation entities.Variation, attributes map[string]interface{}) ImpressionEvent {
4853

4954
impression := ImpressionEvent{}
5055
impression.Key = impressionKey
5156
impression.EntityID = experiment.LayerID
52-
impression.Attributes = getEventAttributes(context.attributeKeyToIDMap, attributes, context.BotFiltering)
57+
impression.Attributes = getEventAttributes(projectConfig, attributes)
5358
impression.VariationID = variation.ID
5459
impression.ExperimentID = experiment.ID
5560
impression.CampaignID = experiment.LayerID
@@ -58,18 +63,18 @@ func createImpressionEvent(context Context, experiment entities.Experiment,
5863
}
5964

6065
// CreateImpressionUserEvent creates and returns ImpressionEvent for user
61-
func CreateImpressionUserEvent(context Context, experiment entities.Experiment,
66+
func CreateImpressionUserEvent(projectConfig optimizely.ProjectConfig, experiment entities.Experiment,
6267
variation entities.Variation,
6368
userContext entities.UserContext) UserEvent {
6469

65-
impression := createImpressionEvent(context, experiment, variation, userContext.Attributes)
70+
impression := createImpressionEvent(projectConfig, experiment, variation, userContext.Attributes)
6671

6772
userEvent := UserEvent{}
6873
userEvent.Timestamp = makeTimestamp()
6974
userEvent.VisitorID = userContext.ID
7075
userEvent.UUID = guuid.New().String()
7176
userEvent.Impression = &impression
72-
userEvent.EventContext = context
77+
userEvent.EventContext = CreateEventContext(projectConfig)
7378

7479
return userEvent
7580
}
@@ -94,27 +99,27 @@ func createImpressionVisitor(userEvent UserEvent) Visitor {
9499
}
95100

96101
// create a conversion event
97-
func createConversionEvent(attributeKeyToIDMap map[string]string, event entities.Event, attributes map[string]interface{}, eventTags map[string]interface{}, botFiltering bool) ConversionEvent {
102+
func createConversionEvent(projectConfig optimizely.ProjectConfig, event entities.Event, attributes map[string]interface{}, eventTags map[string]interface{}) ConversionEvent {
98103
conversion := ConversionEvent{}
99104

100105
conversion.Key = event.Key
101106
conversion.EntityID = event.ID
102107
conversion.Tags = eventTags
103-
conversion.Attributes = getEventAttributes(attributeKeyToIDMap, attributes, botFiltering)
108+
conversion.Attributes = getEventAttributes(projectConfig, attributes)
104109

105110
return conversion
106111
}
107112

108113
// CreateConversionUserEvent creates and returns ConversionEvent for user
109-
func CreateConversionUserEvent(context Context, event entities.Event, userContext entities.UserContext, attributeKeyToIDMap map[string]string, eventTags map[string]interface{}) UserEvent {
114+
func CreateConversionUserEvent(projectConfig optimizely.ProjectConfig, event entities.Event, userContext entities.UserContext, eventTags map[string]interface{}) UserEvent {
110115

111116
userEvent := UserEvent{}
112117
userEvent.Timestamp = makeTimestamp()
113118
userEvent.VisitorID = userContext.ID
114119
userEvent.UUID = guuid.New().String()
115120

116-
userEvent.EventContext = context
117-
conversion := createConversionEvent(attributeKeyToIDMap, event, userContext.Attributes, eventTags, context.BotFiltering)
121+
userEvent.EventContext = CreateEventContext(projectConfig)
122+
conversion := createConversionEvent(projectConfig, event, userContext.Attributes, eventTags)
118123
revenue, err := getRevenueValue(eventTags)
119124
if err == nil {
120125
conversion.Revenue = &revenue
@@ -185,49 +190,49 @@ func createVisitor(userEvent UserEvent, attributes []VisitorAttribute,
185190
// create a batch event with visitor
186191
func createBatchEvent(userEvent UserEvent, visitor Visitor) Batch {
187192

188-
189193
eventBatch := Batch{}
190194
eventBatch.ProjectID = userEvent.EventContext.ProjectID
191195
eventBatch.Revision = userEvent.EventContext.Revision
192196
eventBatch.AccountID = userEvent.EventContext.AccountID
193197
eventBatch.Visitors = []Visitor{visitor}
194-
eventBatch.ClientName = clientKey
195-
eventBatch.ClientVersion = clientVersion
198+
eventBatch.ClientName = userEvent.EventContext.ClientName
199+
eventBatch.ClientVersion = userEvent.EventContext.ClientVersion
196200
eventBatch.AnonymizeIP = userEvent.EventContext.AnonymizeIP
197201
eventBatch.EnrichDecisions = true
198202

199203
return eventBatch
200204
}
201205

202206
// get visitor attributes from user attributes
203-
func getEventAttributes(attributeKeyToIDMap map[string]string, attributes map[string]interface{}, botFiltering bool) []VisitorAttribute {
207+
func getEventAttributes(projectConfig optimizely.ProjectConfig, attributes map[string]interface{}) []VisitorAttribute {
204208
var eventAttributes = []VisitorAttribute{}
205209

206210
for key, value := range attributes {
207211
if value == nil {
208212
continue
209213
}
210-
attribute := VisitorAttribute{}
211-
id := attributeKeyToIDMap[key]
212-
if id != "" {
213-
attribute.EntityID = id
214+
visitorAttribute := VisitorAttribute{}
215+
attribute, _ := projectConfig.GetAttributeByKey(key)
216+
if attribute.ID != "" {
217+
visitorAttribute.EntityID = attribute.ID
214218
} else if strings.HasPrefix(key, specialPrefix) {
215-
attribute.EntityID = key
219+
visitorAttribute.EntityID = key
216220
} else {
221+
efLogger.Debug(fmt.Sprintf("Unrecognized attribute %s provided. Pruning before sending event to Optimizely.", key))
217222
continue
218223
}
219-
attribute.Value = value
220-
attribute.AttributeType = attributeType
224+
visitorAttribute.Value = value
225+
visitorAttribute.AttributeType = attributeType
221226

222-
eventAttributes = append(eventAttributes, attribute)
227+
eventAttributes = append(eventAttributes, visitorAttribute)
223228
}
224229

225-
attribute := VisitorAttribute{}
226-
attribute.Value = botFiltering
227-
attribute.AttributeType = attributeType
228-
attribute.Key = botFilteringKey
229-
attribute.EntityID = botFilteringKey
230-
eventAttributes = append(eventAttributes, attribute)
230+
visitorAttribute := VisitorAttribute{}
231+
visitorAttribute.Value = projectConfig.GetBotFiltering()
232+
visitorAttribute.AttributeType = attributeType
233+
visitorAttribute.Key = botFilteringKey
234+
visitorAttribute.EntityID = botFilteringKey
235+
eventAttributes = append(eventAttributes, visitorAttribute)
231236

232237
return eventAttributes
233238
}

0 commit comments

Comments
 (0)