diff --git a/Sources/SwiftDevRant/Models/NotificationFeed.swift b/Sources/SwiftDevRant/Models/NotificationFeed.swift index 2f681a4..93914f9 100644 --- a/Sources/SwiftDevRant/Models/NotificationFeed.swift +++ b/Sources/SwiftDevRant/Models/NotificationFeed.swift @@ -2,7 +2,7 @@ import Foundation /// Contains a list of all notifications for the logged in user and the numbers of unread notifications. public struct NotificationFeed: Hashable { - public enum Categories: String, CaseIterable { + public enum Category: String, CaseIterable { case all = "" case upvotes = "upvotes" case mentions = "mentions" @@ -32,6 +32,10 @@ public struct NotificationFeed: Hashable { extension NotificationFeed { struct CodingData: Decodable { + struct Container: Decodable { + let data: NotificationFeed.CodingData + } + let check_time: Int let items: [Notification.CodingData] let unread: UnreadNumbers.CodingData diff --git a/Sources/SwiftDevRant/Models/Rant.swift b/Sources/SwiftDevRant/Models/Rant.swift index 14c43f2..3c14323 100644 --- a/Sources/SwiftDevRant/Models/Rant.swift +++ b/Sources/SwiftDevRant/Models/Rant.swift @@ -71,7 +71,7 @@ extension Rant { let text: String let score: Int let created_time: Int - let attached_image: AttachedImage.CodingData? + let attached_image: AttachedImage.CodingData? // this value can also be of type String. See the custom decoding code. let num_comments: Int let tags: [String] let vote_state: Int @@ -104,8 +104,10 @@ extension Rant { created_time = try values.decode(Int.self, forKey: .created_time) do { + // If the value is an object, decode it into an attached image. attached_image = try values.decode(AttachedImage.CodingData.self, forKey: .attached_image) } catch { + // Otherwise it was an empty string. Treat is as no attached image. attached_image = nil } diff --git a/Sources/SwiftDevRant/SwiftDevRant.swift b/Sources/SwiftDevRant/SwiftDevRant.swift index bb211ac..39c3bb7 100644 --- a/Sources/SwiftDevRant/SwiftDevRant.swift +++ b/Sources/SwiftDevRant/SwiftDevRant.swift @@ -1,3 +1,5 @@ +import Foundation + public struct SwiftDevRant { let request: Request let backend = DevRantBackend() @@ -79,7 +81,7 @@ public struct SwiftDevRant { return response.decoded } - /// Get all weeklies as a list. + /// Gets all weeklies as a list. /// /// - Parameters: /// - token: The token from the `logIn` call response. @@ -90,4 +92,45 @@ public struct SwiftDevRant { return response.weeks.map(\.decoded) } + + /// Gets a specific week's weekly rants. + /// + /// - Parameters: + /// - token: The token from the `logIn` call response. + /// - week: The number of the week. Pass `nil` to get the latest week's rants. + /// - limit: The number of rants for pagination. + /// - skip: How many rants to skip for pagination. + public func getWeeklyRants(token: AuthToken, week: Int?, limit: Int = 20, skip: Int) async throws -> RantFeed { + var parameters: [String: String] = [:] + + parameters["week"] = week.flatMap { String($0) } + parameters["limit"] = String(limit) + parameters["skip"] = String(skip) + + //parameters["sort"] = "algo" //TODO: This seems wrong. Check if this is needed or not. + + let config = makeConfig(.get, path: "devrant/weekly-rants", urlParameters: parameters) + + let response: RantFeed.CodingData = try await request.requestJson(config: config, apiError: DevRantApiError.CodingData.self) + + return response.decoded + } + + /// Gets the list of notifications and numbers for each notification type. + /// + /// - Parameters: + /// - token: The token from the `logIn` call response. + /// - lastChecked: Pass the value from the last response or `nil`. + public func getNotificationFeed(token: AuthToken, lastChecked: Date?, category: NotificationFeed.Category) async throws -> NotificationFeed { + var parameters: [String: String] = [:] + + parameters["last_time"] = lastChecked.flatMap { String(Int($0.timeIntervalSince1970)) } ?? "0" + parameters["ext_prof"] = "1" // I don't know wtf that is. + + let config = makeConfig(.get, path: "users/me/notif-feed\(category.rawValue)", urlParameters: parameters) + + let response: NotificationFeed.CodingData.Container = try await request.requestJson(config: config, apiError: DevRantApiError.CodingData.self) + + return response.data.decoded + } }