From 02db55a2023c766105a97bbf829a7968dcdb8912 Mon Sep 17 00:00:00 2001 From: Rashid Siddique Date: Fri, 15 Feb 2019 22:07:21 +0500 Subject: [PATCH] feat: features notification listener --- optimizely/event_builder.py | 42 +++++++++++++++++++++++++++++++++++++ optimizely/helpers/enums.py | 5 ++++- optimizely/optimizely.py | 19 ++++++++++++++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/optimizely/event_builder.py b/optimizely/event_builder.py index 0112b84e..d200267e 100644 --- a/optimizely/event_builder.py +++ b/optimizely/event_builder.py @@ -269,6 +269,27 @@ def _get_required_params_for_conversion(self, event_key, event_tags): snapshot[self.EventParams.EVENTS] = [event_dict] return snapshot + def _get_required_params_for_feature(self, feature_key): + """ Get parameters that are required for the feature event to register. + + Args: + feature_key: Key representing the feature which needs to be recorded. + + Returns: + Dict consisting of the decisions and events info for feature event. + """ + snapshot = {} + + event_dict = { + self.EventParams.EVENT_ID: self.config.get_feature_from_key(feature_key).id, + self.EventParams.TIME: self._get_time(), + self.EventParams.KEY: feature_key, + self.EventParams.UUID: str(uuid.uuid4()) + } + + snapshot[self.EventParams.EVENTS] = [event_dict] + return snapshot + def create_impression_event(self, experiment, variation_id, user_id, attributes): """ Create impression Event to be sent to the logging endpoint. @@ -313,3 +334,24 @@ def create_conversion_event(self, event_key, user_id, attributes, event_tags): params, http_verb=self.HTTP_VERB, headers=self.HTTP_HEADERS) + + def create_feature_event(self, feature_key, user_id, attributes): + """ Create feature Event to be sent to the logging endpoint. + + Args: + feature_key: Key representing the feature which needs to be recorded. + user_id: ID for user. + attributes: Dict representing user attributes and values. + + Returns: + Event object encapsulating the feature event. + """ + + params = self._get_common_params(user_id, attributes) + feature_params = self._get_required_params_for_feature(feature_key) + + params[self.EventParams.USERS][0][self.EventParams.SNAPSHOTS].append(feature_params) + return Event(self.EVENTS_URL, + params, + http_verb=self.HTTP_VERB, + headers=self.HTTP_HEADERS) diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index 879a02a2..764d66ca 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -1,4 +1,4 @@ -# Copyright 2016-2018, Optimizely +# Copyright 2016-2019, Optimizely # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -70,3 +70,6 @@ class NotificationTypes(object): """ ACTIVATE = "ACTIVATE:experiment, user_id, attributes, variation, event" TRACK = "TRACK:event_key, user_id, attributes, event_tags, event" + IS_FEATURE_ENABLED = "IS_FEATURE_ENABLED: feature_key, user_id, attributes, feature_enabled, event" + GET_FEATURE_VARIABLE = "GET_FEATURE_VARIABLE: feature_key, variable_key, user_id, attributes, feature_enabled, "\ + "variable_type, variable_value" diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index f27f0ded..d0a83407 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -208,8 +208,10 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ ) return None + feature_enabled = False decision = self.decision_service.get_variation_for_feature(feature_flag, user_id, attributes) if decision.variation: + feature_enabled = decision.variation.featureEnabled variable_value = self.config.get_variable_value_for_variation(variable, decision.variation) else: @@ -225,6 +227,10 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ self.logger.error('Unable to cast value. Returning None.') actual_value = None + self.notification_center.send_notifications( + enums.NotificationTypes.GET_FEATURE_VARIABLE, + feature_key, variable_key, user_id, attributes, feature_enabled, actual_value, variable_type + ) return actual_value def activate(self, experiment_key, user_id, attributes=None): @@ -384,20 +390,31 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None): if not feature: return False + feature_enabled = False + feature_event = None decision = self.decision_service.get_variation_for_feature(feature, user_id, attributes) if decision.variation: # Send event if Decision came from an experiment. if decision.source == decision_service.DECISION_SOURCE_EXPERIMENT: + feature_event = self.event_builder.create_feature_event(feature_key, user_id, attributes) self._send_impression_event(decision.experiment, decision.variation, user_id, attributes) - if decision.variation.featureEnabled: + feature_enabled = True self.logger.info('Feature "%s" is enabled for user "%s".' % (feature_key, user_id)) return True self.logger.info('Feature "%s" is not enabled for user "%s".' % (feature_key, user_id)) + self.notification_center.send_notifications( + enums.NotificationTypes.IS_FEATURE_ENABLED, + feature_key, + user_id, + attributes, + feature_enabled, + feature_event + ) return False def get_enabled_features(self, user_id, attributes=None):