Manos Chorianopoulos

fix context response parsing

...@@ -1156,6 +1156,86 @@ if self.isUserAuthenticated() { ...@@ -1156,6 +1156,86 @@ if self.isUserAuthenticated() {
1156 **Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users 1156 **Result**: ✅ **No more ERROR: -1** - campaigns load successfully for both authenticated and non-authenticated users
1157 1157
1158 --- 1158 ---
1159 +
1160 +#### **Issue #8: Central Context Response Parsing (FINAL SOLUTION)**
1161 +**File**: `SwiftWarplyFramework/SwiftWarplyFramework/Network/NetworkService.swift`
1162 +**Problem**: All context endpoints failed due to incorrect response structure parsing - looking for data at wrong level
1163 +**Impact**: ❌ **CRITICAL** - Multiple endpoints failing with ERROR: -1 due to response parsing issues
1164 +
1165 +**Root Cause**: The server returns responses in format `{"status": "1", "context": {...}}` but the code expected data at top level.
1166 +
1167 +**Example Response Structure**:
1168 +```json
1169 +{
1170 + "status": "1",
1171 + "context": {
1172 + "MAPP_CAMPAIGNING-status": 1,
1173 + "MAPP_CAMPAIGNING": { "campaigns": [...] },
1174 + "events_processed": 1
1175 + }
1176 +}
1177 +```
1178 +
1179 +**Solution**: **Central Response Transformation in NetworkService**
1180 +```swift
1181 +/// Transform context-wrapped responses to flatten structure for backward compatibility
1182 +private func transformContextResponse(_ response: [String: Any]) -> [String: Any] {
1183 + // Detect context response pattern: {"status": "1", "context": {...}}
1184 + if let statusString = response["status"] as? String,
1185 + let context = response["context"] as? [String: Any] {
1186 +
1187 + print("🔄 [NetworkService] Detected context response - transforming structure")
1188 +
1189 + // Start with context content
1190 + var transformedResponse = context
1191 +
1192 + // Convert string status to integer for backward compatibility
1193 + transformedResponse["status"] = (statusString == "1") ? 1 : 0
1194 +
1195 + // Preserve any other top-level fields (like events_processed)
1196 + for (key, value) in response {
1197 + if key != "context" && key != "status" {
1198 + transformedResponse[key] = value
1199 + }
1200 + }
1201 +
1202 + return transformedResponse
1203 + }
1204 +
1205 + // Return unchanged if not a context response
1206 + return response
1207 +}
1208 +```
1209 +
1210 +**Integration**: Added to `requestRaw` method in NetworkService:
1211 +```swift
1212 +public func requestRaw(_ endpoint: Endpoint) async throws -> [String: Any] {
1213 + let data = try await performRequest(endpoint)
1214 +
1215 + do {
1216 + guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
1217 + throw NetworkError.invalidResponse
1218 + }
1219 +
1220 + // Transform context-wrapped responses for backward compatibility
1221 + let transformedResponse = transformContextResponse(json)
1222 + return transformedResponse
1223 + } catch {
1224 + throw NetworkError.decodingError(error)
1225 + }
1226 +}
1227 +```
1228 +
1229 +**Key Benefits**:
1230 +1. **Central Fix** - One solution fixes all context endpoints automatically
1231 +2. **Smart Detection** - Automatically detects context responses vs regular responses
1232 +3. **Backward Compatible** - Non-context responses pass through unchanged
1233 +4. **Future-Proof** - New context endpoints work automatically
1234 +5. **Zero Breaking Changes** - All existing code continues to work
1235 +
1236 +**Result**: ✅ **Universal fix for all context response parsing issues** - getCampaigns and all other context endpoints now work correctly
1237 +
1238 +---
1159 ### **🔧 Additional Safety Fixes - June 27, 2025 (Session 2)** 1239 ### **🔧 Additional Safety Fixes - June 27, 2025 (Session 2)**
1160 1240
1161 After the initial legacy credential removal, a comprehensive search revealed **3 additional problematic checks** that could still cause issues: 1241 After the initial legacy credential removal, a comprehensive search revealed **3 additional problematic checks** that could still cause issues:
......
...@@ -141,7 +141,10 @@ public final class NetworkService: NetworkServiceProtocol { ...@@ -141,7 +141,10 @@ public final class NetworkService: NetworkServiceProtocol {
141 guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { 141 guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
142 throw NetworkError.invalidResponse 142 throw NetworkError.invalidResponse
143 } 143 }
144 - return json 144 +
145 + // Transform context-wrapped responses for backward compatibility
146 + let transformedResponse = transformContextResponse(json)
147 + return transformedResponse
145 } catch { 148 } catch {
146 throw NetworkError.decodingError(error) 149 throw NetworkError.decodingError(error)
147 } 150 }
...@@ -177,6 +180,39 @@ public final class NetworkService: NetworkServiceProtocol { ...@@ -177,6 +180,39 @@ public final class NetworkService: NetworkServiceProtocol {
177 180
178 // MARK: - Private Methods 181 // MARK: - Private Methods
179 182
183 + /// Transform context-wrapped responses to flatten structure for backward compatibility
184 + /// Detects responses with pattern: {"status": "1", "context": {...}} and flattens them
185 + private func transformContextResponse(_ response: [String: Any]) -> [String: Any] {
186 + // Detect context response pattern: {"status": "1", "context": {...}}
187 + if let statusString = response["status"] as? String,
188 + let context = response["context"] as? [String: Any] {
189 +
190 + print("🔄 [NetworkService] Detected context response - transforming structure")
191 +
192 + // Start with context content
193 + var transformedResponse = context
194 +
195 + // Convert string status to integer for backward compatibility
196 + transformedResponse["status"] = (statusString == "1") ? 1 : 0
197 +
198 + // Preserve any other top-level fields (like events_processed)
199 + for (key, value) in response {
200 + if key != "context" && key != "status" {
201 + transformedResponse[key] = value
202 + }
203 + }
204 +
205 + print("✅ [NetworkService] Context response transformed successfully")
206 + print(" Original keys: \(Array(response.keys).sorted())")
207 + print(" Transformed keys: \(Array(transformedResponse.keys).sorted())")
208 +
209 + return transformedResponse
210 + }
211 +
212 + // Return unchanged if not a context response
213 + return response
214 + }
215 +
180 private func performRequest(_ endpoint: Endpoint) async throws -> Data { 216 private func performRequest(_ endpoint: Endpoint) async throws -> Data {
181 // Check network connectivity 217 // Check network connectivity
182 guard isConnected else { 218 guard isConnected else {
......