diff --git a/Contentstack/AssetLibrary.h b/Contentstack/AssetLibrary.h index efcbfb4..eaa7d81 100644 --- a/Contentstack/AssetLibrary.h +++ b/Contentstack/AssetLibrary.h @@ -230,6 +230,24 @@ typedef NS_ENUM(NSUInteger, OrderBy) { */ - (void)fetchAll:(void (^) (ResponseType type,NSArray * BUILT_NULLABLE_P result,NSError * BUILT_NULLABLE_P error))completionBlock; + +/** + This method fetches assets using other fields than UID.. + + //Obj-C + [assetLib where:(NSString *)field equalTo:(NSObject *)value]; + + //Swift + assetLib.where("fieldName","value"); + + This allows filtering assets by specifying the field name and the value to match. + @param field The name of the field to filter by. + @param value The value that the field should match. + */ +- (void)where:(NSString *)field equalTo:(NSObject *)value ; + +- (NSDictionary*)getPostParamDictionary; + @end BUILT_ASSUME_NONNULL_END diff --git a/Contentstack/AssetLibrary.m b/Contentstack/AssetLibrary.m index 990ba5e..4a861d0 100644 --- a/Contentstack/AssetLibrary.m +++ b/Contentstack/AssetLibrary.m @@ -156,6 +156,25 @@ - (void)cancelRequest { [self.requestOperation cancel]; } } +// MARK: - Where Query - +- (NSDictionary*) getPostParamDictionary { + return [self.postParamDictionary copy]; +} + +- (void)where:(NSString *)field equalTo:(NSObject *)value { + if (field.length == 0 || !value) { + NSLog(@"Field or value cannot be empty"); + return; + } + NSMutableDictionary *queryDict = [NSMutableDictionary dictionary]; + NSDictionary *existingQuery = self.postParamDictionary[@"query"]; + // If an existing query exists, merge it + if (existingQuery) { + [queryDict addEntriesFromDictionary:existingQuery]; + } + queryDict[field] = value; + [self.postParamDictionary setObject:queryDict forKey:@"query"]; +} @end diff --git a/Contentstack/Config.h b/Contentstack/Config.h index f41bb61..b828898 100755 --- a/Contentstack/Config.h +++ b/Contentstack/Config.h @@ -88,4 +88,27 @@ */ @property (nullable, retain) id delegate; + + +/** + Early access features + + //Obj-C + Config *config = [[Config alloc] init]; + [config setEarlyAccess:@[@"Taxonomy", @"Teams", @"Terms", @"LivePreview"]]; + + //Swift + let config = Config() + config.setEarlyAccess(["Taxonomy", "Teams", "Terms", "LivePreview"]) + + */ +@property (nonatomic, strong, nullable) NSArray *setEarlyAccess; + + +/** + Set early access features + + @param setearlyAccess An array of early access feature names + */ +- (NSDictionary *)earlyAccessHeaders; @end diff --git a/Contentstack/Config.m b/Contentstack/Config.m index 2a42703..1dbde51 100755 --- a/Contentstack/Config.m +++ b/Contentstack/Config.m @@ -15,7 +15,8 @@ -(instancetype)init { if (self) { _region = US; _host = @"cdn.contentstack.io"; - _version = kCSIO_ApiVersion; + _version = kCSIO_ApiVersion; + _setEarlyAccess = nil; } return self; } @@ -25,4 +26,11 @@ - (void)setRegion:(ContentstackRegion)region { _host = [self hostURL:_region]; } } +- (NSDictionary *)earlyAccessHeaders { + if (_setEarlyAccess.count > 0) { + NSString *earlyAccessString = [_setEarlyAccess componentsJoinedByString:@","]; + return @{@"x-header-ea": earlyAccessString}; + } + return @{}; +} @end diff --git a/Contentstack/Stack.h b/Contentstack/Stack.h index 48ff064..08fdad6 100644 --- a/Contentstack/Stack.h +++ b/Contentstack/Stack.h @@ -68,6 +68,8 @@ BUILT_ASSUME_NONNULL_BEGIN - (Taxonomy *)taxonomy; +- (NSDictionary *)getHeaders; + //MARK: - Manually set headers /**--------------------------------------------------------------------------------------- * @name Manually set headers diff --git a/Contentstack/Stack.m b/Contentstack/Stack.m index ec23d84..edb1163 100644 --- a/Contentstack/Stack.m +++ b/Contentstack/Stack.m @@ -47,6 +47,11 @@ - (instancetype)initWithAPIKey:(NSString*)apiKey andaccessToken:(NSString *)acce _commonDateFormatter.includeTime = YES; _requestOperationSet = [NSMutableSet set]; + // Add early access headers only if they exist + NSDictionary *earlyAccessHeaders = [_config earlyAccessHeaders]; + if (earlyAccessHeaders.count > 0) { + [_stackHeaders addEntriesFromDictionary:earlyAccessHeaders]; + } [self setHeader:_apiKey forKey:kCSIO_SiteApiKey]; @@ -128,6 +133,10 @@ - (void)removeHeaderForKey:(NSString *)headerKey { } } +- (NSDictionary *)getHeaders { + return [self.stackHeaders copy]; +} + - (NSString *)imageTransformWithUrl:(NSString *)url andParams:(NSDictionary *)params{ if([url rangeOfString:@"?" options:NSCaseInsensitiveSearch].length==0) { url = [url stringByAppendingString:@"?"]; diff --git a/ContentstackTest/ContentstackTest.m b/ContentstackTest/ContentstackTest.m index bd85fe9..ae88d95 100644 --- a/ContentstackTest/ContentstackTest.m +++ b/ContentstackTest/ContentstackTest.m @@ -119,6 +119,61 @@ - (void)tearDown { #pragma mark Test Case - Header +- (void)testStackHeadersEarlyAccess { + XCTestExpectation *expectation = [self expectationWithDescription:@"EarlyAccessHeadersPassed"]; + config = [[Config alloc] init]; + config.setEarlyAccess = @[@"Taxonomy", @"Teams", @"Terms", @"LivePreview"]; + csStack = [Contentstack stackWithAPIKey:@"apikey" accessToken:@"delivery_token" environmentName:@"environment" config:config]; + // Check the headers in the stack + NSDictionary *headers = [csStack getHeaders]; + // Check if the early access headers are set correctly + NSString *expectedHeaderValue = @"Taxonomy,Teams,Terms,LivePreview"; + NSString *earlyAccessHeader = headers[@"x-header-ea"]; + + XCTAssertNotNil(earlyAccessHeader, @"Early access header should be present"); + XCTAssertEqualObjects(earlyAccessHeader, expectedHeaderValue, @"Early access header should match the expected value"); + + // Fulfill the expectation to mark the test as completed + [expectation fulfill]; + + // Wait for the request to complete + [self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:^(NSError *error) { + if (error) { + XCTFail(@"Test timed out: %@", error.localizedDescription); + } + }]; +} + +- (void)testNoEarlyAccessHeaders { + XCTestExpectation *expectation = [self expectationWithDescription:@"NoEarlyAccessHeaders"]; + config = [[Config alloc] init]; + csStack = [Contentstack stackWithAPIKey:@"apikey" accessToken:@"delivery_token" environmentName:@"environment" config:config]; + + NSDictionary *headers = [csStack getHeaders]; + NSString *earlyAccessHeader = headers[@"x-header-ea"]; + XCTAssertNil(earlyAccessHeader, @"Early access header should not be present when no early access features are set"); + + [expectation fulfill]; + [self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil]; +} + +- (void)testSingleEarlyAccessHeader { + XCTestExpectation *expectation = [self expectationWithDescription:@"SingleEarlyAccessHeader"]; + config = [[Config alloc] init]; + config.setEarlyAccess = @[@"LivePreview"]; + csStack = [Contentstack stackWithAPIKey:@"apikey" accessToken:@"delivery_token" environmentName:@"environment" config:config]; + + NSDictionary *headers = [csStack getHeaders]; + NSString *expectedHeaderValue = @"LivePreview"; + NSString *earlyAccessHeader = headers[@"x-header-ea"]; + XCTAssertNotNil(earlyAccessHeader, @"Early access header should be present"); + XCTAssertEqualObjects(earlyAccessHeader, expectedHeaderValue, @"Single early access header should match the expected value"); + + [expectation fulfill]; + [self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil]; +} + + - (void)test01FetchSourceEntries { XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch All Entries"]; @@ -203,6 +258,88 @@ - (void)test04FetchAssets { [self waitForRequest]; } +- (void)testFetchAssetByQuery01{ + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By where method"]; + AssetLibrary* assets = [csStack assetLibrary]; + [assets where:@"title" equalTo:@"image1"]; + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + if (error) { + XCTFail(@"~ ERR: %@, Message = %@", error.userInfo, error.description); + } else { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssert(result.count > 0, @"Expected results, but got none."); + } + [expectation fulfill]; + }]; + [self waitForRequest]; +} + +- (void)testFetchAssetsByValidFileSize02 { + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By valid file size"]; + AssetLibrary *assets = [csStack assetLibrary]; + [assets where:@"file_size" equalTo:@(53986)]; // Valid file size + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssert(result.count > 0, @"Expected results, but got none."); + [expectation fulfill]; + }]; + [self waitForRequest]; +} + +- (void)testFetchAssetsByNonExistentFileSize03 { + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By non-existent file size"]; + AssetLibrary *assets = [csStack assetLibrary]; + [assets where:@"file_size" equalTo:@(9999999)]; // Non-existent file size + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssertEqual(result.count, 0, @"Expected no results, but got some."); + [expectation fulfill]; + }]; + [self waitForRequest]; +} + +- (void)testFetchAssetsByNonExistentTitle04 { + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By non-existent title"]; + AssetLibrary *assets = [csStack assetLibrary]; + [assets where:@"title" equalTo:@"non-existent-title.png"]; // Non-existent title + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssertEqual(result.count, 0, @"Expected no results, but got some."); + [expectation fulfill]; + }]; + [self waitForRequest]; +} + +- (void)testFetchAssetsByMultipleConditions05 { + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By multiple conditions"]; + AssetLibrary *assets = [csStack assetLibrary]; + [assets where:@"file_size" equalTo:@(6884)]; // Valid file size + [assets where:@"title" equalTo:@"image4"]; // Valid title + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssert(result.count > 0, @"Expected results, but got none."); + [expectation fulfill]; + }]; + [self waitForRequest]; +} + +- (void)testFetchAssetsByInvalidFieldName06 { + XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Asset By invalid field name"]; + AssetLibrary *assets = [csStack assetLibrary]; + [assets where:@"invalid_field" equalTo:@"value"]; // Invalid field name + [assets fetchAll:^(ResponseType type, NSArray *result, NSError *error) { + XCTAssert(type == NETWORK, @"Pass"); + XCTAssertNil(error, @"Expected no error, but got: %@", error.userInfo); + XCTAssertEqual(result.count, 0, @"Expected no results."); + [expectation fulfill]; + }]; + [self waitForRequest]; +} - (void)testGetHeader { XCTestExpectation *expectation = [self expectationWithDescription:@"Fetch Set Header"];