Skip to content

Commit

Permalink
Remote config list request implemented (#472)
Browse files Browse the repository at this point in the history
* Remote config list request implemented

* Linter fix

* Tests fix

* CR fixes
  • Loading branch information
SpertsyanKM authored Mar 28, 2024
1 parent fbc283d commit 3c7774a
Show file tree
Hide file tree
Showing 20 changed files with 313 additions and 31 deletions.
10 changes: 10 additions & 0 deletions Qonversion.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
45FFA2EB24BEEA9A007EFB8F /* ProductCenterManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45FFA2EA24BEEA9A007EFB8F /* ProductCenterManagerTests.m */; };
45FFA2ED24BEF379007EFB8F /* full_init.json in Resources */ = {isa = PBXBuildFile; fileRef = 45FFA2EC24BEF379007EFB8F /* full_init.json */; };
4CADC5602759181A004FDC10 /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CADC55F2759181A004FDC10 /* AuthViewController.swift */; };
6A121DAC2BB445AE0073B330 /* QONRemoteConfigList.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A121DAB2BB445AE0073B330 /* QONRemoteConfigList.m */; };
6A121DAE2BB446740073B330 /* QONRemoteConfigList.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A121DAD2BB446740073B330 /* QONRemoteConfigList.h */; settings = {ATTRIBUTES = (Public, ); }; };
6A21BF4C2AB201A7005BDA7C /* QONRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A21BF4B2AB201A7005BDA7C /* QONRateLimiter.h */; };
6A21BF4E2AB20483005BDA7C /* QONRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A21BF4D2AB20483005BDA7C /* QONRateLimiter.m */; };
6A21BF532AB2059F005BDA7C /* QONRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A21BF522AB2059F005BDA7C /* QONRequest.h */; };
Expand Down Expand Up @@ -342,6 +344,9 @@
45FFA2EA24BEEA9A007EFB8F /* ProductCenterManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProductCenterManagerTests.m; sourceTree = "<group>"; };
45FFA2EC24BEF379007EFB8F /* full_init.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = full_init.json; sourceTree = "<group>"; };
4CADC55F2759181A004FDC10 /* AuthViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewController.swift; sourceTree = "<group>"; };
6A121DAB2BB445AE0073B330 /* QONRemoteConfigList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QONRemoteConfigList.m; sourceTree = "<group>"; };
6A121DAD2BB446740073B330 /* QONRemoteConfigList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QONRemoteConfigList.h; sourceTree = "<group>"; };
6A121DAF2BB44D7B0073B330 /* QONRemoteConfigList+protected.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "QONRemoteConfigList+protected.h"; sourceTree = "<group>"; };
6A21BF4B2AB201A7005BDA7C /* QONRateLimiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QONRateLimiter.h; sourceTree = "<group>"; };
6A21BF4D2AB20483005BDA7C /* QONRateLimiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QONRateLimiter.m; sourceTree = "<group>"; };
6A21BF522AB2059F005BDA7C /* QONRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QONRequest.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -991,6 +996,8 @@
70D0E2B7291A9BE3004E8DE8 /* QONConfiguration.m */,
7094501829CD994200F55E68 /* QONRemoteConfig.h */,
7094501929CD994200F55E68 /* QONRemoteConfig.m */,
6A121DAD2BB446740073B330 /* QONRemoteConfigList.h */,
6A121DAB2BB445AE0073B330 /* QONRemoteConfigList.m */,
707734F22A9F607700CFF742 /* QONRemoteConfigurationSource.h */,
707734F32A9F607700CFF742 /* QONRemoteConfigurationSource.m */,
70A26ADC2A31BC44008CE4A7 /* QONExperiment.h */,
Expand Down Expand Up @@ -1335,6 +1342,7 @@
children = (
700EC171291277130032E205 /* QONExperimentGroup+Protected.h */,
7097C6BD2A38BFC800565DE4 /* QONRemoteConfig+Protected.h */,
6A121DAF2BB44D7B0073B330 /* QONRemoteConfigList+protected.h */,
707734F62A9F6B8700CFF742 /* QONRemoteConfigurationSource+Protected.h */,
702DBDEB2A3216C900D590D0 /* QONExperiment+Protected.h */,
8957324226DD03A3009507A6 /* QONUser+Protected.h */,
Expand Down Expand Up @@ -1595,6 +1603,7 @@
6A21BF4C2AB201A7005BDA7C /* QONRateLimiter.h in Headers */,
70B917672B34284200BF0689 /* QONTransaction+Protected.h in Headers */,
895732B426DD03A3009507A6 /* QONAutomationsService.h in Headers */,
6A121DAE2BB446740073B330 /* QONRemoteConfigList.h in Headers */,
895732CA26DD03A3009507A6 /* QNUtils.h in Headers */,
8957328126DD03A3009507A6 /* QONEntitlement.h in Headers */,
8957330526DD03A3009507A6 /* QNIdentityServiceInterface.h in Headers */,
Expand Down Expand Up @@ -1983,6 +1992,7 @@
8957329726DD03A3009507A6 /* QONStoreKitSugare.m in Sources */,
895732A226DD03A3009507A6 /* QONMacrosProcess.m in Sources */,
8957329E26DD03A3009507A6 /* QONProduct.m in Sources */,
6A121DAC2BB445AE0073B330 /* QONRemoteConfigList.m in Sources */,
6ABCBE192B99A79E003DB107 /* QONRemoteConfigLoadingState.m in Sources */,
895732A026DD03A3009507A6 /* QONAutomationsConstants.m in Sources */,
7094501B29CD994200F55E68 /* QONRemoteConfig.m in Sources */,
Expand Down
4 changes: 3 additions & 1 deletion Sources/Qonversion/Public/QONLaunchResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

NS_ASSUME_NONNULL_BEGIN

@class QONEntitlement, QONProduct, QONOfferings, QONIntroEligibility, QONUser, QONRemoteConfig, QONUserProperties;
@class QONEntitlement, QONProduct, QONOfferings, QONIntroEligibility, QONUser, QONRemoteConfig, QONRemoteConfigList, QONUserProperties;

typedef NS_ENUM(NSInteger, QONAttributionProvider) {
QONAttributionProviderAppsFlyer = 0,
Expand Down Expand Up @@ -62,6 +62,8 @@ typedef void (^QONEligibilityCompletionHandler)(NSDictionary<NSString *, QONIntr

typedef void (^QONRemoteConfigCompletionHandler)(QONRemoteConfig *_Nullable remoteConfig, NSError *_Nullable error) NS_SWIFT_NAME(Qonversion.RemoteConfigCompletionHandler);

typedef void (^QONRemoteConfigListCompletionHandler)(QONRemoteConfigList *_Nullable remoteConfigList, NSError *_Nullable error) NS_SWIFT_NAME(Qonversion.RemoteConfigCompletionHandler);

typedef void (^QONExperimentAttachCompletionHandler)(BOOL success, NSError *_Nullable error) NS_SWIFT_NAME(Qonversion.ExperimentAttachCompletionHandler);

typedef void (^QONRemoteConfigurationAttachCompletionHandler)(BOOL success, NSError *_Nullable error) NS_SWIFT_NAME(Qonversion.RemoteConfigurationAttachCompletionHandler);
Expand Down
24 changes: 24 additions & 0 deletions Sources/Qonversion/Public/QONRemoteConfigList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// QONRemoteConfigList.h
// Qonversion
//
// Created by Kamo Spertsyan on 27.03.2024.
// Copyright © 2024 Qonversion Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "QONRemoteConfig.h"

NS_ASSUME_NONNULL_BEGIN

NS_SWIFT_NAME(Qonversion.RemoteConfig)
@interface QONRemoteConfigList : NSObject

@property (nonatomic, copy) NSArray<QONRemoteConfig *> *remoteConfigs;

- (QONRemoteConfig *_Nullable)remoteConfigForContextKey:(NSString *)key;
- (QONRemoteConfig *_Nullable)remoteConfigForEmptyContextKey;

@end

NS_ASSUME_NONNULL_END
40 changes: 40 additions & 0 deletions Sources/Qonversion/Public/QONRemoteConfigList.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// QONRemoteConfigList.m
// Qonversion
//
// Created by Kamo Spertsyan on 27.03.2024.
// Copyright © 2024 Qonversion Inc. All rights reserved.
//

#import "QONRemoteConfigList.h"

@implementation QONRemoteConfigList

- (instancetype)initWithRemoteConfigs:(NSArray *)remoteConfigs {
self = [super init];

if (self) {
_remoteConfigs = [remoteConfigs copy];
}

return self;
}

- (QONRemoteConfig *_Nullable)remoteConfigForContextKey:(NSString *)key {
return [self findRemoteConfigForContextKey:key];
}

- (QONRemoteConfig *_Nullable)remoteConfigForEmptyContextKey {
return [self findRemoteConfigForContextKey:nil];
}

- (QONRemoteConfig *)findRemoteConfigForContextKey:(NSString *_Nullable)key {
for (QONRemoteConfig *config in self.remoteConfigs) {
if ((key == nil && config.source.contextKey == nil) || [config.source.contextKey isEqualToString:key]) {
return config;
}
}
return nil;
}

@end
20 changes: 19 additions & 1 deletion Sources/Qonversion/Public/Qonversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "QONExperimentGroup.h"
#import "QONExperiment.h"
#import "QONRemoteConfig.h"
#import "QONRemoteConfigList.h"
#import "QONUser.h"
#import "QONErrors.h"
#import "QONStoreKitSugare.h"
Expand Down Expand Up @@ -207,12 +208,29 @@ static NSString *const QonversionApiErrorDomain = @"com.qonversion.io.api";
/**
Returns Qonversion remote config object by context key.
Use this function to get the remote config with specific payload and experiment info.
@param contextKey context key for the requested remote config.
@param contextKey context key to load remote config for.
@param completion completion block that includes information about the remote config.
*/
- (void)remoteConfig:(NSString *)contextKey completion:(QONRemoteConfigCompletionHandler)completion
NS_SWIFT_NAME(remoteConfig(contextKey:completion:));

/**
Returns Qonversion remote config objects by a list of context keys.
Use this function to get the remote configs with specific payload and experiment info.
@param contextKeys list of context keys to load remote configs for.
@param includeEmptyContextKey - set to true if you want to include remote config with empty context key to the result
@param completion completion block that includes information about the loaded remote configs.
*/
- (void)remoteConfigList:(NSArray<NSString *> *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey completion:(QONRemoteConfigListCompletionHandler)completion
NS_SWIFT_NAME(remoteConfigList(contextKeys:includeEmptyContextKey:completion:));

/**
Returns Qonversion remote config objects for all existing context key (including empty one).
Use this function to get the remote configs with specific payload and experiment info.
@param completion completion block that includes information about the loaded remote configs.
*/
- (void)remoteConfigList:(QONRemoteConfigListCompletionHandler)completion;

/**
This function should be used for the test purposes only.
Do not forget to delete the usage of this function before the release.
Expand Down
8 changes: 8 additions & 0 deletions Sources/Qonversion/Public/Qonversion.m
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ - (void)remoteConfig:(NSString *)contextKey completion:(QONRemoteConfigCompletio
[[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigWithContextKey:contextKey completion:completion];
}

- (void)remoteConfigList:(NSArray<NSString *> *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey completion:(QONRemoteConfigListCompletionHandler)completion {
[[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigListWithContextKeys:contextKeys includeEmptyContextKey:includeEmptyContextKey completion:completion];
}

- (void)remoteConfigList:(QONRemoteConfigListCompletionHandler)completion {
[[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigList:completion];
}

- (void)attachUserToExperiment:(NSString *)experimentId groupId:(NSString *)groupId completion:(QONExperimentAttachCompletionHandler)completion {
[[[Qonversion sharedInstance] remoteConfigManager] attachUserToExperiment:experimentId groupId:groupId completion:completion];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ extern NSString *const kSdkLogsEndpoint;
extern NSString *const kSdkLogsBaseURL;
extern NSString *const kStoredRequestsKey;
extern NSString *const kRemoteConfigEndpoint;
extern NSString *const kRemoteConfigListEndpoint;

extern NSString *const kEventEndpoint;

extern NSString *const kAccessDeniedError;
extern NSString *const kInternalServerError;

extern NSUInteger const kMaxSimilarRequestsPerSecond;
extern NSUInteger const kMaxSimilarRequestsPerSecond;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
NSString * const kProductsEndpoint = @"v1/products/get";
NSString * const kPropertiesEndpoint = @"v3/users/%@/properties";
NSString * const kRemoteConfigEndpoint = @"v3/remote-config";
NSString * const kRemoteConfigListEndpoint = @"v3/remote-configs";

NSString * const kAttachUserToExperimentEndpointFormat = @"v3/experiments/%@/users/%@";
NSString * const kAttachUserToRemoteConfigurationEndpointFormat = @"v3/remote-configurations/%@/users/%@";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ typedef NS_ENUM(NSInteger, QONRequestType) {
- (NSURLRequest *)makeCreateIdentityRequestWith:(NSDictionary *)parameters;
- (NSURLRequest *)makeScreenShownRequestWith:(NSString *)parameter body:(NSDictionary *)body;
- (NSURLRequest *)makeIntroTrialEligibilityRequestWithData:(NSDictionary *)parameters;
- (NSURLRequest *)remoteConfigRequestForUserId:(NSString *)userId contextKey:(NSString *)contextKey;
- (NSURLRequest *)makeRemoteConfigRequestForUserId:(NSString *)userId contextKey:(NSString *)contextKey;
- (NSURLRequest *)makeRemoteConfigListRequestForUserId:(NSString *)userId contextKeys:(NSArray<NSString *> *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey;
- (NSURLRequest *)makeRemoteConfigListRequestForUserId:(NSString *)userId;
- (NSURLRequest *)makeSdkLogsRequestWithBody:(NSDictionary *)body;
- (NSURLRequest *)makeAttachUserToExperimentRequest:(NSString *)experimentId groupId:(NSString *)groupId userID:(NSString *)userID;
- (NSURLRequest *)makeDetachUserFromExperimentRequest:(NSString *)experimentId userID:(NSString *)userID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,34 @@ - (NSURLRequest *)makeIntroTrialEligibilityRequestWithData:(NSDictionary *)param
return [self makeRequestWithDictBody:parameters baseURL:self.baseURL endpoint:kProductsEndpoint type:QONRequestTypePost];
}

- (NSURLRequest *)remoteConfigRequestForUserId:(NSString *)userId contextKey:(NSString *)contextKey {
NSURLRequest *request = [self makeGetRequestWithBaseURL:self.baseURL endpoint:kRemoteConfigEndpoint];

NSMutableURLRequest *mutableRequest = [request mutableCopy];
NSString *updatedURLString = [mutableRequest.URL.absoluteString stringByAppendingString:[NSString stringWithFormat:@"?user_id=%@", userId]];
- (NSURLRequest *)makeRemoteConfigRequestForUserId:(NSString *)userId contextKey:(NSString *)contextKey {
NSMutableURLRequest *request = [[self makeGetRequestWithBaseURL:self.baseURL endpoint:kRemoteConfigEndpoint] mutableCopy];
NSString *updatedURLString = [request.URL.absoluteString stringByAppendingString:[NSString stringWithFormat:@"?user_id=%@", userId]];
if (contextKey) {
updatedURLString = [updatedURLString stringByAppendingString:[NSString stringWithFormat:@"&context_key=%@", contextKey]];
}
[mutableRequest setURL:[NSURL URLWithString:updatedURLString]];
[request setURL:[NSURL URLWithString:updatedURLString]];

return [request copy];
}

- (NSURLRequest *)makeRemoteConfigListRequestForUserId:(NSString *)userId contextKeys:(NSArray<NSString *> *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey {
NSMutableURLRequest *request = [[self makeGetRequestWithBaseURL:self.baseURL endpoint:kRemoteConfigListEndpoint] mutableCopy];
NSString *updatedURLString = [request.URL.absoluteString stringByAppendingString:[NSString stringWithFormat:@"?user_id=%@&with_empty_context_key=%@", userId, includeEmptyContextKey ? @"true" : @"false"]];
for (NSString *contextKey in contextKeys) {
updatedURLString = [updatedURLString stringByAppendingString:[NSString stringWithFormat:@"&context_key=%@", contextKey]];
}
[request setURL:[NSURL URLWithString:updatedURLString]];

return [request copy];
}

- (NSURLRequest *)makeRemoteConfigListRequestForUserId:(NSString *)userId {
NSMutableURLRequest *request = [[self makeGetRequestWithBaseURL:self.baseURL endpoint:kRemoteConfigListEndpoint] mutableCopy];
NSString *updatedURLString = [request.URL.absoluteString stringByAppendingString:[NSString stringWithFormat:@"?user_id=%@&all_context_keys=true", userId]];
[request setURL:[NSURL URLWithString:updatedURLString]];

return [mutableRequest copy];
return [request copy];
}

- (NSURLRequest *)makeAttachUserToExperimentRequest:(NSString *)experimentId groupId:(NSString *)groupId userID:(NSString *)userID {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)userChangingRequestFailedWithError:(NSError *)error;
- (void)handlePendingRequests;
- (void)obtainRemoteConfigWithContextKey:(NSString * _Nullable)contextKey completion:(QONRemoteConfigCompletionHandler)completion;
- (void)obtainRemoteConfigListWithContextKeys:(NSArray<NSString *> *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey completion:(QONRemoteConfigListCompletionHandler)completion;
- (void)obtainRemoteConfigList:(QONRemoteConfigListCompletionHandler)completion;
- (void)attachUserToExperiment:(NSString *)experimentId groupId:(NSString *)groupId completion:(QONExperimentAttachCompletionHandler)completion;
- (void)detachUserFromExperiment:(NSString *)experimentId completion:(QONExperimentAttachCompletionHandler)completion;
- (void)attachUserToRemoteConfiguration:(NSString *)remoteConfigurationId completion:(QONRemoteConfigurationAttachCompletionHandler)completion;
Expand Down
Loading

0 comments on commit 3c7774a

Please sign in to comment.