Skip to content

Commit

Permalink
Merge 1948c70 into d73771e
Browse files Browse the repository at this point in the history
  • Loading branch information
ABTastyAdel authored Aug 23, 2023
2 parents d73771e + 1948c70 commit ae3150d
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 370 deletions.
2 changes: 1 addition & 1 deletion FlagShip.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = "FlagShip"
s.version = "3.2.0"
s.version = "3.2.1"
s.summary = "Flagship SDK"

# This description is used to generate tags and improve search results.
Expand Down
18 changes: 18 additions & 0 deletions FlagShip/FlagShipTests/FSFlagTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class FSFlagTest: XCTestCase {

/// Create new visitor
testVisitor = Flagship.sharedInstance.newVisitor("alias").build()
// Check if the flagsync is Created
XCTAssertTrue(testVisitor?.flagSyncStatus == .CREATED)
/// Set fake session
if let aUrlFakeSession = urlFakeSession {
testVisitor?.configManager.decisionManager?.networkService.serviceSession = aUrlFakeSession
Expand All @@ -54,6 +56,8 @@ class FSFlagTest: XCTestCase {
let expectationSync = XCTestExpectation(description: "Service-GetScript")

testVisitor?.fetchFlags(onFetchCompleted: {
/// Check if flagSync is fetched
XCTAssertTrue(self.testVisitor?.flagSyncStatus == .FLAGS_FETCHED)
if let flag = self.testVisitor?.getFlag(key: "btnTitle", defaultValue: "dfl") {
XCTAssertTrue(flag.value() as! String == "Alpha_demoApp")
XCTAssertTrue(flag.exists())
Expand Down Expand Up @@ -94,6 +98,20 @@ class FSFlagTest: XCTestCase {
XCTAssertTrue(FSFlagMetadata(nil).slug == "")
}

func testFlagSyncStatus() {
let syncUser = Flagship.sharedInstance.newVisitor("userSync", instanceType: .NEW_INSTANCE).build()
XCTAssertTrue(syncUser.flagSyncStatus == .CREATED)
// Update context
syncUser.updateContext(["keySync": "valSync"])
XCTAssertTrue(syncUser.flagSyncStatus == .CONTEXT_UPDATED)
// Autenticate
syncUser.authenticate(visitorId: "syncUser")
XCTAssertTrue(syncUser.flagSyncStatus == .AUTHENTICATED)
// Unauthenticate
syncUser.unauthenticate()
XCTAssertTrue(syncUser.flagSyncStatus == .UNAUTHENTICATED)
}

func testGetFlagOnPanic() {
let expectationSync = XCTestExpectation(description: "Service-GetScript")
do {
Expand Down
4 changes: 2 additions & 2 deletions FlagShip/Flagship.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1681,7 +1681,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.2.0;
MARKETING_VERSION = 3.2.1;
OTHER_LDFLAGS = "";
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = ABTasty.FlagShip;
Expand Down Expand Up @@ -1714,7 +1714,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.2.0;
MARKETING_VERSION = 3.2.1;
OTHER_LDFLAGS = "";
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = ABTasty.FlagShip;
Expand Down
40 changes: 39 additions & 1 deletion FlagShip/Source/Core/FSFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class FSFlag: NSObject {
if let flagModification = strategy?.getStrategy().getFlagModification(key) {
if isSameType(flagModification.value) { /// _ have type same with default value
///
FlagshipLogManager.Log(level: .ALL, tag: .GET_MODIFICATION, messageToDisplay: .MESSAGE("Return the value for flag \(flagModification.value)"))
FlagshipLogManager.Log(level: .ALL, tag: .GET_MODIFICATION, messageToDisplay: .MESSAGE("The value of the flag `\(key)` is `\(flagModification.value)"))

result = flagModification.value
} else {
Expand Down Expand Up @@ -128,3 +128,41 @@ public class FSFlag: NSObject {
"slug": slug]
}
}

/**
* This status represent the flag status depend on visitor actions
*/
@objc internal enum FlagSynchStatus: Int {
// When visitor is created
case CREATED
// When visitor context is updated
case CONTEXT_UPDATED
// When visitor Fetched flags
case FLAGS_FETCHED
// When visitor is authenticated
case AUTHENTICATED
// When visitor is unauthorised
case UNAUTHENTICATED

/**
Return the string for the flag warning message.
Note: No message for FLAGS_FETCHED state
*/
func warningMessage(_ flagKey: String, _ visitorId: String)->String {
var ret = ""
switch self {
case .CREATED:
ret = "Visitor `\(visitorId)` has been created without calling `fetchFlags` method afterwards, the value of the flag `\(flagKey)` may be outdated."
case .CONTEXT_UPDATED:
ret = "Visitor context for visitor `\(visitorId)` has been updated without calling `fetchFlags` method afterwards, the value of the flag `\(flagKey)` may be outdated."
case .AUTHENTICATED:
ret = "Visitor `\(visitorId)` has been authenticated without calling `fetchFlags` method afterwards, the value of the flag `\(flagKey)` may be outdated."
case .UNAUTHENTICATED:
ret = "Visitor `\(visitorId)` has been unauthenticated without calling `fetchFlags` method afterwards, the value of the flag `\(flagKey)` may be outdated."
default:
break
}

return ret
}
}
16 changes: 9 additions & 7 deletions FlagShip/Source/Core/FSVisitor+Reconcilliation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@

import Foundation

extension FSVisitor {

public extension FSVisitor {
/// Use authenticate methode to go from Logged-out session to logged-in session
///
/// - Parameters:
/// - visitorId: newVisitorId to authenticate
/// - Important: After using this method, you should use Flagship.fetchFlags method to update the visitor informations
/// - Requires: Make sure that the experience continuity option is enabled on the flagship platform before using this method
@objc public func authenticate(visitorId: String) {

self.strategy?.getStrategy().authenticateVisitor(visitorId: visitorId)
@objc func authenticate(visitorId: String) {
self.strategy?.getStrategy().authenticateVisitor(visitorId: visitorId)

// Update the flagSyncStatus
self.flagSyncStatus = .AUTHENTICATED
}

/// Use authenticate methode to go from Logged in session to logged out session
@objc public func unauthenticate() {

@objc func unauthenticate() {
self.strategy?.getStrategy().unAuthenticateVisitor()
// Update the flagSyncStatus
self.flagSyncStatus = .UNAUTHENTICATED
}
}
11 changes: 9 additions & 2 deletions FlagShip/Source/Core/FSVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ import Foundation

/// Assigned hsitory
internal var assignedVariationHistory: [String: String] = [:]

// Initial value for the status .CREATED
internal var flagSyncStatus: FlagSynchStatus = .CREATED

init(aVisitorId: String, aContext: [String: Any], aConfigManager: FSConfigManager, aHasConsented: Bool, aIsAuthenticated: Bool) {
/// Set authenticated
Expand Down Expand Up @@ -99,7 +102,6 @@ import Foundation
if self.configManager.flagshipConfig.mode == .BUCKETING, Flagship.sharedInstance.currentStatus != .PANIC_ON {
self.sendHit(FSSegment(self.getContext()))
}

})
}

Expand All @@ -116,6 +118,8 @@ import Foundation
/// - Parameter newContext: user's context
@objc public func updateContext(_ context: [String: Any]) {
self.strategy?.getStrategy().updateContext(context)
// Update the flagSyncStatus
self.flagSyncStatus = .CONTEXT_UPDATED
}

/// Update context with one
Expand Down Expand Up @@ -207,6 +211,10 @@ import Foundation
/// - Parameter defaultValue:flag default value
/// - Returns: FSFlag object, If no flag match the given key, an empty flag will be returned
public func getFlag<T>(key: String, defaultValue: T?) -> FSFlag {
// We dispaly a warning if the flag's status is not fetched
if self.flagSyncStatus != .FLAGS_FETCHED {
FlagshipLogManager.Log(level: .ALL, tag: .FLAG, messageToDisplay: FSLogMessage.MESSAGE(self.flagSyncStatus.warningMessage(key, self.visitorId)))
}
/// Check the key if exist
guard let modification = self.currentFlags[key] else {
return FSFlag(key, nil, defaultValue, self.strategy)
Expand All @@ -221,7 +229,6 @@ import Foundation
/// //
/////////////////


/// Send Hit consent
internal func sendHitConsent(_ hasConsented: Bool) {
// create the hit consent
Expand Down
6 changes: 3 additions & 3 deletions FlagShip/Source/Logger/FlagshipConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ enum FSLogMessage: CustomStringConvertible {

/// Universal
case MESSAGE(_ key: String?)

var description: String {
var ret: String

Expand Down Expand Up @@ -150,9 +150,9 @@ enum FSLogMessage: CustomStringConvertible {
case .IGNORE_UNAUTHENTICATE:
ret = "UnAuthenticateVisitor method will be ignored in Bucketing configuration"
case .GET_CAMPAIGN(let key):
ret = "Get campaign, the context used for is \(key)"
ret = "Fetching flags, the user context used for is:\(key)"
case .GET_CAMPAIGN_URL(let key):
ret = "The url for the get campaign is \(key)"
ret = "Fetch flags request: \(key)"
case .GET_CAMPAIGN_RESPONSE(let key):
ret = "Response for fetch flags is \(key)"
case .GET_SCRIPT_RESPONSE(let key):
Expand Down
66 changes: 29 additions & 37 deletions FlagShip/Source/Logger/FlagshipLogManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,45 @@

import Foundation

public enum FSTag:String {

case GLOBAL = "GLOBAL"
case VISITOR = "VISITOR"
case INITIALIZATION = "INITIALIZATION"
case CONFIGURATION = "CONFIGURATION"
case BUCKETING = "BUCKETING"
case UPDATE_CONTEXT = "UPDATE_CONTEXT"
case CLEAR_CONTEXT = "CLEAR_CONTEXT"
case SYNCHRONIZE = "SYNCHRONIZE"
case CAMPAIGNS = "CAMPAIGNS"
case PARSING = "PARSING"
case TARGETING = "TARGETING"
case ALLOCATION = "ALLOCATION"
case GET_MODIFICATION = "GET_MODIFICATION"
case GET_MODIFICATION_INFO = "GET_MODIFICATION_INFO"
case TRACKING = "HIT"
case ACTIVATE = "ACTIVATE"
case AUTHENTICATE = "AUTHENTICATE"
case UNAUTHENTICATE = "UNAUTHENTICATE"
case CONSENT = "CONSENT"
case EXCEPTION = "EXCEPTION"
case STORAGE = "CACHE"

public enum FSTag: String {
case GLOBAL
case VISITOR
case INITIALIZATION
case CONFIGURATION
case BUCKETING
case UPDATE_CONTEXT
case CLEAR_CONTEXT
case SYNCHRONIZE
case CAMPAIGNS
case PARSING
case TARGETING
case ALLOCATION
case GET_MODIFICATION
case GET_MODIFICATION_INFO
case TRACKING = "HIT"
case ACTIVATE
case AUTHENTICATE
case UNAUTHENTICATE
case CONSENT
case EXCEPTION
case STORAGE = "CACHE"
case FLAG
}


class FlagshipLogManager:FSLogManager{

override init(){

class FlagshipLogManager: FSLogManager {
override init() {
super.init()
}

static func Log(level: FSLevel, tag: FSTag, messageToDisplay:FSLogMessage) {

if isAllowed(level){

print("Flagship - \(tag.rawValue) - \(messageToDisplay.description)") /// Do not delete this print
static func Log(level: FSLevel, tag: FSTag, messageToDisplay: FSLogMessage) {
if isAllowed(level) {
print("Flagship - \(tag.rawValue) - \(messageToDisplay.description)") /// Do not delete this print
}
}

static private func isAllowed(_ newLevel:FSLevel)-> Bool{

private static func isAllowed(_ newLevel: FSLevel) -> Bool {
let currentLevel = Flagship.sharedInstance.currentConfig.logLevel

return ((newLevel.rawValue < currentLevel.rawValue) || (newLevel.rawValue == currentLevel.rawValue))
}

}
46 changes: 15 additions & 31 deletions FlagShip/Source/Models/FSContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,50 @@
// Created by Adel on 07/09/2021.
//


internal class FSContext {
private var _currentContext: [String: Any] = [:]


private var _currentContext:[String:Any] = [:]


init(_ contextValues:[String:Any]){
init(_ contextValues: [String: Any]) {
/// Clean context with none valide type
self._currentContext = contextValues.filter{ $0.value is Int || $0.value is Double || $0.value is String || $0.value is Bool}
self._currentContext = contextValues.filter { $0.value is Int || $0.value is Double || $0.value is String || $0.value is Bool }
self._currentContext = contextValues
// Set all_users key
self._currentContext.updateValue("", forKey: ALL_USERS)
_currentContext.updateValue("", forKey: ALL_USERS)
}

public func updateContext(_ newValues:[String : Any]){

public func updateContext(_ newValues: [String: Any]) {
FlagshipLogManager.Log(level: .INFO, tag: .UPDATE_CONTEXT, messageToDisplay: FSLogMessage.UPDATE_CONTEXT)
for key in newValues.keys{
if let val = newValues[key]{
for key in newValues.keys {
if let val = newValues[key] {
switch val {
case is Int, is Double, is String, is Bool:
updateContext(key, val)
break

default:
FlagshipLogManager.Log(level: .ERROR, tag: .UPDATE_CONTEXT, messageToDisplay: FSLogMessage.UPDATE_CONTEXT_FAILED(key))
}
}
}
}


public func updateContext(_ key:String , _ newValue:Any){

public func updateContext(_ key: String, _ newValue: Any) {
_currentContext.updateValue(newValue, forKey: key)
}



/// Load preSet Context
func loadPreSetContext(){

_currentContext.merge(FlagshipContextManager.getPresetContextForApp()) { (_, new) in new }
func loadPreSetContext() {
_currentContext.merge(FlagshipContextManager.getPresetContextForApp()) { _, new in new }
}


func getCurrentContext()->[String:Any]{

func getCurrentContext() -> [String: Any] {
return _currentContext
}

func clearContext(){

func clearContext() {
_currentContext.removeAll()
}

func mergeContext(_ ctxValue:[String:Any]){

/// To do later
func mergeContext(_ ctxValue: [String: Any]) {
/// To do later
}


}
2 changes: 2 additions & 0 deletions FlagShip/Source/Strategy/FSDefaultStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class FSDefaultStrategy: FSDelegateStrategy {
Flagship.sharedInstance.currentStatus = .READY
// Resume the process batching when the panic mode is OFF
self.visitor.configManager.trackingManager?.resumeBatchingProcess()
// Update the flagSyncStatus
self.visitor.flagSyncStatus = .FLAGS_FETCHED
onSyncCompleted(.READY)
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion FlagShip/Source/Tools/FlagShipVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ import Foundation

/// This file is automatically updated 2.0.0

public let FlagShipVersion = "3.2.0"
public let FlagShipVersion = "3.2.1"
Loading

0 comments on commit ae3150d

Please sign in to comment.