Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ def wordpress_ui
end

def wordpress_kit
# Anything compatible with 8.9, starting from 8.9.1 which has a breaking change fix
pod 'WordPressKit', '~> 9.0', '>= 9.0.2'
pod 'WordPressKit', '~> 9.0', '>= 9.0.3'
# pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', commit: ''
# pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', branch: 'trunk'
# pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', tag: ''
Expand Down
8 changes: 4 additions & 4 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ PODS:
- WordPressKit (~> 9.0.0)
- WordPressShared (~> 2.1-beta)
- WordPressUI (~> 1.7-beta)
- WordPressKit (9.0.2):
- WordPressKit (9.0.3):
- Alamofire (~> 4.8.0)
- NSObject-SafeExpectations (~> 0.0.4)
- UIDeviceIdentifier (~> 2.0)
Expand Down Expand Up @@ -121,7 +121,7 @@ DEPENDENCIES:
- SwiftLint (~> 0.50)
- WordPress-Editor-iOS (~> 1.19.9)
- WordPressAuthenticator (>= 8.0.1, ~> 8.0)
- WordPressKit (>= 9.0.2, ~> 9.0)
- WordPressKit (>= 9.0.3, ~> 9.0)
- WordPressShared (~> 2.2)
- WordPressUI (~> 1.15)
- ZendeskSupportSDK (= 5.3.0)
Expand Down Expand Up @@ -218,7 +218,7 @@ SPEC CHECKSUMS:
WordPress-Aztec-iOS: fbebd569c61baa252b3f5058c0a2a9a6ada686bb
WordPress-Editor-iOS: bda9f7f942212589b890329a0cb22547311749ef
WordPressAuthenticator: fd2e1d340680faffffd9d675fc2df5ed19e26ea2
WordPressKit: 23d0ffb43f2ccdad2debd6799e62d39790a5ffad
WordPressKit: 4d41fd70b83876ee5db4617868767b33f3ae1bc4
WordPressShared: 87f3ee89b0a3e83106106f13a8b71605fb8eb6d2
WordPressUI: a491454affda3b0fb812812e637dc5e8f8f6bd06
wpxmlrpc: 68db063041e85d186db21f674adf08d9c70627fd
Expand All @@ -231,6 +231,6 @@ SPEC CHECKSUMS:
ZendeskSupportSDK: 3a8e508ab1d9dd22dc038df6c694466414e037ba
ZIPFoundation: d170fa8e270b2a32bef9dcdcabff5b8f1a5deced

PODFILE CHECKSUM: 9567ce349333fd257fea44c201727b4180efb961
PODFILE CHECKSUM: d7a42312b8249374e94aecb6021ee06d137c7cfa

COCOAPODS: 1.14.2
26 changes: 13 additions & 13 deletions WordPress/Classes/Stores/RemoteFeatureFlagStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ class RemoteFeatureFlagStore {
return queue
}()

/// The `deviceID` ensures we retain a stable set of Feature Flags between updates. If there are staged rollouts or other dynamic changes
/// happening server-side we don't want our flags to change on each fetch, so we provide an anonymous ID to manage this.
public var deviceID: String {
guard let deviceID = persistenceStore.string(forKey: Constants.DeviceIdKey) else {
DDLogInfo("🚩 Unable to find existing device ID – generating a new one")
let newID = UUID().uuidString
persistenceStore.set(newID, forKey: Constants.DeviceIdKey)
return newID
}

return deviceID
}

