Manos Chorianopoulos

getCampaigns unauthorized fix

......@@ -1121,6 +1121,81 @@ After these changes, the framework should:
After the initial legacy credential removal, a comprehensive search revealed **2 additional problematic checks** that could still cause issues:
#### **Issue #7: getCampaigns Authentication Logic (FINAL FIX)**
**File**: `SwiftWarplyFramework/SwiftWarplyFramework/Core/WarplySDK.swift`
**Problem**: `getCampaigns` method failed with ERROR: -1 when user not authenticated due to failed `getCampaignsPersonalized` and `getAvailableCoupons` calls
**Impact**: ❌ **CRITICAL** - Campaign loading completely failed for non-authenticated users
**Root Cause**: The method tried to call authentication-required endpoints (`getCampaignsPersonalized` and `getAvailableCoupons`) even when user was not logged in, causing the entire flow to fail.
**Solution**: **Authentication-First Approach**
```swift
// Check if user is authenticated to determine campaign processing approach
if self.isUserAuthenticated() {
// User is authenticated - get full experience with personalized campaigns and coupon filtering
print("✅ [WarplySDK] User authenticated - loading personalized campaigns and coupon availability")
self.getCampaignsPersonalized(language: language, filters: filters, completion: { personalizedCampaigns in
// ... full authenticated flow with parseCampaigns filtering
})
} else {
// User not authenticated - return all basic campaigns without coupon filtering
print("ℹ️ [WarplySDK] User not authenticated - returning all basic campaigns without coupon filtering")
// Skip parseCampaigns entirely - return raw campaigns without filtering
completion(campaignsArray)
}
```
**Key Changes**:
1. **Added `isUserAuthenticated()` helper method** - checks database for valid, non-expired tokens
2. **Authentication-first logic** - check auth status before making dependent calls
3. **Graceful degradation** - non-authenticated users get basic campaigns without filtering
4. **Skip `parseCampaigns`** - for non-authenticated users to avoid empty results due to missing coupon availability
**Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users
---
### **🔧 Additional Safety Fixes - June 27, 2025 (Session 2)**
After the initial legacy credential removal, a comprehensive search revealed **3 additional problematic checks** that could still cause issues:
#### **Issue #7: getCampaigns Authentication Logic (FINAL FIX)**
**File**: `SwiftWarplyFramework/SwiftWarplyFramework/Core/WarplySDK.swift`
**Problem**: `getCampaigns` method failed with ERROR: -1 when user not authenticated due to failed `getCampaignsPersonalized` and `getAvailableCoupons` calls
**Impact**: ❌ **CRITICAL** - Campaign loading completely failed for non-authenticated users
**Root Cause**: The method tried to call authentication-required endpoints (`getCampaignsPersonalized` and `getAvailableCoupons`) even when user was not logged in, causing the entire flow to fail.
**Solution**: **Authentication-First Approach**
```swift
// Check if user is authenticated to determine campaign processing approach
if self.isUserAuthenticated() {
// User is authenticated - get full experience with personalized campaigns and coupon filtering
print("✅ [WarplySDK] User authenticated - loading personalized campaigns and coupon availability")
self.getCampaignsPersonalized(language: language, filters: filters, completion: { personalizedCampaigns in
// ... full authenticated flow with parseCampaigns filtering
})
} else {
// User not authenticated - return all basic campaigns without coupon filtering
print("ℹ️ [WarplySDK] User not authenticated - returning all basic campaigns without coupon filtering")
// Skip parseCampaigns entirely - return raw campaigns without filtering
completion(campaignsArray)
}
```
**Key Changes**:
1. **Added `isUserAuthenticated()` helper method** - checks database for valid, non-expired tokens
2. **Authentication-first logic** - check auth status before making dependent calls
3. **Graceful degradation** - non-authenticated users get basic campaigns without filtering
4. **Skip `parseCampaigns`** - for non-authenticated users to avoid empty results due to missing coupon availability
**Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users
---
#### **Issue #5: NetworkService Signature Generation (CRITICAL)**
**File**: `SwiftWarplyFramework/SwiftWarplyFramework/Network/NetworkService.swift`
**Problem**: Conditional signature generation that skipped the `loyalty-signature` header when API key was empty
......
......@@ -1589,11 +1589,15 @@ public final class WarplySDK {
}
}
// Get personalized campaigns (still using MyApi temporarily)
// Check if user is authenticated to determine campaign processing approach
if self.isUserAuthenticated() {
// User is authenticated - get full experience with personalized campaigns and coupon filtering
print("✅ [WarplySDK] User authenticated - loading personalized campaigns and coupon availability")
self.getCampaignsPersonalized(language: language, filters: filters, completion: { personalizedCampaigns in
campaignsArray = campaignsArray + (personalizedCampaigns ?? [])
// Get available coupons (still using MyApi temporarily)
// Get available coupons for authenticated users
self.getAvailableCoupons { availabilityData in
if let availabilityData = availabilityData {
for tempCampaign in campaignsArray {
......@@ -1605,11 +1609,14 @@ public final class WarplySDK {
}
}
// For authenticated users: use parseCampaigns (filters by coupon availability)
let parsedCampaigns = self.parseCampaigns(campaignsArray)
completion(parsedCampaigns)
}
}, failureCallback: { errorCode in
// If personalized campaigns fail, continue with regular campaigns
// If personalized campaigns fail, still try coupon availability
print("⚠️ [WarplySDK] Personalized campaigns failed for authenticated user - continuing with basic campaigns")
self.getAvailableCoupons { availabilityData in
if let availabilityData = availabilityData {
for tempCampaign in campaignsArray {
......@@ -1621,11 +1628,19 @@ public final class WarplySDK {
}
}
// For authenticated users: use parseCampaigns (filters by coupon availability)
let parsedCampaigns = self.parseCampaigns(campaignsArray)
completion(parsedCampaigns)
}
})
} else {
// User not authenticated - return all basic campaigns without coupon filtering
print("ℹ️ [WarplySDK] User not authenticated - returning all basic campaigns without coupon filtering")
// Skip parseCampaigns entirely - return raw campaigns without filtering
completion(campaignsArray)
}
} else {
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_error_campaigns_loyalty"
dynatraceEvent._parameters = nil
......@@ -2967,6 +2982,19 @@ public final class WarplySDK {
// MARK: - Private Helper Methods
/// Check if user is currently authenticated with valid tokens
private func isUserAuthenticated() -> Bool {
do {
if let tokenModel = try DatabaseManager.shared.getTokenModelSync() {
// Check if token exists and is not expired
return !tokenModel.accessToken.isEmpty && !tokenModel.isExpired
}
} catch {
print("⚠️ [WarplySDK] Failed to check authentication status: \(error)")
}
return false
}
private func parseCampaigns(_ campaigns: [CampaignItemModel]) -> [CampaignItemModel] {
let filteredCampaigns = campaigns.filter { $0._coupon_availability != 0 }
......