|
43 | 43 | #import "OPTLYVariable.h"
|
44 | 44 | #import "OPTLYVariationVariable.h"
|
45 | 45 |
|
| 46 | +NSString *const OptimizelyNotificationsUserDictionaryExperimentKey = @"experiment"; |
| 47 | +NSString *const OptimizelyNotificationsUserDictionaryVariationKey = @"variation"; |
| 48 | +NSString *const OptimizelyNotificationsUserDictionaryUserIdKey = @"userId"; |
| 49 | +NSString *const OptimizelyNotificationsUserDictionaryAttributesKey = @"attributes"; |
| 50 | +NSString *const OptimizelyNotificationsUserDictionaryEventNameKey = @"eventKey"; |
| 51 | +NSString *const OptimizelyNotificationsUserDictionaryFeatureKey = @"feature"; |
| 52 | +NSString *const OptimizelyNotificationsUserDictionaryVariableKey = @"variable"; |
| 53 | +NSString *const OptimizelyNotificationsUserDictionaryExperimentVariationMappingKey = @"ExperimentVariationMapping"; |
| 54 | + |
46 | 55 | @implementation Optimizely
|
47 | 56 |
|
48 | 57 | + (instancetype)init:(OPTLYBuilderBlock)builderBlock {
|
@@ -186,27 +195,39 @@ - (OPTLYVariation *)variation:(NSString *)experimentKey
|
186 | 195 | #pragma mark Forced variation methods
|
187 | 196 | - (OPTLYVariation *)getForcedVariation:(nonnull NSString *)experimentKey
|
188 | 197 | userId:(nonnull NSString *)userId {
|
| 198 | + NSMutableDictionary<NSString *, NSString *> *inputValues = [[NSMutableDictionary alloc] initWithDictionary:@{ |
| 199 | + OptimizelyNotificationsUserDictionaryUserIdKey:[self ObjectOrNull:userId], |
| 200 | + OptimizelyNotificationsUserDictionaryExperimentKey:[self ObjectOrNull:experimentKey]}]; |
| 201 | + if (![self validateStringInputs:inputValues logs:@{}]) { |
| 202 | + return nil; |
| 203 | + } |
189 | 204 | return [self.config getForcedVariation:experimentKey
|
190 | 205 | userId:userId];
|
191 | 206 | }
|
192 | 207 |
|
193 | 208 | - (BOOL)setForcedVariation:(nonnull NSString *)experimentKey
|
194 | 209 | userId:(nonnull NSString *)userId
|
195 | 210 | variationKey:(nullable NSString *)variationKey {
|
196 |
| - return [self.config setForcedVariation:experimentKey |
| 211 | + NSMutableDictionary<NSString *, NSString *> *inputValues = [[NSMutableDictionary alloc] initWithDictionary:@{ |
| 212 | + OptimizelyNotificationsUserDictionaryUserIdKey:[self ObjectOrNull:userId], |
| 213 | + OptimizelyNotificationsUserDictionaryExperimentKey:[self ObjectOrNull:experimentKey]}]; |
| 214 | + return [self validateStringInputs:inputValues logs:@{}] && [self.config setForcedVariation:experimentKey |
197 | 215 | userId:userId
|
198 | 216 | variationKey:variationKey];
|
199 | 217 | }
|
200 | 218 |
|
201 | 219 | #pragma mark - Feature Flag Methods
|
202 | 220 |
|
203 | 221 | - (BOOL)isFeatureEnabled:(NSString *)featureKey userId:(NSString *)userId attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes {
|
204 |
| - if ([userId getValidString] == nil) { |
205 |
| - [self.logger logMessage:OPTLYLoggerMessagesFeatureDisabledUserIdInvalid withLevel:OptimizelyLogLevelError]; |
206 |
| - return false; |
207 |
| - } |
208 |
| - if ([featureKey getValidString] == nil) { |
209 |
| - [self.logger logMessage:OPTLYLoggerMessagesFeatureDisabledFlagKeyInvalid withLevel:OptimizelyLogLevelError]; |
| 222 | + |
| 223 | + NSMutableDictionary<NSString *, NSString *> *inputValues = [[NSMutableDictionary alloc] initWithDictionary:@{ |
| 224 | + OptimizelyNotificationsUserDictionaryUserIdKey:[self ObjectOrNull:userId], |
| 225 | + OptimizelyNotificationsUserDictionaryExperimentKey:[self ObjectOrNull:featureKey]}]; |
| 226 | + NSDictionary <NSString *, NSString *> *logs = @{ |
| 227 | + OptimizelyNotificationsUserDictionaryUserIdKey:OPTLYLoggerMessagesFeatureDisabledUserIdInvalid, |
| 228 | + OptimizelyNotificationsUserDictionaryExperimentKey:OPTLYLoggerMessagesFeatureDisabledFlagKeyInvalid}; |
| 229 | + |
| 230 | + if (![self validateStringInputs:inputValues logs:logs]) { |
210 | 231 | return false;
|
211 | 232 | }
|
212 | 233 |
|
@@ -246,16 +267,17 @@ - (NSString *)getFeatureVariableValueForType:(NSString *)variableType
|
246 | 267 | variableKey:(nullable NSString *)variableKey
|
247 | 268 | userId:(nullable NSString *)userId
|
248 | 269 | attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes {
|
249 |
| - if ([featureKey getValidString] == nil) { |
250 |
| - [self.logger logMessage:OPTLYLoggerMessagesFeatureVariableValueFlagKeyInvalid withLevel:OptimizelyLogLevelError]; |
251 |
| - return nil; |
252 |
| - } |
253 |
| - if ([variableKey getValidString] == nil) { |
254 |
| - [self.logger logMessage:OPTLYLoggerMessagesFeatureVariableValueVariableKeyInvalid withLevel:OptimizelyLogLevelError]; |
255 |
| - return nil; |
256 |
| - } |
257 |
| - if ([userId getValidString] == nil) { |
258 |
| - [self.logger logMessage:OPTLYLoggerMessagesFeatureVariableValueUserIdInvalid withLevel:OptimizelyLogLevelError]; |
| 270 | + |
| 271 | + NSMutableDictionary<NSString *, NSString *> *inputValues = [[NSMutableDictionary alloc] initWithDictionary:@{ |
| 272 | + OptimizelyNotificationsUserDictionaryUserIdKey:[self ObjectOrNull:userId], |
| 273 | + OptimizelyNotificationsUserDictionaryFeatureKey:[self ObjectOrNull:featureKey], |
| 274 | + OptimizelyNotificationsUserDictionaryVariableKey:[self ObjectOrNull:variableKey]}]; |
| 275 | + NSDictionary <NSString *, NSString *> *logs = @{ |
| 276 | + OptimizelyNotificationsUserDictionaryUserIdKey:OPTLYLoggerMessagesFeatureVariableValueUserIdInvalid, |
| 277 | + OptimizelyNotificationsUserDictionaryVariableKey:OPTLYLoggerMessagesFeatureVariableValueVariableKeyInvalid, |
| 278 | + OptimizelyNotificationsUserDictionaryFeatureKey:OPTLYLoggerMessagesFeatureVariableValueFlagKeyInvalid}; |
| 279 | + |
| 280 | + if (![self validateStringInputs:inputValues logs:logs]) { |
259 | 281 | return nil;
|
260 | 282 | }
|
261 | 283 |
|
@@ -364,7 +386,17 @@ - (NSString *)getFeatureVariableString:(nullable NSString *)featureKey
|
364 | 386 | -(NSArray<NSString *> *)getEnabledFeatures:(NSString *)userId
|
365 | 387 | attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
|
366 | 388 |
|
| 389 | + |
367 | 390 | NSMutableArray<NSString *> *enabledFeatures = [NSMutableArray new];
|
| 391 | + |
| 392 | + NSMutableDictionary<NSString *, NSString *> *inputValues = [[NSMutableDictionary alloc] initWithDictionary:@{ |
| 393 | + OptimizelyNotificationsUserDictionaryUserIdKey:[self ObjectOrNull:userId]}]; |
| 394 | + NSDictionary <NSString *, NSString *> *logs = @{}; |
| 395 | + |
| 396 | + if (![self validateStringInputs:inputValues logs:logs]) { |
| 397 | + return enabledFeatures; |
| 398 | + } |
| 399 | + |
368 | 400 | for (OPTLYFeatureFlag *feature in self.config.featureFlags) {
|
369 | 401 | NSString *featureKey = feature.key;
|
370 | 402 | if ([self isFeatureEnabled:featureKey userId:userId attributes:attributes]) {
|
@@ -927,4 +959,57 @@ - (OPTLYVariation *)sendImpressionEventFor:(OPTLYExperiment *)experiment
|
927 | 959 | }
|
928 | 960 | return decisions;
|
929 | 961 | }
|
| 962 | + |
| 963 | ++ (BOOL)isEmptyArray:(NSObject*)array { |
| 964 | + return (!array |
| 965 | + || ![array isKindOfClass:[NSArray class]] |
| 966 | + || (((NSArray *)array).count == 0)); |
| 967 | +} |
| 968 | + |
| 969 | ++ (BOOL)isEmptyString:(NSObject*)string { |
| 970 | + return (!string |
| 971 | + || ![string isKindOfClass:[NSString class]] |
| 972 | + || [(NSString *)string isEqualToString:@""]); |
| 973 | +} |
| 974 | + |
| 975 | ++ (BOOL)isEmptyDictionary:(NSObject*)dict { |
| 976 | + return (!dict |
| 977 | + || ![dict isKindOfClass:[NSDictionary class]] |
| 978 | + || (((NSDictionary *)dict).count == 0)); |
| 979 | +} |
| 980 | + |
| 981 | ++ (NSString *)stringOrEmpty:(NSString *)str { |
| 982 | + NSString *string = str != nil ? str : @""; |
| 983 | + return string; |
| 984 | +} |
| 985 | + |
| 986 | +- (BOOL)validateStringInputs:(NSMutableDictionary<NSString *, NSString *> *)inputs logs:(NSDictionary<NSString *, NSString *> *)logs { |
| 987 | + NSMutableDictionary *_inputs = [inputs mutableCopy]; |
| 988 | + BOOL __block isValid = true; |
| 989 | + // Empty user Id is valid value. |
| 990 | + if (_inputs.allKeys.count > 0) { |
| 991 | + if ([_inputs.allKeys containsObject:OptimizelyNotificationsUserDictionaryUserIdKey]) { |
| 992 | + if ([[_inputs objectForKey:OptimizelyNotificationsUserDictionaryUserIdKey] isKindOfClass:[NSNull class]]) { |
| 993 | + isValid = false; |
| 994 | + if ([logs objectForKey:OptimizelyNotificationsUserDictionaryUserIdKey]) { |
| 995 | + [self.logger logMessage:[logs objectForKey:OptimizelyNotificationsUserDictionaryUserIdKey] withLevel:OptimizelyLogLevelError]; |
| 996 | + } |
| 997 | + } |
| 998 | + [_inputs removeObjectForKey:OptimizelyNotificationsUserDictionaryUserIdKey]; |
| 999 | + } |
| 1000 | + } |
| 1001 | + [_inputs enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) { |
| 1002 | + if ([value isKindOfClass:[NSNull class]] || [value isEqualToString:@""]) { |
| 1003 | + if ([logs objectForKey:key]) { |
| 1004 | + [self.logger logMessage:[logs objectForKey:key] withLevel:OptimizelyLogLevelError]; |
| 1005 | + } |
| 1006 | + isValid = false; |
| 1007 | + } |
| 1008 | + }]; |
| 1009 | + return isValid; |
| 1010 | +} |
| 1011 | + |
| 1012 | +- (id)ObjectOrNull:(id)object { |
| 1013 | + return object ?: [NSNull null]; |
| 1014 | +} |
930 | 1015 | @end
|
0 commit comments