Whalebird-desktop-client-ma.../src/renderer/store/TimelineSpace/Contents/SideBar/AccountProfile.ts

277 lines
10 KiB
TypeScript

import generator, { Entity } from 'megalodon'
import Timeline, { TimelineState } from './AccountProfile/Timeline'
import Follows, { FollowsState } from './AccountProfile/Follows'
import Followers, { FollowersState } from './AccountProfile/Followers'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store'
type ParsedAccount = {
username: string
acct: string
url: string
}
type SearchAccount = {
parsedAccount: ParsedAccount
status: Entity.Status
}
export type AccountProfileState = {
account: Entity.Account | null
relationship: Entity.Relationship | null
loading: boolean
identityProofs: Array<Entity.IdentityProof>
}
type AccountProfileModule = {
Followers: FollowersState
Follows: FollowsState
Timeline: TimelineState
}
export type AccountProfileModuleState = AccountProfileModule & AccountProfileState
const state = (): AccountProfileState => ({
account: null,
relationship: null,
loading: false,
identityProofs: []
})
export const MUTATION_TYPES = {
CHANGE_ACCOUNT: 'changeAccount',
CHANGE_RELATIONSHIP: 'changeRelationship',
CHANGE_LOADING: 'changeLoading',
CHANGE_IDENTITY_PROOFS: 'changeIdentityProofs'
}
const mutations: MutationTree<AccountProfileState> = {
[MUTATION_TYPES.CHANGE_ACCOUNT]: (state, account: Entity.Account | null) => {
state.account = account
},
[MUTATION_TYPES.CHANGE_RELATIONSHIP]: (state, relationship: Entity.Relationship | null) => {
state.relationship = relationship
},
[MUTATION_TYPES.CHANGE_LOADING]: (state, value: boolean) => {
state.loading = value
},
[MUTATION_TYPES.CHANGE_IDENTITY_PROOFS]: (state, values: Array<Entity.IdentityProof>) => {
state.identityProofs = values
}
}
const actions: ActionTree<AccountProfileState, RootState> = {
fetchAccount: async ({ rootState, dispatch }, accountID: string): Promise<Entity.Account> => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.getAccount(accountID)
dispatch('identityProofs', res.data)
return res.data
},
searchAccount: async ({ rootState }, searchAccount: SearchAccount): Promise<Entity.Account> => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
// Find account in toot
if (searchAccount.status.in_reply_to_account_id) {
const res = await client.getAccount(searchAccount.status.in_reply_to_account_id)
if (res.status === 200) {
const user = accountMatch([res.data], searchAccount.parsedAccount, rootState.TimelineSpace.account.domain)
if (user) return user
}
}
// Find account in context
if (searchAccount.status.in_reply_to_id) {
const res = await client.getStatusContext(searchAccount.status.id)
if (res.status === 200) {
const accounts: Array<Entity.Account> = res.data.ancestors.map(s => s.account).concat(res.data.descendants.map(s => s.account))
const user = accountMatch(accounts, searchAccount.parsedAccount, rootState.TimelineSpace.account.domain)
if (user) return user
}
}
// Search account name
const res = await client.searchAccount(searchAccount.parsedAccount.url, { resolve: true })
if (res.data.length <= 0) throw new AccountNotFound('empty result')
const user = accountMatch(res.data, searchAccount.parsedAccount, rootState.TimelineSpace.account.domain)
if (!user) throw new AccountNotFound('not found')
return user
},
changeAccount: ({ commit, dispatch }, account: Entity.Account) => {
dispatch('fetchRelationship', account)
dispatch('identityProofs', account)
commit(MUTATION_TYPES.CHANGE_ACCOUNT, account)
},
fetchRelationship: async ({ commit, rootState }, account: Entity.Account): Promise<Entity.Relationship> => {
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, null)
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.getRelationship(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
},
reload: async ({ dispatch, state, commit }) => {
commit(MUTATION_TYPES.CHANGE_LOADING, true)
Promise.all([
dispatch('fetchRelationship', state.account),
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Timeline/Posts/fetchTimeline', state.account, { root: true }),
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Timeline/PostsAndReplies/fetchTimeline', state.account, { root: true }),
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Timeline/Media/fetchTimeline', state.account, { root: true }),
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Followers/fetchFollowers', state.account, { root: true }),
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Follows/fetchFollows', state.account, { root: true })
]).finally(() => {
commit(MUTATION_TYPES.CHANGE_LOADING, false)
})
},
follow: async ({ commit, rootState, dispatch }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.followAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
dispatch('fetchRelationship', account)
return res.data
},
unfollow: async ({ commit, rootState, dispatch }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.unfollowAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
dispatch('fetchRelationship', account)
return res.data
},
close: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_ACCOUNT, null)
},
unmute: async ({ rootState, commit, dispatch }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.unmuteAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
dispatch('fetchRelationship', account)
return res.data
},
block: async ({ rootState, commit, dispatch }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.blockAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
dispatch('fetchRelationship', account)
return res.data
},
unblock: async ({ rootState, commit, dispatch }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.unblockAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
dispatch('fetchRelationship', account)
return res.data
},
identityProofs: async ({ rootState, commit }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.getIdentityProof(account.id)
commit(MUTATION_TYPES.CHANGE_IDENTITY_PROOFS, res.data)
},
subscribe: async ({ rootState, commit }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.subscribeAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
},
unsubscribe: async ({ rootState, commit }, account: Entity.Account) => {
const client = generator(
rootState.TimelineSpace.sns,
rootState.TimelineSpace.account.baseURL,
rootState.TimelineSpace.account.accessToken,
rootState.App.userAgent
)
const res = await client.unsubscribeAccount(account.id)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
}
}
const getters: GetterTree<AccountProfileState, RootState> = {
isOwnProfile: (state, _getters, rootState) => {
if (!state.account) {
return false
}
const own = rootState.TimelineSpace.account
// For Mastodon
if (`${own.baseURL}/@${own.username}` === state.account.url) {
return true
}
// For Pleroma
return `${own.baseURL}/users/${own.username}` === state.account.url
}
}
const AccountProfile: Module<AccountProfileState, RootState> = {
namespaced: true,
modules: {
Follows,
Followers,
Timeline
},
state: state,
mutations: mutations,
actions: actions,
getters: getters
}
class AccountNotFound extends Error {}
export default AccountProfile
const accountMatch = (findAccounts: Array<Entity.Account>, parsedAccount: ParsedAccount, domain: string): Entity.Account | false => {
const account = findAccounts.find(a => `@${a.acct}` === parsedAccount.acct)
if (account) return account
const pleromaUser = findAccounts.find(a => a.acct === parsedAccount.acct)
if (pleromaUser) return pleromaUser
const localUser = findAccounts.find(a => `@${a.username}@${domain}` === parsedAccount.acct)
if (localUser) return localUser
const user = findAccounts.find(a => a.url === parsedAccount.url)
if (!user) return false
return user
}