init(queue: DispatchQueue = .remoteFeatureFlagStoreQueue,
persistenceStore: UserPersistentRepository = UserDefaults.standard) {
self.queue = queue
Expand Down Expand Up @@ -63,19 +76,6 @@ extension RemoteFeatureFlagStore {

typealias FetchCallback = () -> Void

/// The `deviceID` ensures we retain a stable set of Feature Flags between updates. If there are staged rollouts or other dynamic changes
/// happening server-side we don't want out flags to change on each fetch, so we provide an anonymous ID to manage this.
private var deviceID: String {
guard let deviceID = persistenceStore.string(forKey: Constants.DeviceIdKey) else {
DDLogInfo("🚩 Unable to find existing device ID – generating a new one")
let newID = UUID().uuidString
persistenceStore.set(newID, forKey: Constants.DeviceIdKey)
return newID
}

return deviceID
}

/// The local cache stores feature flags between runs so that the most recently fetched set are ready to go as soon as this object is instantiated.
private var cache: [String: Bool] {
get {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,8 @@ enum DashboardCard: String, CaseIterable {
}
}

static func shouldShowDynamicCard(
for blog: Blog,
payload: DashboardDynamicCardModel.Payload,
remoteFeatureFlagStore: RemoteFeatureFlagStore,
isJetpack: Bool = AppConfiguration.isJetpack
) -> Bool {
let remoteFeatureFlagEnabled = {
guard let key = payload.remoteFeatureFlag else {
return true
}
return remoteFeatureFlagStore.value(for: key) ?? false
}()
return isJetpack
&& RemoteDashboardCard.dynamic.supported(by: blog)
&& remoteFeatureFlagEnabled
static func shouldShowDynamicCard(for blog: Blog, isJetpack: Bool = AppConfiguration.isJetpack) -> Bool {
isJetpack && RemoteDashboardCard.dynamic.supported(by: blog)
}

private func shouldShowRemoteCard(apiResponse: BlogDashboardRemoteEntity?) -> Bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ extension BlogDashboardRemoteEntity {
struct BlogDashboardDynamic: Decodable, Hashable {

let id: String
let remoteFeatureFlag: String?
let title: String?
let featuredImage: String?
let url: String?
Expand All @@ -79,7 +78,6 @@ extension BlogDashboardRemoteEntity {
private enum CodingKeys: String, CodingKey {
case id
case title
case remoteFeatureFlag = "remote_feature_flag"
case featuredImage = "featured_image"
case url
case action
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ final class BlogDashboardService {
private let persistence: BlogDashboardPersistence
private let postsParser: BlogDashboardPostsParser
private let repository: UserPersistentRepository
private let remoteFeatureFlagStore: RemoteFeatureFlagStore
private let isJetpack: Bool
private let isDotComAvailable: Bool
private let shouldShowJetpackFeatures: Bool
private let remoteFeatureFlagStore: RemoteFeatureFlagStore

init(
managedObjectContext: NSManagedObjectContext,
Expand Down Expand Up @@ -42,8 +42,9 @@ final class BlogDashboardService {
}

let cardsToFetch: [String] = DashboardCard.RemoteDashboardCard.allCases.filter {$0.supported(by: blog)}.map { $0.rawValue }
let deviceID = remoteFeatureFlagStore.deviceID

remoteService.fetch(cards: cardsToFetch, forBlogID: dotComID, success: { [weak self] cardsDictionary in
remoteService.fetch(cards: cardsToFetch, forBlogID: dotComID, deviceId: deviceID, success: { [weak self] cardsDictionary in

guard let cardsDictionary = self?.parseCardsForLocalContent(cardsDictionary, blog: blog) else {
failure?([])
Expand Down Expand Up @@ -187,8 +188,6 @@ private extension BlogDashboardService {
let model = DashboardDynamicCardModel(payload: payload, dotComID: dotComID)
let shouldShow = DashboardCard.shouldShowDynamicCard(
for: blog,
payload: payload,
remoteFeatureFlagStore: remoteFeatureFlagStore,
isJetpack: isJetpack
)
guard shouldShow, personalizationService.isEnabled(model) else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class CompliancePopoverCoordinator: CompliancePopoverCoordinatorProtocol {
}

func presentIfNeeded() {
guard FeatureFlag.compliancePopover.enabled, !defaults.didShowCompliancePopup else {
guard FeatureFlag.compliancePopover.enabled/*, !defaults.didShowCompliancePopup */else {
return
}
complianceService.getIPCountryCode { [weak self] result in
Expand Down
38 changes: 13 additions & 25 deletions WordPress/WordPressTest/Dashboard/BlogDashboardServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class BlogDashboardServiceTests: CoreDataTestCase {
private var repositoryMock: InMemoryUserDefaults!
private var postsParserMock: BlogDashboardPostsParserMock!
private var remoteFeatureFlagStore: RemoteFeatureFlagStoreMock!

private let featureFlags = FeatureFlagOverrideStore()

private let wpComID = 123456
Expand Down Expand Up @@ -77,6 +78,7 @@ class BlogDashboardServiceTests: CoreDataTestCase {

service.fetch(blog: blog) { _ in
XCTAssertEqual(self.remoteServiceMock.didCallWithBlogID, self.wpComID)
XCTAssertEqual(self.remoteServiceMock.didCallWithDeviceId, "Test")
XCTAssertEqual(self.remoteServiceMock.didRequestCards, ["todays_stats", "posts", "pages", "activity", "dynamic"])
expect.fulfill()
}
Expand Down Expand Up @@ -413,10 +415,9 @@ class BlogDashboardServiceTests: CoreDataTestCase {

// MARK: - Dynamic Cards

func testCardsPresenceWhenAllCardsFeatureFlagsAreEnabled() throws {
func testCardsPresenceWhenFeatureFlagIsEnabled() throws {
let expect = expectation(description: "2 dynamic cards at the top and one at the bottom should be present")
remoteServiceMock.respondWith = .withMultipleDynamicCards
remoteFeatureFlagStore.enabledFeatureFlags = ["feature_flag_12345", "feature_flag_67890", "feature_flag_13579"]

let blog = newTestBlog(id: wpComID, context: mainContext)

Expand All @@ -430,28 +431,9 @@ class BlogDashboardServiceTests: CoreDataTestCase {
waitForExpectations(timeout: 3, handler: nil)
}

func testCardsPresenceWhenSomeCardsFeatureFlagsAreEnabled() throws {
let expect = expectation(description: "2 dynamic cards at the top and one at the bottom should be present")
remoteServiceMock.respondWith = .withMultipleDynamicCards
remoteFeatureFlagStore.enabledFeatureFlags = ["feature_flag_12345"]
remoteFeatureFlagStore.disabledFeatureFlag = ["feature_flag_67890"]

let blog = newTestBlog(id: wpComID, context: mainContext)

service.fetch(blog: blog) { cards in
let numberOfDynamicCards = cards.compactMap { $0.dynamic() }.count
XCTAssertEqual(numberOfDynamicCards, 1)
XCTAssertEqual(cards[0].dynamic()?.payload.id, "id_12345")
expect.fulfill()
}

waitForExpectations(timeout: 3, handler: nil)
}

func testCardsAbsenceWhenRemoteFeatureFlagIsDisabled() throws {
func testCardsAbsenceWhenFeatureFlagIsDisabled() throws {
let expect = expectation(description: "No dynamic card should be present")
remoteServiceMock.respondWith = .withMultipleDynamicCards
remoteFeatureFlagStore.enabledFeatureFlags = ["feature_flag_12345", "feature_flag_67890", "feature_flag_13579"]
try featureFlags.override(RemoteFeatureFlag.dynamicDashboardCards, withValue: false)

let blog = newTestBlog(id: wpComID, context: mainContext)
Expand All @@ -468,7 +450,6 @@ class BlogDashboardServiceTests: CoreDataTestCase {
func testDecodingWithDynamicCards() throws {
let expect = expectation(description: "Dynamic card should be successfully decoded")
remoteServiceMock.respondWith = .withOnlyOneDynamicCard
remoteFeatureFlagStore.enabledFeatureFlags = ["feature_flag_12345"]
try featureFlags.override(RemoteFeatureFlag.dynamicDashboardCards, withValue: true)

let blog = newTestBlog(id: wpComID, context: mainContext)
Expand All @@ -479,7 +460,6 @@ class BlogDashboardServiceTests: CoreDataTestCase {
let payload = card.payload
let expected = BlogDashboardRemoteEntity.BlogDashboardDynamic(
id: "id_12345",
remoteFeatureFlag: "feature_flag_12345",
title: "Title 12345",
featuredImage: "https://example.com/image12345",
url: "https://example.com/url12345",
Expand Down Expand Up @@ -546,11 +526,19 @@ class DashboardServiceRemoteMock: DashboardServiceRemote {
var respondWith: Response = .withDraftAndSchedulePosts

var didCallWithBlogID: Int?
var didCallWithDeviceId: String?
var didRequestCards: [String]?

override func fetch(cards: [String], forBlogID blogID: Int, success: @escaping (NSDictionary) -> Void, failure: @escaping (Error) -> Void) {
override func fetch(
cards: [String],
forBlogID blogID: Int,
deviceId: String?,
success: @escaping (NSDictionary) -> Void,
failure: @escaping (Error) -> Void
) {
didCallWithBlogID = blogID
didRequestCards = cards
didCallWithDeviceId = deviceId

if let fileURL: URL = Bundle(for: BlogDashboardServiceTests.self).url(forResource: respondWith.rawValue, withExtension: nil),
let data: Data = try? Data(contentsOf: fileURL),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ final class BlogDashboardDynamicCardCoordinatorTests: XCTestCase {
) -> BlogDashboardDynamicCardCoordinator {
let payload = DashboardDynamicCardModel.Payload(
id: id,
remoteFeatureFlag: "default",
title: "Domain Management",
featuredImage: "https://wordpress.com",
url: url,
Expand Down
4 changes: 3 additions & 1 deletion WordPress/WordPressTest/RemoteFeatureFlagStoreMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ class RemoteFeatureFlagStoreMock: RemoteFeatureFlagStore {
var enabledFeatureFlags = Set<String>()
var disabledFeatureFlag = Set<String>()

// MARK: - Access Remote Feature Flag Value
override var deviceID: String {
return "Test"
}

override func value(for flagKey: String) -> Bool? {
if enabledFeatureFlags.contains(flagKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
{
"id": "id_12345",
"title": "Title 12345",
"remote_feature_flag": "feature_flag_12345",
"featured_image": "https://example.com/image12345",
"url": "https://example.com/url12345",
"action": "Action 12345",
Expand All @@ -24,7 +23,6 @@
{
"id": "id_67890",
"title": "Title 67890",
"remote_feature_flag": "feature_flag_67890",
"featured_image": "https://example.com/image67890",
"url": "https://example.com/url67890",
"action": "Action 67890",
Expand All @@ -45,7 +43,6 @@
{
"id": "id_13579",
"title": "Title 13579",
"remote_feature_flag": "feature_flag_13579",
"featured_image": "https://example.com/image13579",
"url": "https://example.com/url13579",
"action": "Action 13579",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
{
"id": "id_12345",
"title": "Title 12345",
"remote_feature_flag": "feature_flag_12345",
"featured_image": "https://example.com/image12345",
"url": "https://example.com/url12345",
"action": "Action 12345",
Expand Down