66 lines
2.3 KiB
Swift
66 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
struct DraftRecord: Codable, Identifiable {
|
|
var id: String { item.slug.isEmpty ? item.title : item.slug }
|
|
var serverURL: String
|
|
var savedAt: Date
|
|
var item: ContentItem
|
|
var markdown: String
|
|
}
|
|
|
|
final class DraftStore {
|
|
private let folder: URL
|
|
|
|
init() {
|
|
let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
|
|
?? URL(fileURLWithPath: NSTemporaryDirectory())
|
|
folder = base.appendingPathComponent("TCMS Mac Client", isDirectory: true)
|
|
try? FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
|
|
}
|
|
|
|
func save(item: ContentItem, markdown: String, serverURL: String) throws {
|
|
let record = DraftRecord(serverURL: serverURL, savedAt: Date(), item: item, markdown: markdown)
|
|
let data = try JSONEncoder.tcms.encode(record)
|
|
try data.write(to: fileURL(for: record.id), options: .atomic)
|
|
}
|
|
|
|
func remove(id: String) {
|
|
try? FileManager.default.removeItem(at: fileURL(for: id))
|
|
}
|
|
|
|
func loadAll(serverURL: String) -> [DraftRecord] {
|
|
let urls = (try? FileManager.default.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)) ?? []
|
|
return urls.compactMap { url in
|
|
guard let data = try? Data(contentsOf: url),
|
|
let record = try? JSONDecoder.tcms.decode(DraftRecord.self, from: data),
|
|
record.serverURL == serverURL else {
|
|
return nil
|
|
}
|
|
return record
|
|
}
|
|
.sorted { $0.savedAt > $1.savedAt }
|
|
}
|
|
|
|
private func fileURL(for id: String) -> URL {
|
|
let safe = id.replacingOccurrences(of: "[^A-Za-z0-9._-]+", with: "-", options: .regularExpression)
|
|
return folder.appendingPathComponent(safe.isEmpty ? "untitled" : safe).appendingPathExtension("json")
|
|
}
|
|
}
|
|
|
|
private extension JSONEncoder {
|
|
static var tcms: JSONEncoder {
|
|
let encoder = JSONEncoder()
|
|
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
|
encoder.dateEncodingStrategy = .iso8601
|
|
return encoder
|
|
}
|
|
}
|
|
|
|
private extension JSONDecoder {
|
|
static var tcms: JSONDecoder {
|
|
let decoder = JSONDecoder()
|
|
decoder.dateDecodingStrategy = .iso8601
|
|
return decoder
|
|
}
|
|
}
|