Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: More defensive enum decoding #1420

Merged
merged 7 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kDrive/UI/Controller/Menu/StoreViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ final class StoreViewController: UICollectionViewController, SceneStateRestorabl

private var purchaseEnabled = true
private var items = Item.allItems
private lazy var selectedPackId = DrivePackId(rawValue: driveFileManager.drive.pack.id)
private lazy var selectedPackId = DrivePackId(rawValue: driveFileManager.drive.pack.name)
private var selectedStorage = 1
private var selectedPeriod = PeriodTab.yearly {
didSet { updateOffers() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class FileDetailActivityTableViewCell: InsetTableViewCell {
localizedKey = "fileDetailsActivityFileColorUpdate"
case .fileColorDelete:
localizedKey = "fileDetailsActivityFileColorDelete"
case .none:
case .unknown:
localizedKey = "fileActivityUnknown"
}
detailLabel.text = localizedKey.localized
Expand Down
14 changes: 9 additions & 5 deletions kDriveCore/Data/Models/Drive/Drive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public enum MaintenanceReason: String, PersistableEnum, Codable {
case demoEnd = "demo_end"
case invoiceOverdue = "invoice_overdue"
case technical
case unknown

public init(from decoder: any Decoder) throws {
let singleKeyContainer = try decoder.singleValueContainer()
let value = try singleKeyContainer.decode(String.self)

self = MaintenanceReason(rawValue: value) ?? .unknown
}
}

public final class DrivePreferences: EmbeddedObject, Codable {
Expand Down Expand Up @@ -134,11 +142,7 @@ public final class Drive: Object, Codable {
}

public var isFreePack: Bool {
guard let packId = pack.drivePackId else {
return false
}

return packId == .free
return pack.drivePackId == .free
}

public var isInTechnicalMaintenance: Bool {
Expand Down
27 changes: 17 additions & 10 deletions kDriveCore/Data/Models/Drive/DrivePack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,21 @@
import Foundation
import RealmSwift

public enum DrivePackId: Int {
case solo = 1
case team = 2
case pro = 3
case free = 6
case kSuiteStandard = 8
case kSuitePro = 11
case kSuiteEntreprise = 14
public enum DrivePackId: String {
case solo
case team
case pro
case free
case kSuiteStandard = "ksuite_standard"
case kSuitePro = "ksuite_pro"
case kSuiteEntreprise = "ksuite_entreprise"
case myKSuite = "my_ksuite"
case myKSuitePlus = "my_ksuite_plus"
case unknown

public init(apiRawValue: String) {
self = .init(rawValue: apiRawValue) ?? .unknown
}
}

public class DrivePack: EmbeddedObject, Codable {
Expand All @@ -39,8 +46,8 @@ public class DrivePack: EmbeddedObject, Codable {
}

/// Convenience enum bridge
public var drivePackId: DrivePackId? {
DrivePackId(rawValue: id)
public var drivePackId: DrivePackId {
DrivePackId(apiRawValue: name)
}

enum CodingKeys: String, CodingKey {
Expand Down
8 changes: 8 additions & 0 deletions kDriveCore/Data/Models/DriveUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public enum DriveUserRole: String, Codable {
case admin
case user
case external
case unknown

public init(from decoder: any Decoder) throws {
let singleKeyContainer = try decoder.singleValueContainer()
let value = try singleKeyContainer.decode(String.self)

self = DriveUserRole(rawValue: value) ?? .unknown
}
}

public enum UserPermission: String, Codable, CaseIterable {
Expand Down
34 changes: 30 additions & 4 deletions kDriveCore/Data/Models/File.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ public enum ConvertedType: String, CaseIterable {
public static let ignoreThumbnailTypes = downloadableTypes
/// Documents that can be previewed by the OS but not necessarily handled by OnlyOffice (eg. .pages)
public static let documentTypes: Set<ConvertedType> = [.presentation, .spreadsheet, .text]

public init(apiRawValue: String) {
self = .init(rawValue: apiRawValue) ?? .unknown
}
}

/// Minimal data needed to query a PublicShare
Expand Down Expand Up @@ -321,7 +325,20 @@ public enum FileStatus: String {

public enum FileImportStatus: String, PersistableEnum, Codable {
// ⚠️ For some reason PersistableEnum breaks something with key decoding, that's why we are explicitly writing snake case
case waiting, inProgress = "in_progress", done, failed, canceling, canceled
case waiting
case inProgress = "in_progress"
case done
case failed
case canceling
case canceled
case unknown

public init(from decoder: any Decoder) throws {
let singleKeyContainer = try decoder.singleValueContainer()
let value = try singleKeyContainer.decode(String.self)

self = FileImportStatus(rawValue: value) ?? .unknown
}
}

public final class FileExternalImport: EmbeddedObject, Codable {
Expand Down Expand Up @@ -370,6 +387,15 @@ public enum FileSupportedBy: String, PersistableEnum, Codable {
case thumbnail
/// This file can be read by OnlyOffice
case onlyOffice = "onlyoffice"

case unknown

public init(from decoder: any Decoder) throws {
let singleKeyContainer = try decoder.singleValueContainer()
let value = try singleKeyContainer.decode(String.self)

self = FileSupportedBy(rawValue: value) ?? .unknown
}
}

public typealias FileCursor = String
Expand Down Expand Up @@ -666,7 +692,7 @@ public final class File: Object, Codable {
} else if isBookmark {
return .url
} else {
return ConvertedType(rawValue: extensionType ?? "") ?? .unknown
return ConvertedType(apiRawValue: extensionType ?? "")
}
}

Expand Down Expand Up @@ -840,9 +866,9 @@ public final class File: Object, Codable {
dropbox = try container.decodeIfPresent(DropBox.self, forKey: .dropbox)
externalImport = try container.decodeIfPresent(FileExternalImport.self, forKey: .externalImport)
size = try container.decodeIfPresent(Int.self, forKey: .size)
let rawSupportedBy = try container.decodeIfPresent([String].self, forKey: .supportedBy) ?? []
let rawSupportedBy = try container.decodeIfPresent([FileSupportedBy].self, forKey: .supportedBy) ?? []
supportedBy = MutableSet()
supportedBy.insert(objectsIn: rawSupportedBy.compactMap { FileSupportedBy(rawValue: $0) })
supportedBy.insert(objectsIn: rawSupportedBy.filter { $0 != .unknown })
extensionType = try container.decodeIfPresent(String.self, forKey: .extensionType)
version = try container.decodeIfPresent(FileVersion.self, forKey: .version)
conversion = try container.decodeIfPresent(FileConversion.self, forKey: .conversion)
Expand Down
9 changes: 7 additions & 2 deletions kDriveCore/Data/Models/FileActivity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public enum FileActivityType: String, Codable, CaseIterable {
case collaborativeUserDelete = "collaborative_user_delete"
case fileColorUpdate = "file_color_update"
case fileColorDelete = "file_color_delete"
case unknown

public static let displayedFileActivities: [FileActivityType] = [
.fileCreate,
Expand Down Expand Up @@ -85,6 +86,10 @@ public enum FileActivityType: String, Codable, CaseIterable {
.fileColorUpdate,
.fileColorDelete
]

public init(apiRawValue: String) {
self = .init(rawValue: apiRawValue) ?? .unknown
}
}

public class FileActivity: Object, Decodable {
Expand All @@ -109,8 +114,8 @@ public class FileActivity: Object, Decodable {
public var mergedFileActivities: [FileActivity] = []

/// Activity type
public var action: FileActivityType? {
return FileActivityType(rawValue: rawAction)
public var action: FileActivityType {
return FileActivityType(apiRawValue: rawAction)
}

public var user: DriveUser? {
Expand Down
Loading