mirror of
https://github.com/metabolist/metatext.git
synced 2025-01-05 11:38:40 +00:00
Featured tags data
This commit is contained in:
parent
2eddf8c558
commit
a51d9aafae
13 changed files with 142 additions and 3 deletions
|
@ -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(
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
25
DB/Sources/DB/Content/FeaturedTagRecord.swift
Normal file
25
DB/Sources/DB/Content/FeaturedTagRecord.swift
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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> {
|
||||||
|
|
|
@ -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:))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
DB/Sources/DB/Extensions/FeaturedTag+Extensions.swift
Normal file
16
DB/Sources/DB/Extensions/FeaturedTag+Extensions.swift
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
23
Mastodon/Sources/Mastodon/Entities/FeaturedTag.swift
Normal file
23
Mastodon/Sources/Mastodon/Entities/FeaturedTag.swift
Normal 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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -103,7 +103,6 @@ public extension EmojiPickerService {
|
||||||
promise(.failure(error))
|
promise(.failure(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.print()
|
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
Loading…
Reference in a new issue