From d5e147ee6f34261b3351ad8b09e2be67fc401192 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Tue, 25 Jan 2022 11:49:39 +0530 Subject: [PATCH 01/10] Add sonarqube scan worflow --- .github/workflows/sonarscanCI.yml | 57 ++++++++++++++++++++++ build-wrapper-macosx-x86.zip | Bin 0 -> 100069 bytes ci_scripts/generateBuildConfigCoverage.sh | 26 ++++++++++ ci_scripts/sonarscan.sh | 14 ++++++ sonar-project.properties | 16 ++++++ 5 files changed, 113 insertions(+) create mode 100644 .github/workflows/sonarscanCI.yml create mode 100644 build-wrapper-macosx-x86.zip create mode 100644 ci_scripts/generateBuildConfigCoverage.sh create mode 100644 ci_scripts/sonarscan.sh create mode 100644 sonar-project.properties diff --git a/.github/workflows/sonarscanCI.yml b/.github/workflows/sonarscanCI.yml new file mode 100644 index 00000000..1d96f79e --- /dev/null +++ b/.github/workflows/sonarscanCI.yml @@ -0,0 +1,57 @@ +name: BVSDK Sonarqube Scan CI + +on: + push: + branches: [ develop ] + pull_request: + branches: [ develop ] + +env: + SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }} + SONAR_URL: ${{ secrets.SONAR_URL }} + +jobs: + build: + + runs-on: macos-11 + + steps: + - uses: actions/checkout@v2 + - uses: Homebrew/actions/setup-homebrew@master + + - name: Select Xcode + run: sudo Xcode-select -switch /Applications/Xcode_13.1.app + + - name: GenerateBuildConfigCoverage + run: sh '././ci_scripts/generateBuildConfigCoverage.sh' + + - uses: actions/upload-artifact@v2 + with: + name: BuildConfigAndCoverage + path: | + ${{ github.workspace }}/build + ${{ github.workspace }}/build_wrapper_output_directory + ${{ github.workspace }}/sonarqube-generic-coverage.xml + retention-days: 1 + + scan: + needs: build + + runs-on: [self-hosted,qa] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/download-artifact@v2 + with: + name: BuildConfigAndCoverage + path: ${{ github.workspace }} + - uses: actions/setup-java@v2 + with: + distribution: 'adopt' + java-version: '11' + + + - name: Sonarqube Scan + run: sh '././ci_scripts/sonarscan.sh' diff --git a/build-wrapper-macosx-x86.zip b/build-wrapper-macosx-x86.zip new file mode 100644 index 0000000000000000000000000000000000000000..9a76baa23ae7ef691408ef2262924d8b78abbc93 GIT binary patch literal 100069 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%0D^^v|##pBVIl!J*MB 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 sonarqube-generic-coverage.xml + +#Replace & with & (& in "/Sorting & Filtering/") +sed -i '.bak' 's+&+&+g' sonarqube-generic-coverage.xml +#Change absolute paths to relative paths +sed -i '.bak' "s+$(pwd)+.+g" sonarqube-generic-coverage.xml diff --git a/ci_scripts/sonarscan.sh b/ci_scripts/sonarscan.sh new file mode 100644 index 00000000..1cf4ce6b --- /dev/null +++ b/ci_scripts/sonarscan.sh @@ -0,0 +1,14 @@ +wget https://apt.llvm.org/llvm.sh +chmod +x llvm.sh +sudo ./llvm.sh 13 + +wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip +unzip sonar-scanner-cli-4.6.2.2472-linux.zip + +./sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner \ + -Dsonar.projectKey=bazaarvoice_bv-ios-sdk-dev \ + -Dsonar.sources=. \ + -Dsonar.cfamily.build-wrapper-output=build_wrapper_output_directory \ + -Dsonar.host.url=$SONAR_URL \ + -Dsonar.login=$SONAR_LOGIN \ + -Dsonar.coverageReportPaths=sonarqube-generic-coverage.xml diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000..04e0ec5b --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,16 @@ +# Project Details +sonar.projectKey=bazaarvoice_bv-ios-sdk-dev + + +# Path to source directories +# sonar.sources=SonarDemo,SonarDemoTests,SonarDemoUITests +sonar.sources=. + +# Exclude directories +sonar.test.inclusions=**/*Test*/** +sonar.test.inclusions=*.swift +sonar.exclusions=**/*.xml,Pods/**/*,Reports/**/* +sonar.inclusions=**/*.h,**/*.m + +# Path to test directories (comment if no test) +sonar.tests=BVSDKTests From 2afcc61491510d1ef0d7b71ab1f4ac69ba122f53 Mon Sep 17 00:00:00 2001 From: chetan shanbag Date: Thu, 21 Apr 2022 16:56:01 +0530 Subject: [PATCH 02/10] Mapped "ValueLabel" response object in ContextDataDistribution --- .../Display/Model/BVDistributionValue.h | 1 + .../Display/Model/BVDistributionValue.m | 1 + .../DisplayTests/ReviewDisplayTests.swift | 33 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/BVSDK/BVConversations/Display/Model/BVDistributionValue.h b/BVSDK/BVConversations/Display/Model/BVDistributionValue.h index 1af5be64..f44ce31b 100644 --- a/BVSDK/BVConversations/Display/Model/BVDistributionValue.h +++ b/BVSDK/BVConversations/Display/Model/BVDistributionValue.h @@ -14,6 +14,7 @@ @property(nonnull) NSString *value; @property(nonnull) NSNumber *count; +@property(nullable) NSString *valueLabel; - (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse; diff --git a/BVSDK/BVConversations/Display/Model/BVDistributionValue.m b/BVSDK/BVConversations/Display/Model/BVDistributionValue.m index 0cd6be7c..f601b5b5 100644 --- a/BVSDK/BVConversations/Display/Model/BVDistributionValue.m +++ b/BVSDK/BVConversations/Display/Model/BVDistributionValue.m @@ -14,6 +14,7 @@ - (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse { if ((self = [super init])) { SET_IF_NOT_NULL(self.value, apiResponse[@"Value"]) SET_IF_NOT_NULL(self.count, apiResponse[@"Count"]) + SET_IF_NOT_NULL(self.valueLabel, apiResponse[@"ValueLabel"]) } return self; } diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index b90bfbe6..a01c482b 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -471,4 +471,37 @@ class ReviewDisplayTests: XCTestCase { XCTAssertNil(error, "Something went horribly wrong, request took too long.") } } + + func testContextDataValueLabelIncludes(){ + + let configDict = ["clientId": "testcustomermobilesdk", + "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testContextDataValueLabelIncludes") + let request = BVReviewsRequest(productId: "Product1", limit: 10, offset: 0) + .include(.reviewProducts) + .addCustomDisplayParameter("Stats", withValue: "reviews") + request.load({ (response) in + + let review = response.results.first! + + XCTAssertNotNil(review.product?.reviewStatistics?.contextDataDistribution?.value(forKey: "Gender")) + + let incentivizedReviewDistribution = review.product?.reviewStatistics?.contextDataDistribution?.value(forKey: "Gender") as! BVDistributionElement + + XCTAssertEqual(incentivizedReviewDistribution.values.first?.valueLabel,"Male") + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + expectation.fulfill() + } + + self.waitForExpectations(timeout: 10) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + } } From 98debf43da8138869000a059e9377163e264d31e Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Thu, 21 Apr 2022 17:06:39 +0530 Subject: [PATCH 03/10] Add tagstats function to Review & Product Request --- .../Requests/Product/BVBaseProductRequest.h | 3 ++ .../Requests/Product/BVBaseProductRequest.m | 12 ++++++- .../Requests/Review/BVReviewsRequest.h | 2 ++ .../Requests/Review/BVReviewsRequest.m | 17 +++++++++ .../DisplayTests/ProductDisplayTests.swift | 34 ++++++++++++++++++ .../DisplayTests/ReviewDisplayTests.swift | 35 +++++++++++++++++++ 6 files changed, 102 insertions(+), 1 deletion(-) diff --git a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h index 1ebdced3..b4b3b55d 100644 --- a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h @@ -26,6 +26,9 @@ typedef void (^ProductSearchRequestCompletionHandler)( - (nonnull instancetype)includeStatistics: (BVProductIncludeTypeValue)productIncludeTypeValue; +// Includes tag statistics under review statistics +- (nonnull instancetype)tagStats:(BOOL)tagStats; + /// Inclusive filter to add for included reviews. - (nonnull instancetype) filterOnReviewFilterValue:(BVReviewFilterValue)reviewFilterValue diff --git a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m index 11a4ab01..91c7fd6a 100644 --- a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m @@ -28,7 +28,7 @@ @interface BVBaseProductRequest () NSMutableArray *pdpIncludes; @property(nonnull, nonatomic, strong, readonly) NSMutableArray *includes; - +@property BOOL tagStats; @end @implementation BVBaseProductRequest @@ -40,6 +40,7 @@ - (instancetype)init { _questionFilters = [NSMutableArray array]; _pdpIncludes = [NSMutableArray array]; self.incentivizedStats = NO; + self.tagStats = NO; } return self; @@ -100,6 +101,11 @@ - (nonnull instancetype)includeStatistics: return self; } +- (nonnull instancetype)tagStats:(BOOL)tagStats { + _tagStats = tagStats; + return self; +} + - (nonnull instancetype) filterOnReviewFilterValue:(BVReviewFilterValue)reviewFilterValue relationalFilterOperatorValue: @@ -212,6 +218,10 @@ - (nonnull NSMutableArray *)createParams { if (self.incentivizedStats == YES) { [params addObject:[BVStringKeyValuePair pairWithKey:@"incentivizedstats" value:@"true"]]; } + + if (self.tagStats == YES) { + [params addObject:[BVStringKeyValuePair pairWithKey:@"tagstats" value:@"true"]]; + } return params; } diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h index 5341a0b7..858c3745 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h @@ -39,4 +39,6 @@ typedef void (^ReviewRequestCompletionHandler)( offset:(NSUInteger)offset; - (nonnull instancetype)__unavailable init; +- (nonnull instancetype)tagStats:(BOOL)tagStats; + @end diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m index c3d75018..057e3c98 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m @@ -12,12 +12,19 @@ #import "BVSort.h" #import "BVStringKeyValuePair.h" +@interface BVReviewsRequest () + +@property BOOL tagStats; + +@end + @implementation BVReviewsRequest - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId limit:(NSUInteger)limit offset:(NSUInteger)offset { self.incentivizedStats = NO; + self.tagStats = NO; return self = [super initWithID:productId limit:limit offset:offset primaryFilter: BVReviewFilterValueProductId]; } @@ -26,15 +33,25 @@ - (nonnull instancetype)initWithId:(nonnull NSString *)Id limit:(NSUInteger)limit offset:(NSUInteger)offset { self.incentivizedStats = NO; + self.tagStats = NO; return self = [super initWithID:Id limit:limit offset:offset primaryFilter: filter]; } +- (nonnull instancetype)tagStats:(BOOL)tagStats { + _tagStats = tagStats; + return self; +} + - (nonnull NSMutableArray *)createParams { NSMutableArray *params = [super createParams]; if (self.incentivizedStats == YES) { [params addObject:[BVStringKeyValuePair pairWithKey:@"incentivizedstats" value:@"true"]]; } + + if (self.tagStats == YES) { + [params addObject:[BVStringKeyValuePair pairWithKey:@"tagstats" value:@"true"]]; + } if (self.feature) { [params addObject:[BVStringKeyValuePair pairWithKey:@"feature" value:self.feature]]; diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift index bcacd9b8..48271676 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift @@ -153,4 +153,38 @@ class ProductDisplayTests: XCTestCase { XCTAssertNil(error, "Something went horribly wrong, request took too long.") } } + + func testProductRequestTagStats() { + + let expectation = self.expectation(description: "testProductStatisticsTagStats") + + let request = BVProductDisplayPageRequest(productId: "test1") + .addCustomDisplayParameter("stats", withValue: "reviews") + .tagStats(true) + + request.load({ (response) in + + let reviewStatistics = response.result?.reviewStatistics + XCTAssertNotNil(reviewStatistics?.tagDistribution!["Con"]) + let conTagDistribution = reviewStatistics?.tagDistribution!["Con"] as! BVDistributionElement + let conTagDistributionValues = conTagDistribution.values + + XCTAssertEqual(conTagDistributionValues.count, 10) + XCTAssertEqual(conTagDistributionValues.first?.count,30) + XCTAssertEqual(conTagDistributionValues.first?.value,"Quality") + + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } } diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index a01c482b..5bfb49b6 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -120,6 +120,41 @@ class ReviewDisplayTests: XCTestCase { } + + func testReviewsRequestTagStats() { + + let expectation = self.expectation(description: "testReviewStatisticsTagStats") + + let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 0) + .include(.reviewProducts) + .tagStats(true) + + request.load({ (response) in + + let includedProduct = response.results.first?.product + XCTAssertNotNil(includedProduct?.reviewStatistics?.tagDistribution!["Con"]) + let conTagDistribution = includedProduct?.reviewStatistics?.tagDistribution!["Con"] as! BVDistributionElement + let conTagDistributionValues = conTagDistribution.values + + XCTAssertEqual(conTagDistributionValues.count, 10) + XCTAssertEqual(conTagDistributionValues.first?.count,30) + XCTAssertEqual(conTagDistributionValues.first?.value,"Quality") + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + func testReviewEmptyFeatureFilter() { let expectation = self.expectation(description: "testReviewDisplay") From c22be14a26d9a0ed08ce56474d50dfceb16ae101 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Thu, 21 Apr 2022 18:12:36 +0530 Subject: [PATCH 04/10] Add a feature method to BVReviewsRequest --- .../Display/Requests/Feature/BVFeaturesRequest.h | 4 ---- .../Display/Requests/Feature/BVFeaturesRequest.m | 7 +++++++ .../Display/Requests/Review/BVReviewsRequest.h | 2 +- .../Display/Requests/Review/BVReviewsRequest.m | 6 ++++++ .../DisplayTests/ReviewDisplayTests.swift | 4 ++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.h b/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.h index 20007f98..61c9577e 100644 --- a/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.h @@ -10,10 +10,6 @@ @interface BVFeaturesRequest : BVConversationsRequest -@property(nonnull, readonly) NSString *productId; -@property(nonnull, readonly) NSString *language; - - - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId; - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId language:(nonnull NSString *)language; - (nonnull instancetype)__unavailable init; diff --git a/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.m b/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.m index 0f6238e8..6f20ad4c 100644 --- a/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Feature/BVFeaturesRequest.m @@ -10,6 +10,13 @@ #import "BVConversationsRequest+Private.h" #import "BVStringKeyValuePair.h" +@interface BVFeaturesRequest () + +@property(nonnull, readonly) NSString *productId; +@property(nonnull, readonly) NSString *language; + +@end + @implementation BVFeaturesRequest - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId { diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h index 858c3745..1752e947 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h @@ -27,7 +27,6 @@ typedef void (^ReviewRequestCompletionHandler)( @property(nonnull, readonly) NSString *productId; @property BOOL incentivizedStats; -@property(nullable) NSString *feature; - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId limit:(NSUInteger)limit @@ -38,6 +37,7 @@ typedef void (^ReviewRequestCompletionHandler)( limit:(NSUInteger)limit offset:(NSUInteger)offset; - (nonnull instancetype)__unavailable init; +- (nonnull instancetype)feature:(nullable NSString *)feature; - (nonnull instancetype)tagStats:(BOOL)tagStats; diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m index 057e3c98..741210f1 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m @@ -14,6 +14,7 @@ @interface BVReviewsRequest () +@property(nullable) NSString *feature; @property BOOL tagStats; @end @@ -37,6 +38,11 @@ - (nonnull instancetype)initWithId:(nonnull NSString *)Id return self = [super initWithID:Id limit:limit offset:offset primaryFilter: filter]; } +- (nonnull instancetype)feature:(nullable NSString *)feature{ + _feature = feature; + return self; +} + - (nonnull instancetype)tagStats:(BOOL)tagStats { _tagStats = tagStats; return self; diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index 5bfb49b6..18cab9f7 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -101,7 +101,7 @@ class ReviewDisplayTests: XCTestCase { let expectation = self.expectation(description: "testReviewDisplay") let request = BVReviewsRequest(productId: "XYZ123-prod-3-4-ExternalId", limit: 5, offset: 0) - request.feature = "speed" + .feature("speed") request.load({ (response) in @@ -160,7 +160,7 @@ class ReviewDisplayTests: XCTestCase { let expectation = self.expectation(description: "testReviewDisplay") let request = BVReviewsRequest(productId: "XYZ123-prod-3-4-ExternalId", limit: 5, offset: 0) - request.feature = "" + .feature("") request.load({ (response) in From 7ad62cdc0ea1c75ca82d517e8a8eab5883bc6476 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Thu, 21 Apr 2022 23:49:38 +0530 Subject: [PATCH 05/10] Add secondary ratings distribution to BVReviewStatistics --- BVSDK.xcodeproj/project.pbxproj | 16 ++++++ .../Model/BVDimensionAndDistributionUtil.h | 3 + .../Model/BVDimensionAndDistributionUtil.m | 19 +++++++ .../Display/Model/BVReviewStatistics.h | 1 + .../Display/Model/BVReviewStatistics.m | 2 + .../BVSecondaryRatingsDistributionElement.h | 20 +++++++ .../BVSecondaryRatingsDistributionElement.m | 29 ++++++++++ .../BVSecondaryRatingsDistributionValue.h | 21 +++++++ .../BVSecondaryRatingsDistributionValue.m | 22 ++++++++ .../BVDimensionAndDistributionUtil+Private.h | 2 + .../Requests/Product/BVBaseProductRequest.h | 4 ++ .../Requests/Product/BVBaseProductRequest.m | 12 ++++ .../Requests/Review/BVReviewsRequest.h | 3 + .../Requests/Review/BVReviewsRequest.m | 21 +++++-- .../DisplayTests/ProductDisplayTests.swift | 55 ++++++++++++++++++- .../DisplayTests/ReviewDisplayTests.swift | 48 ++++++++++++++++ 16 files changed, 271 insertions(+), 7 deletions(-) create mode 100644 BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.h create mode 100644 BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.m create mode 100644 BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.h create mode 100644 BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.m diff --git a/BVSDK.xcodeproj/project.pbxproj b/BVSDK.xcodeproj/project.pbxproj index ca93a044..dbbef136 100644 --- a/BVSDK.xcodeproj/project.pbxproj +++ b/BVSDK.xcodeproj/project.pbxproj @@ -40,6 +40,10 @@ 15BE4D261E55F03200C12B57 /* BVCurationsUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 870F133E1E490B5200D46BE6 /* BVCurationsUICollectionView.m */; }; 15D4F83B1DF5D5F800E6B30D /* testNotificationProductConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = 15D4F83A1DF5D5F800E6B30D /* testNotificationProductConfig.json */; }; 15D4F83F1DF5EC3C00E6B30D /* ph.png in Resources */ = {isa = PBXBuildFile; fileRef = 15D4F83E1DF5EC3C00E6B30D /* ph.png */; }; + 2E371E592808226B008D9223 /* BVSecondaryRatingsDistributionElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E371E572808226B008D9223 /* BVSecondaryRatingsDistributionElement.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2E371E5A2808226B008D9223 /* BVSecondaryRatingsDistributionElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E371E582808226B008D9223 /* BVSecondaryRatingsDistributionElement.m */; }; + 2E371E5D280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E371E5B280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2E371E5E280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E371E5C280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m */; }; 2E998AC82789963D0036DE64 /* BVFeaturesRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AC72789963D0036DE64 /* BVFeaturesRequest.m */; }; 2E998ACB2789967E0036DE64 /* BVFeaturesResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998ACA2789967E0036DE64 /* BVFeaturesResponse.m */; }; 2E998ACD278996940036DE64 /* BVFeaturesRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E998ACC278996940036DE64 /* BVFeaturesRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -683,6 +687,10 @@ 15D4F83A1DF5D5F800E6B30D /* testNotificationProductConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = testNotificationProductConfig.json; sourceTree = ""; }; 15D4F83E1DF5EC3C00E6B30D /* ph.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ph.png; sourceTree = ""; }; 15D4F8451DF5EFFF00E6B30D /* BVSDKTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BVSDKTests-Bridging-Header.h"; sourceTree = ""; }; + 2E371E572808226B008D9223 /* BVSecondaryRatingsDistributionElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVSecondaryRatingsDistributionElement.h; sourceTree = ""; }; + 2E371E582808226B008D9223 /* BVSecondaryRatingsDistributionElement.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVSecondaryRatingsDistributionElement.m; sourceTree = ""; }; + 2E371E5B280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVSecondaryRatingsDistributionValue.h; sourceTree = ""; }; + 2E371E5C280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVSecondaryRatingsDistributionValue.m; sourceTree = ""; }; 2E998AC72789963D0036DE64 /* BVFeaturesRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeaturesRequest.m; sourceTree = ""; }; 2E998ACA2789967E0036DE64 /* BVFeaturesResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeaturesResponse.m; sourceTree = ""; }; 2E998ACC278996940036DE64 /* BVFeaturesRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVFeaturesRequest.h; sourceTree = ""; }; @@ -1629,8 +1637,12 @@ 87F2DB261DAD585E00FB43F3 /* BVDimensionElement.m */, 87F2DB281DAD585E00FB43F3 /* BVDistributionElement.h */, 87F2DB291DAD585E00FB43F3 /* BVDistributionElement.m */, + 2E371E572808226B008D9223 /* BVSecondaryRatingsDistributionElement.h */, + 2E371E582808226B008D9223 /* BVSecondaryRatingsDistributionElement.m */, 87F2DB2A1DAD585E00FB43F3 /* BVDistributionValue.h */, 87F2DB2B1DAD585E00FB43F3 /* BVDistributionValue.m */, + 2E371E5B280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h */, + 2E371E5C280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m */, 5FE2C0801F6B05100090DD55 /* BVErrorCode.h */, 87F2DB2F1DAD585E00FB43F3 /* BVPhoto.h */, 87F2DB301DAD585E00FB43F3 /* BVPhoto.m */, @@ -2670,6 +2682,8 @@ buildActionMask = 2147483647; files = ( 2E998ACD278996940036DE64 /* BVFeaturesRequest.h in Headers */, + 2E371E5D280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h in Headers */, + 2E371E592808226B008D9223 /* BVSecondaryRatingsDistributionElement.h in Headers */, 2E998ACF278996A80036DE64 /* BVFeaturesResponse.h in Headers */, 2E998AD32789B3F00036DE64 /* BVFeatures.h in Headers */, 87D424F31E8AD45400147FDB /* BVCurationsUICollectionView.h in Headers */, @@ -3313,6 +3327,7 @@ 1539745D1E719B9600BA52C1 /* BVDisplayResponse.m in Sources */, 87F2DD141DAD585E00FB43F3 /* BVReviewTableViewCell.m in Sources */, 87F2DCEC1DAD585E00FB43F3 /* BVSubmittedQuestion.m in Sources */, + 2E371E5E280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m in Sources */, 87C5FF5D1E36A8B7004EE6E8 /* BVAuthorResponse.m in Sources */, 87A02B671E096B300002701B /* BVFeedbackSubmissionResponse.m in Sources */, 87F2DC5F1DAD585E00FB43F3 /* BVBadgeType.m in Sources */, @@ -3366,6 +3381,7 @@ B586398E214AFBD000EFD763 /* BVConversationsError.m in Sources */, 987C075F2252913B00227934 /* BVInitiateSubmitResponseData.m in Sources */, 87F2DC901DAD585E00FB43F3 /* BVSecondaryRatingsAverages.m in Sources */, + 2E371E5A2808226B008D9223 /* BVSecondaryRatingsDistributionElement.m in Sources */, 87F2DCDC1DAD585E00FB43F3 /* BVSubmissionAction.m in Sources */, 8754117E1E1F201E006C5C6E /* BVProductReviewRichNotificationCenter.m in Sources */, 875410B51E1F10DF006C5C6E /* BVStoreReviewNotificationViewController.m in Sources */, diff --git a/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.h b/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.h index 63cc5507..47b83e8e 100644 --- a/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.h +++ b/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.h @@ -7,10 +7,13 @@ #import "BVDimensionElement.h" #import "BVDistributionElement.h" +#import "BVSecondaryRatingsDistributionElement.h" #import typedef NSMutableDictionary *TagDistribution; +typedef NSMutableDictionary + *SecondaryRatingsDistribution; typedef NSMutableDictionary *ContextDataDistribution; typedef NSMutableDictionary *TagDimensions; diff --git a/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.m b/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.m index 9798849b..f3786ff2 100644 --- a/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.m +++ b/BVSDK/BVConversations/Display/Model/BVDimensionAndDistributionUtil.m @@ -28,4 +28,23 @@ + (nullable TagDistribution)createDistributionWithApiResponse: return tempValues; } ++ (nullable SecondaryRatingsDistribution)createSecondaryRatingsDistributionWithApiResponse: + (nullable id)apiResponse { + if (!apiResponse) { + return nil; + } + + NSDictionary *apiObject = + (NSDictionary *)apiResponse; + SecondaryRatingsDistribution tempValues = [NSMutableDictionary dictionary]; + for (NSString *key in apiObject) { + NSDictionary *value = [apiObject objectForKey:key]; + BVSecondaryRatingsDistributionElement *element = + [[BVSecondaryRatingsDistributionElement alloc] initWithApiResponse:value]; + [tempValues setObject:element forKey:key]; + } + + return tempValues; +} + @end diff --git a/BVSDK/BVConversations/Display/Model/BVReviewStatistics.h b/BVSDK/BVConversations/Display/Model/BVReviewStatistics.h index 6e726ca5..9de48506 100644 --- a/BVSDK/BVConversations/Display/Model/BVReviewStatistics.h +++ b/BVSDK/BVConversations/Display/Model/BVReviewStatistics.h @@ -30,6 +30,7 @@ @property(nullable) BVRatingDistribution *ratingDistribution; @property(nullable) TagDistribution tagDistribution; +@property(nullable) SecondaryRatingsDistribution secondaryRatingsDistribution; @property(nullable) ContextDataDistribution contextDataDistribution; @property(nullable) NSDate *firstSubmissionTime; diff --git a/BVSDK/BVConversations/Display/Model/BVReviewStatistics.m b/BVSDK/BVConversations/Display/Model/BVReviewStatistics.m index e65cbd79..123bd0e2 100644 --- a/BVSDK/BVConversations/Display/Model/BVReviewStatistics.m +++ b/BVSDK/BVConversations/Display/Model/BVReviewStatistics.m @@ -38,6 +38,8 @@ - (nullable id)initWithApiResponse:(nullable id)apiResponse { createWithDictionary:apiObject[@"SecondaryRatingsAverages"]]; self.tagDistribution = [BVDimensionAndDistributionUtil createDistributionWithApiResponse:apiObject[@"TagDistribution"]]; + self.secondaryRatingsDistribution = [BVDimensionAndDistributionUtil + createSecondaryRatingsDistributionWithApiResponse:apiObject[@"SecondaryRatingsDistribution"]]; self.contextDataDistribution = [BVDimensionAndDistributionUtil createDistributionWithApiResponse:apiObject [@"ContextDataDistribution"]]; diff --git a/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.h b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.h new file mode 100644 index 00000000..4b8ffb68 --- /dev/null +++ b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.h @@ -0,0 +1,20 @@ +// +// BVGenericDimensionElement.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import "BVSecondaryRatingsDistributionValue.h" +#import + + +@interface BVSecondaryRatingsDistributionElement : NSObject + +@property(nonnull) NSString *label; +@property(nonnull) NSString *identifier; +@property(nonnull) NSArray *values; + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse; + +@end diff --git a/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.m b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.m new file mode 100644 index 00000000..8cf2b2ab --- /dev/null +++ b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionElement.m @@ -0,0 +1,29 @@ +// +// BVGenericDimensionElement.m +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import "BVSecondaryRatingsDistributionElement.h" +#import "BVNullHelper.h" + +@implementation BVSecondaryRatingsDistributionElement + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse { + if ((self = [super init])) { + SET_IF_NOT_NULL(self.label, apiResponse[@"Label"]) + SET_IF_NOT_NULL(self.identifier, apiResponse[@"Id"]) + + NSMutableArray *tempValues = [NSMutableArray array]; + for (NSDictionary *value in apiResponse[@"Values"]) { + BVSecondaryRatingsDistributionValue *distributionValue = + [[BVSecondaryRatingsDistributionValue alloc] initWithApiResponse:value]; + [tempValues addObject:distributionValue]; + } + self.values = tempValues; + } + return self; +} + +@end diff --git a/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.h b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.h new file mode 100644 index 00000000..457d8e43 --- /dev/null +++ b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.h @@ -0,0 +1,21 @@ +// +// BVSecondaryRatingsDistributionValue.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import + +/* + The value of a secondary rating distribution -- see BVGenericValueDistributionElement.h + */ +@interface BVSecondaryRatingsDistributionValue : NSObject + +@property(nonnull) NSNumber *value; +@property(nonnull) NSNumber *count; +@property(nullable) NSString *valueLabel; + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse; + +@end diff --git a/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.m b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.m new file mode 100644 index 00000000..0636ddc2 --- /dev/null +++ b/BVSDK/BVConversations/Display/Model/BVSecondaryRatingsDistributionValue.m @@ -0,0 +1,22 @@ +// +// BVSecondaryRatingsDistributionValue.m +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import "BVSecondaryRatingsDistributionValue.h" +#import "BVNullHelper.h" + +@implementation BVSecondaryRatingsDistributionValue + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse { + if ((self = [super init])) { + SET_IF_NOT_NULL(self.value, apiResponse[@"Value"]) + SET_IF_NOT_NULL(self.count, apiResponse[@"Count"]) + SET_IF_NOT_NULL(self.valueLabel, apiResponse[@"ValueLabel"]) + } + return self; +} + +@end diff --git a/BVSDK/BVConversations/Display/Model/Private/BVDimensionAndDistributionUtil+Private.h b/BVSDK/BVConversations/Display/Model/Private/BVDimensionAndDistributionUtil+Private.h index e550acf1..f247fdd7 100644 --- a/BVSDK/BVConversations/Display/Model/Private/BVDimensionAndDistributionUtil+Private.h +++ b/BVSDK/BVConversations/Display/Model/Private/BVDimensionAndDistributionUtil+Private.h @@ -14,6 +14,8 @@ + (nullable TagDistribution)createDistributionWithApiResponse: (nullable id)apiResponse; ++ (nullable SecondaryRatingsDistribution)createSecondaryRatingsDistributionWithApiResponse: + (nullable id)apiResponse; @end diff --git a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h index b4b3b55d..6fe9655e 100644 --- a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.h @@ -16,6 +16,7 @@ typedef void (^ProductSearchRequestCompletionHandler)( @property BOOL incentivizedStats; + /// Type of social content to include with the product request. NOTE: /// BVProductIncludeTypeValue is only supported for statistics, no for Includes. - (nonnull instancetype)includeProductIncludeTypeValue: @@ -26,6 +27,9 @@ typedef void (^ProductSearchRequestCompletionHandler)( - (nonnull instancetype)includeStatistics: (BVProductIncludeTypeValue)productIncludeTypeValue; +// Includes secondary ratings distribution under review statistics +- (nonnull instancetype)secondaryRatingStats:(BOOL)secondaryRatingStats; + // Includes tag statistics under review statistics - (nonnull instancetype)tagStats:(BOOL)tagStats; diff --git a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m index 91c7fd6a..27cc5955 100644 --- a/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Product/BVBaseProductRequest.m @@ -28,7 +28,9 @@ @interface BVBaseProductRequest () NSMutableArray *pdpIncludes; @property(nonnull, nonatomic, strong, readonly) NSMutableArray *includes; +@property BOOL secondaryRatingStats; @property BOOL tagStats; + @end @implementation BVBaseProductRequest @@ -40,6 +42,7 @@ - (instancetype)init { _questionFilters = [NSMutableArray array]; _pdpIncludes = [NSMutableArray array]; self.incentivizedStats = NO; + self.secondaryRatingStats = NO; self.tagStats = NO; } @@ -101,6 +104,11 @@ - (nonnull instancetype)includeStatistics: return self; } +- (nonnull instancetype)secondaryRatingStats:(BOOL)secondaryRatingStats { + _secondaryRatingStats = secondaryRatingStats; + return self; +} + - (nonnull instancetype)tagStats:(BOOL)tagStats { _tagStats = tagStats; return self; @@ -219,6 +227,10 @@ - (nonnull NSMutableArray *)createParams { [params addObject:[BVStringKeyValuePair pairWithKey:@"incentivizedstats" value:@"true"]]; } + if (self.secondaryRatingStats == YES) { + [params addObject:[BVStringKeyValuePair pairWithKey:@"secondaryratingstats" value:@"true"]]; + } + if (self.tagStats == YES) { [params addObject:[BVStringKeyValuePair pairWithKey:@"tagstats" value:@"true"]]; } diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h index 1752e947..5a068053 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.h @@ -37,8 +37,11 @@ typedef void (^ReviewRequestCompletionHandler)( limit:(NSUInteger)limit offset:(NSUInteger)offset; - (nonnull instancetype)__unavailable init; + - (nonnull instancetype)feature:(nullable NSString *)feature; - (nonnull instancetype)tagStats:(BOOL)tagStats; +- (nonnull instancetype)secondaryRatingStats:(BOOL)secondaryRatingStats; + @end diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m index 741210f1..da7757ea 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Review/BVReviewsRequest.m @@ -14,8 +14,9 @@ @interface BVReviewsRequest () -@property(nullable) NSString *feature; +@property BOOL secondaryRatingStats; @property BOOL tagStats; +@property(nullable) NSString *feature; @end @@ -25,6 +26,7 @@ - (nonnull instancetype)initWithProductId:(nonnull NSString *)productId limit:(NSUInteger)limit offset:(NSUInteger)offset { self.incentivizedStats = NO; + self.secondaryRatingStats = NO; self.tagStats = NO; return self = [super initWithID:productId limit:limit offset:offset primaryFilter: BVReviewFilterValueProductId]; } @@ -34,13 +36,14 @@ - (nonnull instancetype)initWithId:(nonnull NSString *)Id limit:(NSUInteger)limit offset:(NSUInteger)offset { self.incentivizedStats = NO; + self.secondaryRatingStats = NO; self.tagStats = NO; return self = [super initWithID:Id limit:limit offset:offset primaryFilter: filter]; } -- (nonnull instancetype)feature:(nullable NSString *)feature{ - _feature = feature; - return self; +- (nonnull instancetype)secondaryRatingStats:(BOOL)secondaryRatingStats { + _secondaryRatingStats = secondaryRatingStats; + return self; } - (nonnull instancetype)tagStats:(BOOL)tagStats { @@ -48,12 +51,22 @@ - (nonnull instancetype)tagStats:(BOOL)tagStats { return self; } +- (nonnull instancetype)feature:(nullable NSString *)feature{ + _feature = feature; + return self; +} + + - (nonnull NSMutableArray *)createParams { NSMutableArray *params = [super createParams]; if (self.incentivizedStats == YES) { [params addObject:[BVStringKeyValuePair pairWithKey:@"incentivizedstats" value:@"true"]]; } + + if (self.secondaryRatingStats == YES) { + [params addObject:[BVStringKeyValuePair pairWithKey:@"secondaryratingstats" value:@"true"]]; + } if (self.tagStats == YES) { [params addObject:[BVStringKeyValuePair pairWithKey:@"tagstats" value:@"true"]]; diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift index 48271676..b49fe919 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ProductDisplayTests.swift @@ -154,7 +154,55 @@ class ProductDisplayTests: XCTestCase { } } - func testProductRequestTagStats() { + func testProductRequestSecondaryRatingsDistribution() { + + let configDict = ["clientId": "testcustomermobilesdk", + "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testProductRequestSecondaryRatingsDistribution") + + let request = BVProductDisplayPageRequest(productId: "Product1") + .addCustomDisplayParameter("stats", withValue: "Reviews") + .secondaryRatingStats(true) + + request.load({ (response) in + + let reviewStatistics = response.result?.reviewStatistics + XCTAssertNotNil(reviewStatistics?.secondaryRatingsDistribution!["WhatSizeIsTheProduct"]) + let productSizeSecondaryRatingsDistribution = reviewStatistics?.secondaryRatingsDistribution!["WhatSizeIsTheProduct"] as! BVSecondaryRatingsDistributionElement + XCTAssertEqual(productSizeSecondaryRatingsDistribution.label,"What size is the product?") + let productSizeSecondaryRatingsDistributionValues = productSizeSecondaryRatingsDistribution.values + + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.count,9) + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.value,2) + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.valueLabel,"Medium") + + XCTAssertNotNil(reviewStatistics?.secondaryRatingsDistribution!["Quality"]) + let qualitySecondaryRatingsDistribution = reviewStatistics?.secondaryRatingsDistribution!["Quality"] as! BVSecondaryRatingsDistributionElement + XCTAssertEqual(qualitySecondaryRatingsDistribution.label,"Quality of Product") + let qualitySecondaryRatingsDistributionValues = qualitySecondaryRatingsDistribution.values + + XCTAssertEqual(qualitySecondaryRatingsDistributionValues.first?.count,9) + XCTAssertEqual(qualitySecondaryRatingsDistributionValues.first?.value,4) + XCTAssertNil(qualitySecondaryRatingsDistributionValues.first!.valueLabel) + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + expectation.fulfill() + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + func testProductRequestTagStats() { let expectation = self.expectation(description: "testProductStatisticsTagStats") @@ -175,10 +223,11 @@ class ProductDisplayTests: XCTestCase { expectation.fulfill() - - }) { (error) in + + }) { (error) in XCTFail("review display request error: \(error)") + expectation.fulfill() } diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index 18cab9f7..b00cd075 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -506,6 +506,54 @@ class ReviewDisplayTests: XCTestCase { XCTAssertNil(error, "Something went horribly wrong, request took too long.") } } + + + func testReviewRequestSecondaryRatingsDistribution() { + + let configDict = ["clientId": "testcustomermobilesdk", + "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testReviewRequestSecondaryRatingsDistribution") + + let request = BVReviewsRequest(productId: "Product1", limit: 10, offset: 0) + .include(.reviewProducts) + .secondaryRatingStats(true) + + request.load({ (response) in + + let reviewStatistics = response.results.first?.product?.reviewStatistics + XCTAssertNotNil(reviewStatistics?.secondaryRatingsDistribution!["WhatSizeIsTheProduct"]) + let productSizeSecondaryRatingsDistribution = reviewStatistics?.secondaryRatingsDistribution!["WhatSizeIsTheProduct"] as! BVSecondaryRatingsDistributionElement + XCTAssertEqual(productSizeSecondaryRatingsDistribution.label,"What size is the product?") + let productSizeSecondaryRatingsDistributionValues = productSizeSecondaryRatingsDistribution.values + + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.count,9) + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.value,2) + XCTAssertEqual(productSizeSecondaryRatingsDistributionValues.first?.valueLabel,"Medium") + + XCTAssertNotNil(reviewStatistics?.secondaryRatingsDistribution!["Quality"]) + let qualitySecondaryRatingsDistribution = reviewStatistics?.secondaryRatingsDistribution!["Quality"] as! BVSecondaryRatingsDistributionElement + XCTAssertEqual(qualitySecondaryRatingsDistribution.label,"Quality of Product") + let qualitySecondaryRatingsDistributionValues = qualitySecondaryRatingsDistribution.values + + XCTAssertEqual(qualitySecondaryRatingsDistributionValues.first?.count,9) + XCTAssertEqual(qualitySecondaryRatingsDistributionValues.first?.value,4) + XCTAssertNil(qualitySecondaryRatingsDistributionValues.first!.valueLabel) + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + expectation.fulfill() + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } func testContextDataValueLabelIncludes(){ From a013ffc4d06143fcb2a861969ddbc2440ebbdf69 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Fri, 22 Apr 2022 00:17:49 +0530 Subject: [PATCH 06/10] Add filter by secondary rating,additional field, tag dimension, cdv option to BVReviewsRequest --- BVSDK.xcodeproj/project.pbxproj | 4 + .../Requests/Review/BVBaseReviewsRequest.h | 12 ++ .../Requests/Review/BVBaseReviewsRequest.m | 50 ++++++ .../Sorting & Filtering/BVFilterTypeValues.h | 1 + .../BVReviewFilterFieldType.h | 21 +++ .../DisplayTests/ReviewDisplayTests.swift | 146 +++++++++++++++++- 6 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewFilterFieldType.h diff --git a/BVSDK.xcodeproj/project.pbxproj b/BVSDK.xcodeproj/project.pbxproj index dbbef136..9ae3fb01 100644 --- a/BVSDK.xcodeproj/project.pbxproj +++ b/BVSDK.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 2E998AD72789B4C20036DE64 /* BVFeature.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AD62789B4C20036DE64 /* BVFeature.m */; }; 2E998AD9278BF02A0036DE64 /* FeatureDisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AD8278BF02A0036DE64 /* FeatureDisplayTests.swift */; }; 2EAD31C326DCAC8600903208 /* BVAuthenticatedUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EAD31C226DCAC8600903208 /* BVAuthenticatedUser.m */; }; + 2EE2579127F23EE300E6DBDE /* BVReviewFilterFieldType.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5F140C5D1F9553FE00905828 /* skelly_android.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F140C5C1F9553FE00905828 /* skelly_android.jpg */; }; 5F51EA4D1F575659002FA8FD /* BVFormInputType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F51EA4C1F575659002FA8FD /* BVFormInputType.m */; }; 5F51EA501F5F2BB4002FA8FD /* BVFormInputType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F51EA4B1F575578002FA8FD /* BVFormInputType.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -701,6 +702,7 @@ 2E998AD62789B4C20036DE64 /* BVFeature.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeature.m; sourceTree = ""; }; 2E998AD8278BF02A0036DE64 /* FeatureDisplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureDisplayTests.swift; sourceTree = ""; }; 2EAD31C226DCAC8600903208 /* BVAuthenticatedUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BVAuthenticatedUser.m; sourceTree = ""; }; + 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVReviewFilterFieldType.h; sourceTree = ""; }; 3462CE8D50CC0B93A458E62C /* Pods-BVSDKTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BVSDKTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BVSDKTests/Pods-BVSDKTests.debug.xcconfig"; sourceTree = ""; }; 5F140C5C1F9553FE00905828 /* skelly_android.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = skelly_android.jpg; sourceTree = ""; }; 5F51EA4B1F575578002FA8FD /* BVFormInputType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVFormInputType.h; sourceTree = ""; }; @@ -1753,6 +1755,7 @@ B5BE76A3200EA5EC002BA818 /* BVQuestionsSortOptionValue.h */, B5BE7691200EA0CA002BA818 /* BVRelationalFilterOperatorValue.h */, B5BE7693200EA157002BA818 /* BVReviewFilterValue.h */, + 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */, B5BE76A5200EA666002BA818 /* BVReviewIncludeTypeValue.h */, B5BE76A7200EA6B4002BA818 /* BVReviewsSortOptionValue.h */, B583B124200E8ABE001E9548 /* BVSortOptionValues.h */, @@ -2902,6 +2905,7 @@ 873DC49B1E7482840080FA03 /* BVPersonalizationEvent.h in Headers */, B5BE76A0200EA53D002BA818 /* BVProductIncludeTypeValue.h in Headers */, B58639B2214AFE0A00EFD763 /* BVSDKManager+Private.h in Headers */, + 2EE2579127F23EE300E6DBDE /* BVReviewFilterFieldType.h in Headers */, 982B607522EA125C0041D40B /* BVProgressiveSubmissionReview.h in Headers */, B5BE769C200EA473002BA818 /* BVCommentsSortOptionValue.h in Headers */, 873DC4931E7482840080FA03 /* BVFeatureUsedEvent.h in Headers */, diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h index 523cd612..52b98141 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h @@ -46,6 +46,18 @@ sortByReviewsSortOptionValue:(BVReviewsSortOptionValue)reviewsSortOptionValue (BVRelationalFilterOperatorValue)relationalFilterOperatorValue values:(nonnull NSArray *)values; +- (nonnull instancetype) + filterOnReviewFilterFieldType:(BVReviewFilterFieldType)reviewFilterFieldType + fieldId:(nonnull NSString *)reviewFilterFieldId + relationalFilterOperatorValue:(BVRelationalFilterOperatorValue)relationalFilterOperatorValue + value:(nonnull NSString *)value; + +- (nonnull instancetype) +filterOnReviewFilterFieldType:(BVReviewFilterFieldType)reviewFilterFieldType + fieldId:(nonnull NSString *)reviewFilterFieldId +relationalFilterOperatorValue:(BVRelationalFilterOperatorValue)relationalFilterOperatorValue + values:(nonnull NSArray *)values; + - (void)load:(nonnull void (^)(BVResponseType __nonnull response))success failure:(nonnull ConversationsFailureHandler)failure; diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m index 6c3216f5..61a305cc 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m @@ -184,6 +184,56 @@ - (nonnull instancetype)includeReviewIncludeTypeValue: return self; } +- (nonnull instancetype) + filterOnReviewFilterFieldType:(BVReviewFilterFieldType)reviewFilterFieldType + fieldId:(nonnull NSString *)reviewFilterFieldId + relationalFilterOperatorValue:(BVRelationalFilterOperatorValue)relationalFilterOperatorValue + value:(nonnull NSString *)value { + [self filterOnReviewFilterFieldType:reviewFilterFieldType + fieldId:reviewFilterFieldId + relationalFilterOperatorValue:relationalFilterOperatorValue + values:@[ value ]]; + return self; +} + +- (nonnull instancetype) +filterOnReviewFilterFieldType:(BVReviewFilterFieldType)reviewFilterFieldType + fieldId:(nonnull NSString *)reviewFilterFieldId +relationalFilterOperatorValue:(BVRelationalFilterOperatorValue)relationalFilterOperatorValue + values:(nonnull NSArray *)values { + + NSString *reviewFilterFieldTypeString; + + switch (reviewFilterFieldType) { + case BVReviewFilterFieldTypeAdditionalField: + reviewFilterFieldTypeString = @"AdditionalField"; + break; + case BVReviewFilterFieldTypeContextDataValue: + reviewFilterFieldTypeString = @"ContextDataValue"; + break; + case BVReviewFilterFieldTypeSecondaryRating: + reviewFilterFieldTypeString = @"SecondaryRating"; + break; + case BVReviewFilterFieldTypeTag: + reviewFilterFieldTypeString = @"Tag"; + break; + } + + NSString *reviewFilterField = [NSString stringWithFormat: @"%@_%@", reviewFilterFieldTypeString, reviewFilterFieldId]; + + + BVFilter *filter = [[BVFilter alloc] + initWithString: reviewFilterField + filterOperator: + [BVRelationalFilterOperator + filterOperatorWithRawValue:relationalFilterOperatorValue] + values:values]; + + [self.filters addObject:filter]; + + return self; +} + - (void)load:(nonnull void (^)( BVDisplayResponse *__nonnull response))success failure:(nonnull ConversationsFailureHandler)failure { diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/BVFilterTypeValues.h b/BVSDK/BVConversations/Display/Sorting & Filtering/BVFilterTypeValues.h index 5212490f..b49d0855 100644 --- a/BVSDK/BVConversations/Display/Sorting & Filtering/BVFilterTypeValues.h +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/BVFilterTypeValues.h @@ -15,5 +15,6 @@ #import "BVProductFilterValue.h" #import "BVQuestionFilterValue.h" #import "BVReviewFilterValue.h" +#import "BVReviewFilterFieldType.h" #endif /* BVFILTERVALUES_H */ diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewFilterFieldType.h b/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewFilterFieldType.h new file mode 100644 index 00000000..204307c7 --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewFilterFieldType.h @@ -0,0 +1,21 @@ +// +// BVReviewFilterFieldType.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import + + +#ifndef BVReviewFilterFieldType_h +#define BVReviewFilterFieldType_h + +typedef NS_ENUM(NSInteger, BVReviewFilterFieldType) { + BVReviewFilterFieldTypeAdditionalField, + BVReviewFilterFieldTypeContextDataValue, + BVReviewFilterFieldTypeSecondaryRating, + BVReviewFilterFieldTypeTag +}; + +#endif /* BVReviewFilterFieldType_h */ diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index b00cd075..7cb9337e 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -507,8 +507,39 @@ class ReviewDisplayTests: XCTestCase { } } - - func testReviewRequestSecondaryRatingsDistribution() { + func testReviewSeconadaryRatingFilter() { + + let expectation = self.expectation(description: "testReviewSeconadaryRatingFilter") + + let request = BVReviewsRequest(productId: "test1", limit: 5, offset: 0) + .filter(on: .secondaryRating, fieldId: "Quality", relationalFilterOperatorValue: .equalTo, value: "2") + + request.load({ (response) in + + let reviews = response.results + + for review in reviews { + let qualityRating = review.secondaryRatings.filter({ $0.identifier == "Quality"}).first; + XCTAssertTrue(qualityRating?.value == 2) + } + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + expectation.fulfill() + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + + func testReviewRequestSecondaryRatingsDistribution() { let configDict = ["clientId": "testcustomermobilesdk", "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; @@ -543,9 +574,10 @@ class ReviewDisplayTests: XCTestCase { expectation.fulfill() - }) { (error) in + }) { (error) in XCTFail("review display request error: \(error)") + expectation.fulfill() } @@ -554,6 +586,114 @@ class ReviewDisplayTests: XCTestCase { } } + + func testReviewAdditionalFieldFilter() { + + let configDict = ["clientId": "testcustomer-56", + "apiKeyConversations": "caYgyVsPvUkcK2a4aBCu0CK64S3vx6ERor9FpgAM32Uew"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testReviewAdditionalFieldFilter") + + let request = BVReviewsRequest(productId: "test1", limit: 10, offset: 0) + .filter(on: .additionalField, fieldId: "DateOfUserExperience", relationalFilterOperatorValue: .equalTo, value: "2021-04-03") + + request.load({ (response) in + + let reviews = response.results + + for review in reviews { + let additionalField_DateOfUserExperience = review.additionalFields!["DateOfUserExperience"] as! NSDictionary + + XCTAssertTrue(additionalField_DateOfUserExperience["Value"] as! String == "2021-04-03") + } + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + + func testReviewTagFilter() { + + let configDict = ["clientId": "apitestcustomer", + "apiKeyConversations": "caYeBHjUvQaSNY1gJwSfQwpOMgoCc0Dhq2yBPcnyxRQwo"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testReviewTagFilter") + + let request = BVReviewsRequest(productId: "JAM5BLK", limit: 10, offset: 0) + .filter(on: .tag, fieldId: "ProductVariant", relationalFilterOperatorValue: .equalTo, value: "Gray") + + request.load({ (response) in + + let reviews = response.results + + for review in reviews { + let tag_ProductVariant = review.tagDimensions!["ProductVariant"] as! BVDimensionElement + let tag_ProductVariantValues = tag_ProductVariant.values + XCTAssertTrue(tag_ProductVariantValues!.contains("Gray")) + } + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + func testReviewCDVFilter() { + + let configDict = ["clientId": "apitestcustomer", + "apiKeyConversations": "caYeBHjUvQaSNY1gJwSfQwpOMgoCc0Dhq2yBPcnyxRQwo"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testReviewCDVFilter") + + let request = BVReviewsRequest(productId: "JAM5BLK", limit: 10, offset: 0) + .filter(on: .contextDataValue, fieldId: "DidYouReceiveThisProductForFree", relationalFilterOperatorValue: .equalTo, value: "Yes") + + request.load({ (response) in + + let reviews = response.results + + for review in reviews { + let contextDataValue_DidYouReceiveThisProductForFree = review.contextDataValues.first(where: { cdv in + cdv.identifier == "DidYouReceiveThisProductForFree" + }) + + XCTAssertTrue(contextDataValue_DidYouReceiveThisProductForFree?.value == "Yes") + } + + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } func testContextDataValueLabelIncludes(){ From 0eabbedd0b0ebdd52d84628a153148df70498aa4 Mon Sep 17 00:00:00 2001 From: chetan shanbag Date: Mon, 25 Apr 2022 21:58:40 +0530 Subject: [PATCH 07/10] Release 8.8.0 --- BVSDK.podspec | 2 +- BVSDK/BVCommon/BVSDKConstants.h | 2 +- BVSDK/Support/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BVSDK.podspec b/BVSDK.podspec index 4eb3fe2a..ed35d3d0 100644 --- a/BVSDK.podspec +++ b/BVSDK.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.name = "BVSDK" - s.version = '8.7.0' + s.version = '8.8.0' s.homepage = 'https://developer.bazaarvoice.com/' s.license = { :type => 'Commercial', :text => 'See https://developer.bazaarvoice.com/API_Terms_of_Use' } s.author = { 'Bazaarvoice' => 'support@bazaarvoice.com' } diff --git a/BVSDK/BVCommon/BVSDKConstants.h b/BVSDK/BVCommon/BVSDKConstants.h index 6c421132..97c403d9 100644 --- a/BVSDK/BVCommon/BVSDKConstants.h +++ b/BVSDK/BVCommon/BVSDKConstants.h @@ -10,7 +10,7 @@ #define BVSDKConstants_h /// Provides the master version of the SDK. -#define BV_SDK_VERSION @"8.7.0" +#define BV_SDK_VERSION @"8.8.0" /// Conversation SDK Version #define SDK_HEADER_NAME @"X-UA-BV-SDK" diff --git a/BVSDK/Support/Info.plist b/BVSDK/Support/Info.plist index a69cd62b..52f390b7 100644 --- a/BVSDK/Support/Info.plist +++ b/BVSDK/Support/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.7.0 + 8.8.0 CFBundleVersion 1 LSApplicationCategoryType From 58330ec96b1f4e89c33c855fc71603df70a0efaa Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Fri, 1 Jul 2022 15:13:37 +0530 Subject: [PATCH 08/10] Add sort by content locale (Custom sort order) --- BVSDK.xcodeproj/project.pbxproj | 20 ++++++ .../Requests/Review/BVBaseReviewsRequest.h | 4 ++ .../Requests/Review/BVBaseReviewsRequest.m | 12 ++++ .../BVReviewsCustomOrderSortOptionValue.h | 11 +++ .../Sorting & Filtering/BVSortOptionValues.h | 2 + .../Private/BVCustomSortOrder.h | 17 +++++ .../Private/BVCustomSortOrder.m | 38 ++++++++++ .../Private/BVReviewsCustomOrderSortOption.h | 16 +++++ .../Private/BVReviewsCustomOrderSortOption.m | 38 ++++++++++ .../Sorting & Filtering/Private/BVSort.h | 8 +++ .../Sorting & Filtering/Private/BVSort.m | 9 +++ .../DisplayTests/ReviewDisplayTests.swift | 69 +++++++++++++++++++ 12 files changed, 244 insertions(+) create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewsCustomOrderSortOptionValue.h create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.h create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.m create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.h create mode 100644 BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.m diff --git a/BVSDK.xcodeproj/project.pbxproj b/BVSDK.xcodeproj/project.pbxproj index 9ae3fb01..9982a11a 100644 --- a/BVSDK.xcodeproj/project.pbxproj +++ b/BVSDK.xcodeproj/project.pbxproj @@ -44,6 +44,8 @@ 2E371E5A2808226B008D9223 /* BVSecondaryRatingsDistributionElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E371E582808226B008D9223 /* BVSecondaryRatingsDistributionElement.m */; }; 2E371E5D280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E371E5B280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2E371E5E280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E371E5C280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m */; }; + 2E88C046282A38C4007B77B0 /* BVCustomSortOrder.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E88C044282A38C4007B77B0 /* BVCustomSortOrder.h */; }; + 2E88C047282A38C4007B77B0 /* BVCustomSortOrder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E88C045282A38C4007B77B0 /* BVCustomSortOrder.m */; }; 2E998AC82789963D0036DE64 /* BVFeaturesRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AC72789963D0036DE64 /* BVFeaturesRequest.m */; }; 2E998ACB2789967E0036DE64 /* BVFeaturesResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998ACA2789967E0036DE64 /* BVFeaturesResponse.m */; }; 2E998ACD278996940036DE64 /* BVFeaturesRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E998ACC278996940036DE64 /* BVFeaturesRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -53,6 +55,9 @@ 2E998AD52789B4990036DE64 /* BVFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E998AD42789B4990036DE64 /* BVFeature.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2E998AD72789B4C20036DE64 /* BVFeature.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AD62789B4C20036DE64 /* BVFeature.m */; }; 2E998AD9278BF02A0036DE64 /* FeatureDisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E998AD8278BF02A0036DE64 /* FeatureDisplayTests.swift */; }; + 2EA5DD962824FDA4006B0949 /* BVReviewsCustomOrderSortOptionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EA5DD952824FDA4006B0949 /* BVReviewsCustomOrderSortOptionValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2EA5DD992825110E006B0949 /* BVReviewsCustomOrderSortOption.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EA5DD972825110E006B0949 /* BVReviewsCustomOrderSortOption.h */; }; + 2EA5DD9A2825110E006B0949 /* BVReviewsCustomOrderSortOption.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA5DD982825110E006B0949 /* BVReviewsCustomOrderSortOption.m */; }; 2EAD31C326DCAC8600903208 /* BVAuthenticatedUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EAD31C226DCAC8600903208 /* BVAuthenticatedUser.m */; }; 2EE2579127F23EE300E6DBDE /* BVReviewFilterFieldType.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5F140C5D1F9553FE00905828 /* skelly_android.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F140C5C1F9553FE00905828 /* skelly_android.jpg */; }; @@ -692,6 +697,8 @@ 2E371E582808226B008D9223 /* BVSecondaryRatingsDistributionElement.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVSecondaryRatingsDistributionElement.m; sourceTree = ""; }; 2E371E5B280824BE008D9223 /* BVSecondaryRatingsDistributionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVSecondaryRatingsDistributionValue.h; sourceTree = ""; }; 2E371E5C280824BE008D9223 /* BVSecondaryRatingsDistributionValue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVSecondaryRatingsDistributionValue.m; sourceTree = ""; }; + 2E88C044282A38C4007B77B0 /* BVCustomSortOrder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVCustomSortOrder.h; sourceTree = ""; }; + 2E88C045282A38C4007B77B0 /* BVCustomSortOrder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVCustomSortOrder.m; sourceTree = ""; }; 2E998AC72789963D0036DE64 /* BVFeaturesRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeaturesRequest.m; sourceTree = ""; }; 2E998ACA2789967E0036DE64 /* BVFeaturesResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeaturesResponse.m; sourceTree = ""; }; 2E998ACC278996940036DE64 /* BVFeaturesRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVFeaturesRequest.h; sourceTree = ""; }; @@ -701,6 +708,9 @@ 2E998AD42789B4990036DE64 /* BVFeature.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVFeature.h; sourceTree = ""; }; 2E998AD62789B4C20036DE64 /* BVFeature.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVFeature.m; sourceTree = ""; }; 2E998AD8278BF02A0036DE64 /* FeatureDisplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureDisplayTests.swift; sourceTree = ""; }; + 2EA5DD952824FDA4006B0949 /* BVReviewsCustomOrderSortOptionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVReviewsCustomOrderSortOptionValue.h; sourceTree = ""; }; + 2EA5DD972825110E006B0949 /* BVReviewsCustomOrderSortOption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVReviewsCustomOrderSortOption.h; sourceTree = ""; }; + 2EA5DD982825110E006B0949 /* BVReviewsCustomOrderSortOption.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVReviewsCustomOrderSortOption.m; sourceTree = ""; }; 2EAD31C226DCAC8600903208 /* BVAuthenticatedUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BVAuthenticatedUser.m; sourceTree = ""; }; 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVReviewFilterFieldType.h; sourceTree = ""; }; 3462CE8D50CC0B93A458E62C /* Pods-BVSDKTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BVSDKTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BVSDKTests/Pods-BVSDKTests.debug.xcconfig"; sourceTree = ""; }; @@ -1758,6 +1768,7 @@ 2EE2579027F23EE300E6DBDE /* BVReviewFilterFieldType.h */, B5BE76A5200EA666002BA818 /* BVReviewIncludeTypeValue.h */, B5BE76A7200EA6B4002BA818 /* BVReviewsSortOptionValue.h */, + 2EA5DD952824FDA4006B0949 /* BVReviewsCustomOrderSortOptionValue.h */, B583B124200E8ABE001E9548 /* BVSortOptionValues.h */, B583B121200E8ABD001E9548 /* BVSortOrderValues.h */, B583B11E200E888C001E9548 /* Private */, @@ -2304,6 +2315,8 @@ B583AEE82009486C001E9548 /* BVIncludeType.m */, B583AEDB2007FB59001E9548 /* BVMonotonicSortOrder.h */, B583AEDC2007FB59001E9548 /* BVMonotonicSortOrder.m */, + 2E88C044282A38C4007B77B0 /* BVCustomSortOrder.h */, + 2E88C045282A38C4007B77B0 /* BVCustomSortOrder.m */, 87F2DB781DAD585E00FB43F3 /* BVProductFilterType.h */, 87F2DB791DAD585E00FB43F3 /* BVProductFilterType.m */, B583AEEB20094A58001E9548 /* BVProductIncludeType.h */, @@ -2328,6 +2341,8 @@ B583AEE0200816A4001E9548 /* BVSortOption.m */, B583AED72007F80A001E9548 /* BVSortOrder.h */, B583AED82007F80A001E9548 /* BVSortOrder.m */, + 2EA5DD972825110E006B0949 /* BVReviewsCustomOrderSortOption.h */, + 2EA5DD982825110E006B0949 /* BVReviewsCustomOrderSortOption.m */, ); path = Private; sourceTree = ""; @@ -2781,6 +2796,7 @@ B58639C5214AFE8700EFD763 /* BVLocaleServiceManager.h in Headers */, B5BE768E200EA025002BA818 /* BVProductFilterValue.h in Headers */, B583B12A200E8ABE001E9548 /* BVSortOptionValues.h in Headers */, + 2E88C046282A38C4007B77B0 /* BVCustomSortOrder.h in Headers */, 87F2DCAD1DAD585E00FB43F3 /* BVQuestionsAndAnswersRequest.h in Headers */, 87F2DCBD1DAD585E00FB43F3 /* BVQuestionFilterType.h in Headers */, 87F2DCE11DAD585E00FB43F3 /* BVPhotoSubmission.h in Headers */, @@ -2905,6 +2921,7 @@ 873DC49B1E7482840080FA03 /* BVPersonalizationEvent.h in Headers */, B5BE76A0200EA53D002BA818 /* BVProductIncludeTypeValue.h in Headers */, B58639B2214AFE0A00EFD763 /* BVSDKManager+Private.h in Headers */, + 2EA5DD962824FDA4006B0949 /* BVReviewsCustomOrderSortOptionValue.h in Headers */, 2EE2579127F23EE300E6DBDE /* BVReviewFilterFieldType.h in Headers */, 982B607522EA125C0041D40B /* BVProgressiveSubmissionReview.h in Headers */, B5BE769C200EA473002BA818 /* BVCommentsSortOptionValue.h in Headers */, @@ -2968,6 +2985,7 @@ B575C38A1FBE02FE000F890B /* BVUASSubmissionErrorResponse.h in Headers */, B575C38E1FBE1A4F000F890B /* BVUASSubmissionResponse.h in Headers */, 5F51EA501F5F2BB4002FA8FD /* BVFormInputType.h in Headers */, + 2EA5DD992825110E006B0949 /* BVReviewsCustomOrderSortOption.h in Headers */, B583B129200E8ABE001E9548 /* BVFilterOperatorValues.h in Headers */, 5F6201DC1F7030FA00454D77 /* NSError+BVErrorCodeParser.h in Headers */, 5F608FF41F6AF3E100E197CE /* BVSubmissionErrorCode.h in Headers */, @@ -3297,6 +3315,7 @@ B57B8335215E8A58006B378E /* BVPhotoSubmissionErrorResponse.m in Sources */, B5A764E71FE191BA00B5DC9A /* BVStoreReviewSubmission.m in Sources */, 87C5FEBF1E22A05D004EE6E8 /* BVLogger.m in Sources */, + 2EA5DD9A2825110E006B0949 /* BVReviewsCustomOrderSortOption.m in Sources */, 873DC4981E7482840080FA03 /* BVInViewEvent.m in Sources */, B57B8329215E8054006B378E /* BVPhotoSubmissionResponse.m in Sources */, 87F2DD101DAD585E00FB43F3 /* BVReviewsCollectionView.m in Sources */, @@ -3377,6 +3396,7 @@ 87F2DC721DAD585E00FB43F3 /* BVDistributionElement.m in Sources */, 87C5FEC61E22A05D004EE6E8 /* BVStringKeyValuePair.m in Sources */, 87F2DC7D1DAD585E00FB43F3 /* BVProductsResponse.m in Sources */, + 2E88C047282A38C4007B77B0 /* BVCustomSortOrder.m in Sources */, B583AEF2200956D0001E9548 /* BVAuthorIncludeType.m in Sources */, 875411841E1F201E006C5C6E /* BVStoreReviewNotificationProperties.m in Sources */, 87F2DCBE1DAD585E00FB43F3 /* BVQuestionFilterType.m in Sources */, diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h index 52b98141..b7eea9cb 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h +++ b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.h @@ -35,6 +35,10 @@ sortByReviewsSortOptionValue:(BVReviewsSortOptionValue)reviewsSortOptionValue monotonicSortOrderValue:(BVMonotonicSortOrderValue)monotonicSortOrderValue; +- (nonnull instancetype) +sortByReviewsCustomOrderSortOptionValue:(BVReviewsCustomOrderSortOptionValue)reviewsCustomOrderSortOptionValue +customSortOrder:(nonnull NSArray *)customSortOrder; + - (nonnull instancetype) filterOnReviewFilterValue:(BVReviewFilterValue)reviewFilterValue relationalFilterOperatorValue: diff --git a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m index 61a305cc..29832c3d 100644 --- a/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m +++ b/BVSDK/BVConversations/Display/Requests/Review/BVBaseReviewsRequest.m @@ -13,12 +13,14 @@ #import "BVConversationsRequest+Private.h" #import "BVFilter.h" #import "BVMonotonicSortOrder.h" +#import "BVCustomSortOrder.h" #import "BVProduct.h" #import "BVRelationalFilterOperator.h" #import "BVReview.h" #import "BVReviewFilterType.h" #import "BVReviewIncludeType.h" #import "BVReviewsSortOption.h" +#import "BVReviewsCustomOrderSortOption.h" #import "BVSort.h" #import "BVStringKeyValuePair.h" @@ -157,6 +159,16 @@ - (nonnull instancetype)includeReviewIncludeTypeValue: return self; } +- (nonnull instancetype) +sortByReviewsCustomOrderSortOptionValue:(BVReviewsCustomOrderSortOptionValue)reviewsCustomOrderSortOptionValue + customSortOrder:(nonnull NSArray *)customSortOrder{ + BVSort *sort = [[BVSort alloc] initWithCustomOrderSortOption:[BVReviewsCustomOrderSortOption + sortOptionWithRawValue:reviewsCustomOrderSortOptionValue] + customSortOrder:[BVCustomSortOrder customSortOrderWithValues:customSortOrder]]; + [self.sorts addObject:sort]; + return self; +} + - (nonnull instancetype) filterOnReviewFilterValue:(BVReviewFilterValue)reviewFilterValue relationalFilterOperatorValue: diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewsCustomOrderSortOptionValue.h b/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewsCustomOrderSortOptionValue.h new file mode 100644 index 00000000..b885e63d --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/BVReviewsCustomOrderSortOptionValue.h @@ -0,0 +1,11 @@ +// +// BVReviewsCustomOrderSortOptionValue.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// +#import + +typedef NS_ENUM(NSInteger, BVReviewsCustomOrderSortOptionValue) { + BVReviewsCustomOrderSortOptionValueContentLocale +}; diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/BVSortOptionValues.h b/BVSDK/BVConversations/Display/Sorting & Filtering/BVSortOptionValues.h index 6a5fcfa1..aff2c6cb 100644 --- a/BVSDK/BVConversations/Display/Sorting & Filtering/BVSortOptionValues.h +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/BVSortOptionValues.h @@ -16,4 +16,6 @@ #import "BVQuestionsSortOptionValue.h" #import "BVReviewsSortOptionValue.h" +#import "BVReviewsCustomOrderSortOptionValue.h" + #endif /* BVSORTOPTIONVALUES_H */ diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.h b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.h new file mode 100644 index 00000000..8a24db24 --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.h @@ -0,0 +1,17 @@ +// +// BVCustomSortOrder.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// +#import "BVSort.h" + +@interface BVCustomSortOrder : NSObject + ++ (nonnull instancetype)customSortOrderWithValues:(nonnull NSArray *)values; +- (nonnull instancetype)initWithCustomSortOrderValues: + (nonnull NSArray *)values; +- (nonnull instancetype)__unavailable init; + + +@end diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.m b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.m new file mode 100644 index 00000000..4c3441f5 --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVCustomSortOrder.m @@ -0,0 +1,38 @@ +// +// BVCustomSortOrder.m +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import "BVCustomSortOrder.h" +#import "BVCommaUtil.h" + +@interface BVCustomSortOrder () +@property(nonnull, nonatomic, strong) NSString *value; +@end + +@implementation BVCustomSortOrder + ++ (nonnull NSString *)toCustomSortOrderParameterStringWithValues:(nonnull NSArray *)values +{ + return [BVCustomSortOrder customSortOrderWithValues:values].value; +} + ++ (nonnull instancetype)customSortOrderWithValues:(nonnull NSArray *)values { + return [[BVCustomSortOrder alloc] initWithCustomSortOrderValues:values]; +} + +- (nonnull NSString *)toCustomSortOrderParameterString { + return self.value; +} + +- (nonnull instancetype)initWithCustomSortOrderValues: +(nonnull NSArray *)values { + if ((self = [super init])) { + self.value = [[BVCommaUtil escapeMultiple:values] componentsJoinedByString:@","]; + } + return self; +} + +@end diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.h b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.h new file mode 100644 index 00000000..0c37af61 --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.h @@ -0,0 +1,16 @@ +// +// BVReviewsCustomOrderCustomOrderSortOption.h +// BVSDK +// +// Copyright © 2022 Bazaarvoice. All rights reserved. +// + +#import "BVReviewsCustomOrderSortOptionValue.h" +#import "BVSortOption.h" + +@interface BVReviewsCustomOrderSortOption : BVSortOption + +- (nonnull instancetype)initWithReviewsSortOptionValue: + (BVReviewsCustomOrderSortOptionValue)reviewsSortOptionValue; + +@end diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.m b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.m new file mode 100644 index 00000000..ff176a60 --- /dev/null +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVReviewsCustomOrderSortOption.m @@ -0,0 +1,38 @@ +#import "BVReviewsCustomOrderSortOption.h" + +@interface BVReviewsCustomOrderSortOption () +@property(nonnull, nonatomic, strong) NSString *value; +@end + +@implementation BVReviewsCustomOrderSortOption + ++ (nonnull NSString *)toSortOptionParameterStringWithRawValue: + (NSInteger)rawValue { + return [BVReviewsCustomOrderSortOption sortOptionWithRawValue:rawValue].value; +} + ++ (nonnull instancetype)sortOptionWithRawValue:(NSInteger)rawValue { + return [[BVReviewsCustomOrderSortOption alloc] initWithRawValue:rawValue]; +} + +- (nonnull instancetype)initWithRawValue:(NSInteger)rawValue { + if ((self = [super initWithRawValue:rawValue])) { + switch (rawValue) { + case BVReviewsCustomOrderSortOptionValueContentLocale: + self.value = @"ContentLocale"; + break; + } + } + return self; +} + +- (nonnull NSString *)toSortOptionParameterString { + return self.value; +} + +- (nonnull instancetype)initWithReviewsSortOptionValue: + (BVReviewsCustomOrderSortOptionValue)reviewsSortOptionValue { + return [BVReviewsCustomOrderSortOption sortOptionWithRawValue:reviewsSortOptionValue]; +} + +@end diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.h b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.h index fe0a7934..a1061fc5 100644 --- a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.h +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.h @@ -19,6 +19,12 @@ - (nonnull NSString *)toSortOrderParameterString; @end +@protocol BVCustomSortOrderProtocol ++ (nonnull NSString *)toCustomSortOrderParameterStringWithValues: + (nonnull NSArray *)values; +- (nonnull NSString *)toCustomSortOrderParameterString; +@end + @interface BVSort : NSObject - (nonnull id)initWithSortOption:(nonnull id)sortOption @@ -26,6 +32,8 @@ - (nonnull id)initWithSortOptionString:(nonnull NSString *)sortOptionString sortOrder: (nonnull id)sortOrder; +- (nonnull id)initWithCustomOrderSortOption:(nonnull id)customOrderSortOption + customSortOrder:(nonnull id)customSortOrder; - (nonnull NSString *)toParameterString; @end diff --git a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.m b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.m index 39d491b2..260dc401 100644 --- a/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.m +++ b/BVSDK/BVConversations/Display/Sorting & Filtering/Private/BVSort.m @@ -35,6 +35,15 @@ - (nonnull id)initWithSortOptionString:(nonnull NSString *)sortOptionString return self; } +- (nonnull id)initWithCustomOrderSortOption:(nonnull id)customOrderSortOption + customSortOrder:(nonnull id)customSortOrder{ + if ((self = [super init])) { + self.sortOption = [customOrderSortOption toSortOptionParameterString]; + self.sortOrder = [customSortOrder toCustomSortOrderParameterString]; + } + return self; +} + - (nonnull NSString *)toParameterString { return [NSString stringWithFormat:@"%@:%@", self.sortOption, self.sortOrder]; } diff --git a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift index 7cb9337e..4923a55a 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/ReviewDisplayTests.swift @@ -727,4 +727,73 @@ class ReviewDisplayTests: XCTestCase { XCTAssertNil(error, "Something went horribly wrong, request took too long.") } } + + func testReviewCustomSortOrder() { + + let configDict = ["clientId": "testcustomermobilesdk", + "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + let expectation = self.expectation(description: "testReviewCustomSortOrder") + + let request = BVReviewsRequest(productId: "product1", limit: 20, offset: 0) + .sort(by: .contentLocale, customSortOrder: ["es_US","en_US"]) + + + request.load({ (response) in + + let reviews = response.results + let ContentLocales = reviews.map { review in + review.contentLocale + } + + XCTAssertTrue(ContentLocales.index(of: "es_US")! < ContentLocales.index(of: "en_US")!); + expectation.fulfill() + + }) { (error) in + + XCTFail("review display request error: \(error)") + expectation.fulfill() + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } + + func testReviewCustomSortOrderOver5Values() { + + let configDict = ["clientId": "testcustomermobilesdk", + "apiKeyConversations": "cavNO70oED9uDIo3971pfLc9IJET3eaozVNHJhL1vnAK4"]; + BVSDKManager.configure(withConfiguration: configDict, configType: .staging) + + + let expectation = self.expectation(description: "testReviewCustomSortOrderOver5Values") + + let request = BVReviewsRequest(productId: "product1", limit: 10, offset: 5) + .sort(by: .contentLocale, customSortOrder: ["fr_FR","en_GB","en_US","en_ZH","en_CA","en_DE"]) + + request.load({ (response) in + + XCTFail("Only 5 locales are allowed") + expectation.fulfill() + + }) { (errors) in + for error in errors as [NSError] { + + let errorCode = error.userInfo["BVKeyErrorCode"] as! String + let errorMessage = error.userInfo["BVKeyErrorMessage"] as! String + + XCTAssertEqual(errorCode, "ERROR_PARAM_INVALID_SORT_ATTRIBUTE") + XCTAssertEqual(errorMessage, "Sort by contentlocale cannot have more than 5 values") + } + expectation.fulfill() + } + + self.waitForExpectations(timeout: 1000) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + + } } From 2ccff1663d9bd2367c1357adb96fd7cb003ade81 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Fri, 1 Jul 2022 15:14:30 +0530 Subject: [PATCH 09/10] Fix "Staging pixel url called with prod configuration" bug --- BVSDK/BVAnalytics/Private/BVAnalyticsManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BVSDK/BVAnalytics/Private/BVAnalyticsManager.m b/BVSDK/BVAnalytics/Private/BVAnalyticsManager.m index cc35a77c..00936e17 100644 --- a/BVSDK/BVAnalytics/Private/BVAnalyticsManager.m +++ b/BVSDK/BVAnalytics/Private/BVAnalyticsManager.m @@ -593,7 +593,7 @@ - (nonnull NSString *)baseUrl { return [localeServiceManager resourceForService:BVLocaleServiceManagerServiceAnalytics withLocale:self.analyticsLocale - andIsProduction:(!self.isStagingServer)]; + andIsProduction:![self.isStagingServer boolValue]]; } #pragma mark - Testing From e27a68ca300419e21fcdd7400349004690575384 Mon Sep 17 00:00:00 2001 From: Abishekh S Kamath Date: Fri, 1 Jul 2022 15:15:08 +0530 Subject: [PATCH 10/10] Update sonarscan workflow --- .github/workflows/sonarscanCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonarscanCI.yml b/.github/workflows/sonarscanCI.yml index 1d96f79e..9a62527d 100644 --- a/.github/workflows/sonarscanCI.yml +++ b/.github/workflows/sonarscanCI.yml @@ -2,9 +2,9 @@ name: BVSDK Sonarqube Scan CI on: push: - branches: [ develop ] + branches: [ master ] pull_request: - branches: [ develop ] + branches: [ master ] env: SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}