You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
12 KiB
321 lines
12 KiB
//
|
|
// MastodonDataManager.swift
|
|
// elpha-ios
|
|
//
|
|
// Created by Dwayne Harris on 10/1/18.
|
|
// Copyright © 2018 Elpha. All rights reserved.
|
|
//
|
|
|
|
import CoreData
|
|
import Foundation
|
|
import MastodonKit
|
|
|
|
class UpsertResult<T> {
|
|
var model: T
|
|
var new: Bool = false
|
|
|
|
init(model: T, new: Bool) {
|
|
self.model = model
|
|
self.new = new
|
|
}
|
|
}
|
|
|
|
public class MastodonDataManager {
|
|
static func setAccount(_ account: AccountMO, withRemoteAccount remoteAccount: Account) -> AccountMO {
|
|
account.id = remoteAccount.id
|
|
account.username = remoteAccount.username
|
|
account.acct = remoteAccount.acct
|
|
account.displayName = remoteAccount.displayName
|
|
account.note = remoteAccount.note
|
|
account.url = remoteAccount.url
|
|
account.avatarURL = URL(string: remoteAccount.avatar)
|
|
account.avatarStaticURL = URL(string: remoteAccount.avatarStatic)
|
|
account.headerURL = URL(string: remoteAccount.header)
|
|
account.headerStaticURL = URL(string: remoteAccount.headerStatic)
|
|
account.locked = remoteAccount.locked
|
|
account.createdAt = remoteAccount.createdAt
|
|
account.followersCount = Int32(remoteAccount.followersCount)
|
|
account.followingCount = Int32(remoteAccount.followingCount)
|
|
account.statusesCount = Int32(remoteAccount.statusesCount)
|
|
|
|
return account
|
|
}
|
|
|
|
static func upsertAccount(_ remoteAccount: Account) -> AccountMO? {
|
|
let request = NSFetchRequest<AccountMO>(entityName: "Account")
|
|
request.predicate = NSPredicate(format: "id == %@", remoteAccount.id)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let account = results.first {
|
|
return setAccount(account, withRemoteAccount: remoteAccount)
|
|
} else {
|
|
return setAccount(AccountMO(context: CoreDataManager.shared.context), withRemoteAccount: remoteAccount)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setAttachment(_ attachment: AttachmentMO, withRemoteAttachment remoteAttachment: Attachment) -> AttachmentMO {
|
|
attachment.id = remoteAttachment.id
|
|
attachment.type = remoteAttachment.type.rawValue
|
|
attachment.url = URL(string: remoteAttachment.url)
|
|
attachment.previewURL = URL(string: remoteAttachment.previewURL)
|
|
attachment.remoteURL = remoteAttachment.remoteURL
|
|
attachment.textURL = remoteAttachment.textURL
|
|
|
|
return attachment
|
|
}
|
|
|
|
static func upsertAttachment(_ remoteAttachment: Attachment) -> AttachmentMO? {
|
|
let request = NSFetchRequest<AttachmentMO>(entityName: "Attachment")
|
|
request.predicate = NSPredicate(format: "id == %@", remoteAttachment.id)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let attachment = results.first {
|
|
return setAttachment(attachment, withRemoteAttachment: remoteAttachment)
|
|
} else {
|
|
return setAttachment(AttachmentMO(context: CoreDataManager.shared.context), withRemoteAttachment: remoteAttachment)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setMention(_ mention: MentionMO, withRemoteMention remoteMention: Mention) -> MentionMO {
|
|
mention.id = remoteMention.id
|
|
mention.username = remoteMention.username
|
|
mention.acct = remoteMention.acct
|
|
mention.url = URL(string: remoteMention.url)
|
|
|
|
return mention
|
|
}
|
|
|
|
static func upsertMention(_ remoteMention: Mention) -> MentionMO? {
|
|
let request = NSFetchRequest<MentionMO>(entityName: "Mention")
|
|
request.predicate = NSPredicate(format: "id == %@", remoteMention.id)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let mention = results.first {
|
|
return setMention(mention, withRemoteMention: remoteMention)
|
|
} else {
|
|
return setMention(MentionMO(context: CoreDataManager.shared.context), withRemoteMention: remoteMention)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setTag(_ tag: TagMO, withRemoteTag remoteTag: Tag) -> TagMO {
|
|
tag.name = remoteTag.name
|
|
tag.url = URL(string: remoteTag.url)
|
|
|
|
return tag
|
|
}
|
|
|
|
static func upsertTag(_ remoteTag: Tag) -> TagMO? {
|
|
let request = NSFetchRequest<TagMO>(entityName: "Tag")
|
|
request.predicate = NSPredicate(format: "name == %@", remoteTag.name)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let tag = results.first {
|
|
return setTag(tag, withRemoteTag: remoteTag)
|
|
} else {
|
|
return setTag(TagMO(context: CoreDataManager.shared.context), withRemoteTag: remoteTag)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setApp(_ app: AppMO, withRemoteApp remoteApp: Application) -> AppMO {
|
|
app.name = remoteApp.name
|
|
|
|
if let website = remoteApp.website {
|
|
app.website = URL(string: website)
|
|
}
|
|
|
|
return app
|
|
}
|
|
|
|
static func upsertApp(_ remoteApp: Application) -> AppMO? {
|
|
let request = NSFetchRequest<AppMO>(entityName: "App")
|
|
request.predicate = NSPredicate(format: "name == %@", remoteApp.name)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let app = results.first {
|
|
return setApp(app, withRemoteApp: remoteApp)
|
|
} else {
|
|
return setApp(AppMO(context: CoreDataManager.shared.context), withRemoteApp: remoteApp)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setEmoji(_ emoji: EmojiMO, withRemoteEmoji remoteEmoji: Emoji) -> EmojiMO {
|
|
emoji.shortcode = remoteEmoji.shortcode
|
|
emoji.staticURL = remoteEmoji.staticURL
|
|
emoji.url = remoteEmoji.url
|
|
emoji.visibleInPicker = false
|
|
|
|
return emoji
|
|
}
|
|
|
|
static func upsertEmoji(_ remoteEmoji: Emoji) -> EmojiMO? {
|
|
let request = NSFetchRequest<EmojiMO>(entityName: "Emoji")
|
|
request.predicate = NSPredicate(format: "url == %@", remoteEmoji.url.absoluteString)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let emoji = results.first {
|
|
return setEmoji(emoji, withRemoteEmoji: remoteEmoji)
|
|
} else {
|
|
return setEmoji(EmojiMO(context: CoreDataManager.shared.context), withRemoteEmoji: remoteEmoji)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func setStatus(_ status: StatusMO, withRemoteStatus remoteStatus: Status) -> StatusMO {
|
|
status.id = remoteStatus.id
|
|
status.uri = URL(string: remoteStatus.uri)
|
|
status.url = remoteStatus.url
|
|
status.account = MastodonDataManager.upsertAccount(remoteStatus.account)
|
|
status.inReplyToID = remoteStatus.inReplyToID
|
|
status.inReplyToAccountID = remoteStatus.inReplyToAccountID
|
|
status.content = remoteStatus.content
|
|
status.createdAt = remoteStatus.createdAt
|
|
status.reblogsCount = Int32(remoteStatus.reblogsCount)
|
|
status.favouritesCount = Int32(remoteStatus.favouritesCount)
|
|
status.reblogged = remoteStatus.reblogged ?? false
|
|
status.favourited = remoteStatus.favourited ?? false
|
|
status.sensitive = remoteStatus.sensitive ?? false
|
|
status.pinned = remoteStatus.pinned ?? false
|
|
status.spoilerText = remoteStatus.spoilerText
|
|
status.visibility = remoteStatus.visibility.rawValue
|
|
|
|
if let app = remoteStatus.application {
|
|
status.app = MastodonDataManager.upsertApp(app)
|
|
}
|
|
|
|
remoteStatus.mediaAttachments.forEach { attachment in
|
|
if let attachment = MastodonDataManager.upsertAttachment(attachment) {
|
|
status.mutableOrderedSetValue(forKey: "attachments").add(attachment)
|
|
}
|
|
}
|
|
|
|
remoteStatus.mentions.forEach { mention in
|
|
if let mention = MastodonDataManager.upsertMention(mention) {
|
|
status.mutableSetValue(forKey: "mentions").add(mention)
|
|
}
|
|
}
|
|
|
|
remoteStatus.tags.forEach { tag in
|
|
if let tag = MastodonDataManager.upsertTag(tag) {
|
|
status.mutableSetValue(forKey: "tags").add(tag)
|
|
}
|
|
}
|
|
|
|
remoteStatus.emojis.forEach { emoji in
|
|
if let emoji = MastodonDataManager.upsertEmoji(emoji) {
|
|
status.mutableSetValue(forKey: "emojis").add(emoji)
|
|
}
|
|
}
|
|
|
|
if let reblog = remoteStatus.reblog {
|
|
let savedReblogResult = upsertStatus(reblog)
|
|
status.reblog = savedReblogResult?.model
|
|
}
|
|
|
|
return status
|
|
}
|
|
|
|
static func upsertStatus(_ remoteStatus: Status) -> UpsertResult<StatusMO>? {
|
|
let request = NSFetchRequest<StatusMO>(entityName: "Status")
|
|
request.predicate = NSPredicate(format: "id == %@", remoteStatus.id)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
if let status = results.first {
|
|
return UpsertResult(
|
|
model: setStatus(status, withRemoteStatus: remoteStatus),
|
|
new: false
|
|
)
|
|
} else {
|
|
return UpsertResult(
|
|
model: setStatus(StatusMO(context: CoreDataManager.shared.context), withRemoteStatus: remoteStatus),
|
|
new: true
|
|
)
|
|
}
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func saveClient(id: String, clientID: String, clientSecret: String, url: String) -> ClientMO {
|
|
let client = ClientMO(context: CoreDataManager.shared.context)
|
|
client.id = id
|
|
client.clientID = clientID
|
|
client.clientSecret = clientSecret
|
|
client.url = url
|
|
|
|
CoreDataManager.shared.saveContext()
|
|
return client
|
|
}
|
|
|
|
static func accountByID(_ id: String) -> AccountMO? {
|
|
let request = NSFetchRequest<AccountMO>(entityName: "Account")
|
|
request.predicate = NSPredicate(format: "id == %@", id)
|
|
|
|
do {
|
|
let results = try CoreDataManager.shared.context.fetch(request)
|
|
guard let account = results.first else {
|
|
return nil
|
|
}
|
|
|
|
return account
|
|
} catch {
|
|
print("\(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
static func remoteAccountByID(id: String, completion: @escaping (AccountMO?, Error?) -> Void ) {
|
|
if let account = accountByID(id) {
|
|
completion(account, nil)
|
|
return
|
|
}
|
|
|
|
guard let client = AuthenticationManager.shared.mkClient else {
|
|
completion(nil, NSError())
|
|
return
|
|
}
|
|
|
|
let request = Accounts.account(id: id)
|
|
|
|
client.run(request) { result in
|
|
switch result {
|
|
case .success(let account, _):
|
|
completion(upsertAccount(account), nil)
|
|
return
|
|
case .failure(let error):
|
|
completion(nil, error)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|