Featured tags data

This commit is contained in:
Justin Mazzocchi 2021-01-17 23:17:45 -08:00
parent 2eddf8c558
commit a51d9aafae
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
13 changed files with 142 additions and 3 deletions

View file

@ -56,6 +56,7 @@ extension AccountRecord {
static let moved = belongsTo(AccountRecord.self) static let moved = belongsTo(AccountRecord.self)
static let relationship = hasOne(Relationship.self) static let relationship = hasOne(Relationship.self)
static let identityProofs = hasMany(IdentityProofRecord.self) static let identityProofs = hasMany(IdentityProofRecord.self)
static let featuredTags = hasMany(FeaturedTagRecord.self)
static let pinnedStatusJoins = hasMany(AccountPinnedStatusJoin.self) static let pinnedStatusJoins = hasMany(AccountPinnedStatusJoin.self)
.order(AccountPinnedStatusJoin.Columns.index) .order(AccountPinnedStatusJoin.Columns.index)
static let pinnedStatuses = hasMany( static let pinnedStatuses = hasMany(

View file

@ -57,6 +57,15 @@ extension ContentDatabase {
t.primaryKey(["accountId", "provider"], onConflict: .replace) t.primaryKey(["accountId", "provider"], onConflict: .replace)
} }
try db.create(table: "featuredTagRecord") { t in
t.column("id", .text).primaryKey(onConflict: .replace)
t.column("name", .text).notNull()
t.column("url", .text).notNull()
t.column("statusesCount", .integer).notNull()
t.column("lastStatusAt", .date).notNull()
t.column("accountId", .text).notNull().references("accountRecord", onDelete: .cascade)
}
try db.create(table: "statusRecord") { t in try db.create(table: "statusRecord") { t in
t.column("id", .text).primaryKey(onConflict: .replace) t.column("id", .text).primaryKey(onConflict: .replace)
t.column("uri", .text).notNull() t.column("uri", .text).notNull()

View file

@ -284,6 +284,23 @@ public extension ContentDatabase {
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
func insert(featuredTags: [FeaturedTag], id: Account.Id) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
for featuredTag in featuredTags {
try FeaturedTagRecord(
id: featuredTag.id,
name: featuredTag.name,
url: featuredTag.url,
statusesCount: featuredTag.statusesCount,
lastStatusAt: featuredTag.lastStatusAt,
accountId: id)
.save($0)
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
func insert(relationships: [Relationship]) -> AnyPublisher<Never, Error> { func insert(relationships: [Relationship]) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher { databaseWriter.writePublisher {
for relationship in relationships { for relationship in relationships {

View file

@ -0,0 +1,25 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
import GRDB
import Mastodon
struct FeaturedTagRecord: ContentDatabaseRecord, Hashable {
let id: FeaturedTag.Id
let name: String
let url: URL
let statusesCount: Int
let lastStatusAt: Date
let accountId: Account.Id
}
extension FeaturedTagRecord {
enum Columns {
static let id = Column(CodingKeys.id)
static let name = Column(CodingKeys.name)
static let url = Column(CodingKeys.url)
static let statusesCount = Column(CodingKeys.statusesCount)
static let lastStatusAt = Column(CodingKeys.lastStatusAt)
static let accountId = Column(CodingKeys.accountId)
}
}

View file

@ -8,6 +8,7 @@ struct ProfileInfo: Codable, Hashable, FetchableRecord {
let accountInfo: AccountInfo let accountInfo: AccountInfo
let relationship: Relationship? let relationship: Relationship?
let identityProofRecords: [IdentityProofRecord] let identityProofRecords: [IdentityProofRecord]
let featuredTagRecords: [FeaturedTagRecord]
} }
extension ProfileInfo { extension ProfileInfo {
@ -15,6 +16,7 @@ extension ProfileInfo {
AccountInfo.addingIncludes(request) AccountInfo.addingIncludes(request)
.including(optional: AccountRecord.relationship.forKey(CodingKeys.relationship)) .including(optional: AccountRecord.relationship.forKey(CodingKeys.relationship))
.including(all: AccountRecord.identityProofs.forKey(CodingKeys.identityProofRecords)) .including(all: AccountRecord.identityProofs.forKey(CodingKeys.identityProofRecords))
.including(all: AccountRecord.featuredTags.forKey(CodingKeys.featuredTagRecords))
} }
static func request(_ request: QueryInterfaceRequest<AccountRecord>) -> QueryInterfaceRequest<Self> { static func request(_ request: QueryInterfaceRequest<AccountRecord>) -> QueryInterfaceRequest<Self> {

View file

@ -7,11 +7,13 @@ public struct Profile: Codable, Hashable {
public let account: Account public let account: Account
public let relationship: Relationship? public let relationship: Relationship?
public let identityProofs: [IdentityProof] public let identityProofs: [IdentityProof]
public let featuredTags: [FeaturedTag]
public init(account: Account) { public init(account: Account) {
self.account = account self.account = account
self.relationship = nil self.relationship = nil
self.identityProofs = [] self.identityProofs = []
self.featuredTags = []
} }
} }
@ -20,5 +22,6 @@ extension Profile {
account = Account(info: info.accountInfo) account = Account(info: info.accountInfo)
relationship = info.relationship relationship = info.relationship
identityProofs = info.identityProofRecords.map(IdentityProof.init(record:)) identityProofs = info.identityProofRecords.map(IdentityProof.init(record:))
featuredTags = info.featuredTagRecords.map(FeaturedTag.init(record:))
} }
} }

View file

@ -0,0 +1,16 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
import GRDB
import Mastodon
extension FeaturedTag {
init(record: FeaturedTagRecord) {
self.init(
id: record.id,
name: record.name,
url: record.url,
statusesCount: record.statusesCount,
lastStatusAt: record.lastStatusAt)
}
}

View file

@ -0,0 +1,23 @@
// Copyright © 2021 Metabolist. All rights reserved.
import Foundation
public struct FeaturedTag: Codable, Hashable {
public let id: Id
public let name: String
public let url: URL
public let statusesCount: Int
public let lastStatusAt: Date
public init(id: FeaturedTag.Id, name: String, url: URL, statusesCount: Int, lastStatusAt: Date) {
self.id = id
self.name = name
self.url = url
self.statusesCount = statusesCount
self.lastStatusAt = lastStatusAt
}
}
public extension FeaturedTag {
typealias Id = String
}

View file

@ -0,0 +1,35 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
import HTTP
import Mastodon
public enum FeaturedTagsEndpoint {
case featuredTags(id: Account.Id)
}
extension FeaturedTagsEndpoint: Endpoint {
public typealias ResultType = [FeaturedTag]
public var context: [String] {
switch self {
case .featuredTags:
return defaultContext + ["accounts"]
}
}
public var pathComponentsInContext: [String] {
switch self {
case let .featuredTags(id):
return [id, "featured_tags"]
}
}
public var method: HTTPMethod {
switch self {
case .featuredTags:
return .get
}
}
}

View file

@ -10,6 +10,7 @@ public struct AccountService {
public let account: Account public let account: Account
public let relationship: Relationship? public let relationship: Relationship?
public let identityProofs: [IdentityProof] public let identityProofs: [IdentityProof]
public let featuredTags: [FeaturedTag]
public let navigationService: NavigationService public let navigationService: NavigationService
private let mastodonAPIClient: MastodonAPIClient private let mastodonAPIClient: MastodonAPIClient
@ -18,11 +19,13 @@ public struct AccountService {
public init(account: Account, public init(account: Account,
relationship: Relationship? = nil, relationship: Relationship? = nil,
identityProofs: [IdentityProof] = [], identityProofs: [IdentityProof] = [],
featuredTags: [FeaturedTag] = [],
mastodonAPIClient: MastodonAPIClient, mastodonAPIClient: MastodonAPIClient,
contentDatabase: ContentDatabase) { contentDatabase: ContentDatabase) {
self.account = account self.account = account
self.relationship = relationship self.relationship = relationship
self.identityProofs = identityProofs self.identityProofs = identityProofs
self.featuredTags = featuredTags
navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase) navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
self.mastodonAPIClient = mastodonAPIClient self.mastodonAPIClient = mastodonAPIClient
self.contentDatabase = contentDatabase self.contentDatabase = contentDatabase

View file

@ -103,7 +103,6 @@ public extension EmojiPickerService {
promise(.failure(error)) promise(.failure(error))
} }
} }
.print()
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }

View file

@ -49,6 +49,7 @@ public struct ProfileService {
account: $0.account, account: $0.account,
relationship: $0.relationship, relationship: $0.relationship,
identityProofs: $0.identityProofs, identityProofs: $0.identityProofs,
featuredTags: $0.featuredTags,
mastodonAPIClient: mastodonAPIClient, mastodonAPIClient: mastodonAPIClient,
contentDatabase: contentDatabase) contentDatabase: contentDatabase)
} }
@ -65,14 +66,17 @@ public extension ProfileService {
} }
func fetchProfile() -> AnyPublisher<Never, Error> { func fetchProfile() -> AnyPublisher<Never, Error> {
Publishers.Merge3( Publishers.Merge4(
mastodonAPIClient.request(AccountEndpoint.accounts(id: id)) mastodonAPIClient.request(AccountEndpoint.accounts(id: id))
.flatMap { contentDatabase.insert(accounts: [$0]) }, .flatMap { contentDatabase.insert(accounts: [$0]) },
mastodonAPIClient.request(RelationshipsEndpoint.relationships(ids: [id])) mastodonAPIClient.request(RelationshipsEndpoint.relationships(ids: [id]))
.flatMap { contentDatabase.insert(relationships: $0) }, .flatMap { contentDatabase.insert(relationships: $0) },
mastodonAPIClient.request(IdentityProofsEndpoint.identityProofs(id: id)) mastodonAPIClient.request(IdentityProofsEndpoint.identityProofs(id: id))
.catch { _ in Empty() } .catch { _ in Empty() }
.flatMap { contentDatabase.insert(identityProofs: $0, id: id) }) .flatMap { contentDatabase.insert(identityProofs: $0, id: id) },
mastodonAPIClient.request(FeaturedTagsEndpoint.featuredTags(id: id))
.catch { _ in Empty() }
.flatMap { contentDatabase.insert(featuredTags: $0, id: id) })
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }

View file

@ -44,6 +44,8 @@ public extension AccountViewModel {
var identityProofs: [IdentityProof] { accountService.identityProofs } var identityProofs: [IdentityProof] { accountService.identityProofs }
var featuredTags: [FeaturedTag] { accountService.featuredTags }
var fields: [Account.Field] { accountService.account.fields } var fields: [Account.Field] { accountService.account.fields }
var note: NSAttributedString { accountService.account.note.attributed } var note: NSAttributedString { accountService.account.note.attributed }