From d330881d5713656018bc364634a32ed9f773024f Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 15 Aug 2022 18:55:01 +0100
Subject: [PATCH] Add ProcessBannedList functor

---
 Package.swift                                 |  1 +
 .../ReportingFeature/ProcessBannedList.swift  | 64 +++++++++++++++++++
 2 files changed, 65 insertions(+)
 create mode 100644 Sources/ReportingFeature/ProcessBannedList.swift

diff --git a/Package.swift b/Package.swift
index d204c98f..f10ccf87 100644
--- a/Package.swift
+++ b/Package.swift
@@ -749,6 +749,7 @@ let package = Package(
         .target(
             name: "ReportingFeature",
             dependencies: [
+                .product(name: "SwiftCSV", package: "SwiftCSV"),
                 .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
             ],
             resources: [
diff --git a/Sources/ReportingFeature/ProcessBannedList.swift b/Sources/ReportingFeature/ProcessBannedList.swift
new file mode 100644
index 00000000..3399a34e
--- /dev/null
+++ b/Sources/ReportingFeature/ProcessBannedList.swift
@@ -0,0 +1,64 @@
+import Foundation
+import SwiftCSV
+import XCTestDynamicOverlay
+
+public struct ProcessBannedList {
+    public enum ElementError: Swift.Error {
+        case missingUserId
+        case invalidUserId(String)
+    }
+
+    public enum Error: Swift.Error {
+        case invalidData
+        case csv(Swift.Error)
+    }
+
+    public typealias ForEach = (Result<Data, ElementError>) -> Void
+    public typealias Completion = (Result<Void, Error>) -> Void
+
+    public var run: (Data, ForEach, Completion) -> Void
+
+    public func callAsFunction(
+        data: Data,
+        forEach: ForEach,
+        completion: Completion
+    ) {
+        run(data, forEach, completion)
+    }
+}
+
+extension ProcessBannedList {
+    public static let live = ProcessBannedList { data, forEach, completion in
+        guard let csvString = String(data: data, encoding: .utf8) else {
+            completion(.failure(.invalidData))
+            return
+        }
+        let csv: EnumeratedCSV
+        do {
+            csv = try EnumeratedCSV(string: csvString)
+        }
+        catch {
+            completion(.failure(.csv(error)))
+            return
+        }
+        csv.rows.forEach { row in
+            guard let userIdString = row.first else {
+                forEach(.failure(.missingUserId))
+                return
+            }
+            guard let userId = Data(base64Encoded: userIdString) else {
+                forEach(.failure(.invalidUserId(userIdString)))
+                return
+            }
+            forEach(.success(userId))
+        }
+        completion(.success(()))
+    }
+}
+
+extension ProcessBannedList {
+    public static let unimplemented = ProcessBannedList { _, _, _ in
+        let run: () -> Void = XCTUnimplemented("\(Self.self)")
+        run()
+    }
+}
-- 
GitLab