787 lines
23 KiB
JavaScript
787 lines
23 KiB
JavaScript
import Cookies from 'js-cookie'
|
|
import { last } from 'lodash'
|
|
import { defineStore } from 'pinia'
|
|
|
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
|
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
|
|
import { useChatsStore } from 'src/stores/chats.js'
|
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
|
import { useInstanceStore } from 'src/stores/instance.js'
|
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
|
import { useListsStore } from 'src/stores/lists.js'
|
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
|
import { useStreamingStore } from 'src/stores/streaming.js'
|
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
|
import { useTimelinesStore } from 'src/stores/timelines.js'
|
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
|
|
|
import { revokeToken } from 'src/api/oauth.js'
|
|
import {
|
|
fetchFollowers,
|
|
fetchFriends,
|
|
fetchUser,
|
|
fetchUserByName,
|
|
verifyCredentials,
|
|
} from 'src/api/public.js'
|
|
import {
|
|
blockUser,
|
|
editUserNote,
|
|
fetchBlocks,
|
|
fetchDomainMutes,
|
|
fetchMutes,
|
|
fetchUserInLists,
|
|
fetchUserRelationship,
|
|
followUser,
|
|
muteDomain,
|
|
muteUser,
|
|
removeUserFromFollowers,
|
|
unblockUser,
|
|
unfollowUser,
|
|
unmuteDomain,
|
|
unmuteUser,
|
|
} from 'src/api/user.js'
|
|
import { WSConnectionStatus } from 'src/api/websocket.js'
|
|
import { promiseInterval } from 'src/services/promise_interval/promise_interval.js'
|
|
|
|
export const useUsersStore = defineStore('users', {
|
|
state: () => ({
|
|
loggingIn: false,
|
|
currentUser: null,
|
|
users: new Map(),
|
|
usersByName: new Map(),
|
|
usersByURL: new Map(),
|
|
relationships: new Map(),
|
|
relationshipsLists: {
|
|
friends: new WeakMap(),
|
|
followers: new WeakMap(),
|
|
},
|
|
timestamps: new WeakMap(),
|
|
fetchesIds: new Map(),
|
|
fetchesNames: new Map(),
|
|
followPollers: new Map(),
|
|
followPollersAttempts: new Map(),
|
|
}),
|
|
getters: {
|
|
loggedIn: (state) => !!state.currentUser,
|
|
findUser: (state) => (query) => {
|
|
return state.users.get(query)
|
|
},
|
|
findUserByName: (state) => (query) => {
|
|
return state.usersByName.get(query.toLowerCase())
|
|
},
|
|
findUserByUrl: (state) => (query) => {
|
|
return state.usersByURL.get(query.toLowerCase())
|
|
},
|
|
relationship: (state) => (id) => {
|
|
const rel = id && state.relationships.get(id)
|
|
return rel || { id, loading: true }
|
|
},
|
|
},
|
|
actions: {
|
|
// Main updates
|
|
addNewUsers(response) {
|
|
const { data, timestamp } = response
|
|
const users = Array.isArray(data) ? data : [data]
|
|
|
|
return users.map((user) => {
|
|
const existing = this.users.get(user.id) ?? {}
|
|
const oldTimestamp = this.timestamps.get(existing)
|
|
//
|
|
// Relationship might have different timestamp and
|
|
// might need updating separate from user
|
|
const oldRelationship = this.relationships.get(user.id)
|
|
const oldRelationshipTimestamp = this.timestamps.get(oldRelationship)
|
|
let relationship
|
|
|
|
// Only need an update if new user data has relationship
|
|
if (user.relationship) {
|
|
// Only update if there is no old data or if it's outdated
|
|
if (
|
|
oldRelationship === undefined ||
|
|
timestamp > oldRelationshipTimestamp
|
|
) {
|
|
relationship = this.updateUserRelationships({
|
|
timestamp,
|
|
data: { id: user.id, ...user.relationship },
|
|
})[0]
|
|
}
|
|
} else {
|
|
relationship = oldRelationship
|
|
}
|
|
|
|
// implicit: if oldTimestamp is undefined this will still be false
|
|
if (oldTimestamp > timestamp) return existing // not overwriting old data with new
|
|
|
|
const { relationship: unused1, ...newUser } = user
|
|
|
|
let reactive = this.users.get(user.id)
|
|
// Initializing reactivity & avoiding excessive Map mutation
|
|
if (!reactive) {
|
|
this.users.set(user.id, existing)
|
|
|
|
reactive = this.users.get(user.id)
|
|
this.usersByName.set(user.screen_name.toLowerCase(), reactive)
|
|
this.usersByURL.set(user.url.toLowerCase(), reactive)
|
|
}
|
|
|
|
// Relying on object reactivity to avoid mutating the Map
|
|
reactive.relationship = relationship ?? reactive.relationship
|
|
|
|
Object.entries(newUser).forEach(([k, v]) => {
|
|
reactive[k] = v
|
|
})
|
|
|
|
// Updating the timestamp
|
|
this.timestamps.set(reactive, timestamp)
|
|
|
|
if (user.id === this.currentUser?.id) {
|
|
this.currentUser = reactive
|
|
}
|
|
|
|
// Initialize some stuff
|
|
const { friends, followers } = this.relationshipsLists
|
|
if (!friends.has(reactive)) friends.set(reactive, new Set())
|
|
if (!followers.has(reactive)) followers.set(reactive, new Set())
|
|
|
|
return reactive
|
|
})
|
|
},
|
|
updateUserRelationships({ timestamp, optimism, data }) {
|
|
const relationships = Array.isArray(data) ? data : [data]
|
|
|
|
return relationships.map((relationship) => {
|
|
const { id } = relationship
|
|
const existing = this.relationships.get(id) ?? {}
|
|
const oldTimestamp = this.timestamps.get(existing)
|
|
|
|
// implicit: if oldTimestamp is undefined this will still be false
|
|
if (!optimism && oldTimestamp > timestamp) return existing
|
|
|
|
// Initializing reactivity
|
|
if (!this.relationships.has(id)) this.relationships.set(id, existing)
|
|
const reactive = this.relationships.get(id)
|
|
|
|
// Relying on reactivity
|
|
Object.entries(relationship).forEach(([k, v]) => {
|
|
reactive[k] = v
|
|
})
|
|
|
|
if (timestamp) {
|
|
this.timestamps.set(reactive, timestamp)
|
|
}
|
|
|
|
// Updating user property if there is such a user
|
|
if (this.users.has(id)) {
|
|
this.users.get(id).relationship = reactive
|
|
}
|
|
|
|
// Update block/mute lists
|
|
if (this.currentUser && id !== this.currentUser.id) {
|
|
;[
|
|
['muting', this.currentUser.muteIds],
|
|
['blocking', this.currentUser.blockIds],
|
|
[
|
|
'following',
|
|
this.relationshipsLists.friends.get(this.currentUser),
|
|
],
|
|
[
|
|
'followed_by',
|
|
this.relationshipsLists.followers.get(this.currentUser),
|
|
],
|
|
].forEach(([relationshipName, list]) => {
|
|
if (relationship[relationshipName]) {
|
|
list?.add(id)
|
|
} else {
|
|
list?.delete(id)
|
|
}
|
|
})
|
|
}
|
|
|
|
return reactive
|
|
})
|
|
},
|
|
|
|
// Misc updates
|
|
updateUserAdminData(id, data) {
|
|
const user = this.users.get(id)
|
|
|
|
user.adminData = data
|
|
user.deactivated = !data.is_active
|
|
user.tags = new Set(data.tags)
|
|
},
|
|
updateRight(id, right, value) {
|
|
const user = this.users.get(id)
|
|
const newRights = user.rights ?? {}
|
|
newRights[right] = value
|
|
user.rights = newRights
|
|
},
|
|
|
|
// Because frontend doesn't have a reason to keep these stuff in memory
|
|
// outside of viewing someones user profile.
|
|
clearFollowLists(userId) {
|
|
const user = this.users.get(userId)
|
|
if (user) {
|
|
this.relationshipsLists.friends.set(user, new Set())
|
|
this.relationshipsLists.followers.set(user, new Set())
|
|
}
|
|
},
|
|
|
|
// Fetches
|
|
async fetchUserIfMissing({ id, name }) {
|
|
let findFunc
|
|
let fetchFunc
|
|
let map
|
|
let identifier
|
|
|
|
if (id) {
|
|
findFunc = this.findUser
|
|
fetchFunc = this.fetchUser
|
|
map = this.fetchesIds
|
|
identifier = id
|
|
} else if (name) {
|
|
findFunc = this.findUserByName
|
|
fetchFunc = this.fetchUserByName
|
|
map = this.fetchesNames
|
|
identifier = name
|
|
} else {
|
|
throw new TypeError('No identifier provided')
|
|
}
|
|
|
|
// Search in cache
|
|
const user = findFunc(identifier)
|
|
|
|
if (user) return user
|
|
// not found => fetch
|
|
let promise
|
|
|
|
// Did we already search for this user?
|
|
if (map.has(identifier)) {
|
|
// if so, reuse the promise
|
|
promise = map.get(identifier)
|
|
} else {
|
|
// if not, make a new one
|
|
promise = fetchFunc(identifier)
|
|
}
|
|
|
|
map.set(identifier, promise)
|
|
|
|
const result = await promise
|
|
|
|
if (result) {
|
|
const { id, screen_name } = result
|
|
|
|
// Save promise for future use
|
|
this.fetchesIds.set(id, promise)
|
|
this.fetchesNames.set(screen_name, promise)
|
|
return this.users.get(id)
|
|
} else {
|
|
return null
|
|
}
|
|
},
|
|
async fetchUser(id) {
|
|
try {
|
|
const result = await fetchUser({
|
|
id,
|
|
credentials: useOAuthStore().token,
|
|
})
|
|
|
|
this.addNewUsers(result)
|
|
|
|
return this.users.get(result.data.id)
|
|
} catch (error) {
|
|
if (error.name === 'StatusCodeError' && error.statusCode === 404) {
|
|
console.warn(`User ${id} not found`)
|
|
return null
|
|
} else {
|
|
throw error
|
|
}
|
|
}
|
|
},
|
|
async fetchUserByName(name) {
|
|
try {
|
|
const result = await fetchUserByName({
|
|
name,
|
|
credentials: useOAuthStore().token,
|
|
})
|
|
|
|
this.addNewUsers(result)
|
|
|
|
return this.users.get(result.data.id)
|
|
} catch (error) {
|
|
if (error.name === 'StatusCodeError' && error.statusCode === 404) {
|
|
console.warn(`User ${name} not found`)
|
|
return null
|
|
} else {
|
|
throw error
|
|
}
|
|
}
|
|
},
|
|
fetchUserRelationship(id) {
|
|
return fetchUserRelationship({
|
|
id,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
},
|
|
fetchFriends(id) {
|
|
const user = this.users.get(id)
|
|
const maxId = last([...this.relationshipsLists.friends.get(user)])
|
|
return fetchFriends({
|
|
id,
|
|
maxId,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => {
|
|
const users = this.addNewUsers(result)
|
|
const list = this.relationshipsLists.friends.get(user)
|
|
users.forEach(({ id }) => list.add(id))
|
|
return result.data
|
|
})
|
|
},
|
|
fetchFollowers(id) {
|
|
const user = this.users.get(id)
|
|
const maxId = last([...this.relationshipsLists.followers.get(user)])
|
|
return fetchFollowers({
|
|
id,
|
|
maxId,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => {
|
|
const users = this.addNewUsers(result)
|
|
const list = this.relationshipsLists.followers.get(user)
|
|
users.forEach(({ id }) => list.add(id))
|
|
return result.data
|
|
})
|
|
},
|
|
fetchUserInLists(id) {
|
|
if (this.currentUser) {
|
|
return fetchUserInLists({
|
|
id,
|
|
credentials: useOAuthStore().token,
|
|
}).then(({ data: inLists }) => {
|
|
this.users.get(id).inLists = inLists
|
|
})
|
|
}
|
|
},
|
|
fetchMutes(args) {
|
|
const { reset } = args || {}
|
|
|
|
const maxId = this.currentUser.muteIdsMaxId
|
|
return fetchMutes({
|
|
maxId,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => {
|
|
const { data: mutes } = result
|
|
if (reset) {
|
|
this.currentUser.muteIds = new Set(mutes.map(({ id }) => id))
|
|
} else {
|
|
mutes.forEach(({ id }) => this.currentUser.muteIds.add(id))
|
|
}
|
|
if (mutes.length) {
|
|
this.currentUser.muteIdsMaxId = last(mutes).id
|
|
}
|
|
this.addNewUsers(result)
|
|
return mutes
|
|
})
|
|
},
|
|
fetchBlocks(args) {
|
|
const { reset } = args || {}
|
|
|
|
const maxId = this.currentUser.blockIdsMaxId
|
|
return fetchBlocks({
|
|
maxId,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => {
|
|
const { data: blocks } = result
|
|
if (reset) {
|
|
this.currentUser.blockIds = new Set(blocks.map(({ id }) => id))
|
|
} else {
|
|
blocks.forEach(({ id }) => this.currentUser.blockIds.add(id))
|
|
}
|
|
if (blocks.length) {
|
|
this.currentUser.blockIdsMaxId = last(blocks).id
|
|
}
|
|
this.addNewUsers(result)
|
|
return blocks
|
|
})
|
|
},
|
|
fetchDomainMutes() {
|
|
return fetchDomainMutes({
|
|
credentials: useOAuthStore().token,
|
|
}).then(({ data: domainMutes }) => {
|
|
this.currentUser.domainMutes = new Set(domainMutes)
|
|
return domainMutes
|
|
})
|
|
},
|
|
|
|
// Actions
|
|
/// Follow
|
|
async followUser(id) {
|
|
// Don't spam follow requests if we are already polling
|
|
if (this.followPollers.has(id)) return
|
|
|
|
const followFunc = () =>
|
|
followUser({
|
|
id,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
|
|
const checker = async (func = () => this.fetchUserRelationship(id)) => {
|
|
await func() // Either fetch relationships or follow request
|
|
const relationship = this.relationships.get(id)
|
|
|
|
return (
|
|
relationship.following ||
|
|
(relationship.locked && relationship.requested)
|
|
)
|
|
}
|
|
|
|
const immediate = await checker(followFunc)
|
|
if (immediate) return // If follow goes through immediately don'd to looping
|
|
|
|
const loop = async () => {
|
|
const attempts = this.followPollersAttempts.get(id)
|
|
const result = await checker()
|
|
|
|
if (result || attempts === 1) {
|
|
this.followPollersAttempts.delete(id)
|
|
this.followPollers.get(id).stop()
|
|
this.followPollers.delete(id)
|
|
} else {
|
|
this.followPollersAttempts.set(id, attempts - 1)
|
|
}
|
|
}
|
|
|
|
this.followPollersAttempts.set(id, 3)
|
|
this.followPollers.set(id, promiseInterval(loop, 500))
|
|
},
|
|
async unfollowUser(id) {
|
|
const result = await unfollowUser({
|
|
id,
|
|
credentials: useOAuthStore().token,
|
|
})
|
|
|
|
return this.updateUserRelationships(result)
|
|
},
|
|
|
|
/// Subscribe
|
|
subscribeUser(id) {
|
|
return followUser({
|
|
id,
|
|
notify: true,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
},
|
|
unsubscribeUser(id) {
|
|
return followUser({
|
|
id,
|
|
notify: false,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
},
|
|
|
|
/// User Note
|
|
editUserNote(id, comment) {
|
|
return editUserNote({ id, comment }).then((result) =>
|
|
this.updateUserRelationships(result),
|
|
)
|
|
},
|
|
|
|
/// Hide reblogs
|
|
hideReblogs(id) {
|
|
return followUser({
|
|
id,
|
|
reblogs: false,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
},
|
|
showReblogs(id) {
|
|
return followUser({
|
|
id,
|
|
reblogs: true,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => this.updateUserRelationships(result))
|
|
},
|
|
|
|
/// Remove follower
|
|
removeUserFromFollowers(id) {
|
|
return removeUserFromFollowers({ id }).then((result) =>
|
|
this.updateUserRelationships(result),
|
|
)
|
|
},
|
|
|
|
/// Mute
|
|
muteUser(id, expiresIn = 0) {
|
|
const predictedRelationship = this.relationships[id] || { id }
|
|
predictedRelationship.muting = true
|
|
this.updateUserRelationships({
|
|
optimism: true,
|
|
data: [predictedRelationship],
|
|
})
|
|
|
|
return muteUser({
|
|
id,
|
|
expiresIn,
|
|
credentials: useOAuthStore().token,
|
|
}).then((result) => {
|
|
this.updateUserRelationships(result)
|
|
})
|
|
},
|
|
muteUsers(data = []) {
|
|
return Promise.all(data.map((d) => this.muteUser(d)))
|
|
},
|
|
unmuteUser(id) {
|
|
const predictedRelationship = this.relationships[id] || { id }
|
|
predictedRelationship.muting = false
|
|
this.updateUserRelationships({
|
|
optimism: true,
|
|
data: [predictedRelationship],
|
|
})
|
|
|
|
return unmuteUser({ id }).then((result) =>
|
|
this.updateUserRelationships(result),
|
|
)
|
|
},
|
|
unmuteUsers(ids = []) {
|
|
return Promise.all(ids.map((d) => this.unmuteUser(d)))
|
|
},
|
|
|
|
/// Block
|
|
blockUser(id, expiresIn = 0) {
|
|
const predictedRelationship = this.relationships[id] || { id }
|
|
this.updateUserRelationships({
|
|
optimism: true,
|
|
data: [predictedRelationship],
|
|
})
|
|
|
|
return blockUser({ id, expiresIn }).then((result) => {
|
|
this.updateUserRelationships(result)
|
|
|
|
const ids = useStatusesStore().wipeUserStatuses(id)
|
|
useTimelinesStore().wipeStatuses(ids)
|
|
useNotificationsStore().wipeStatuses(ids)
|
|
})
|
|
},
|
|
blockUsers(data = []) {
|
|
return Promise.all(data.map((d) => this.blockUser(d)))
|
|
},
|
|
unblockUser(id) {
|
|
return unblockUser({ id }).then((result) => {
|
|
this.updateUserRelationships(result)
|
|
})
|
|
},
|
|
unblockUsers(data = []) {
|
|
return Promise.all(data.map((d) => this.unblockUser(d)))
|
|
},
|
|
|
|
/// Domain Mute
|
|
muteDomain(domain) {
|
|
return muteDomain({
|
|
domain,
|
|
credentials: useOAuthStore().token,
|
|
}).then(() => this.currentUser.domainMutes.add(domain))
|
|
},
|
|
unmuteDomain(domain) {
|
|
return unmuteDomain({
|
|
domain,
|
|
credentials: useOAuthStore().token,
|
|
}).then(() => this.currentUser.domainMutes.delete(domain))
|
|
},
|
|
muteDomains(domains = []) {
|
|
return Promise.all(domains.map((domain) => this.muteDomain(domain)))
|
|
},
|
|
unmuteDomains(domain = []) {
|
|
return Promise.all(domain.map((domain) => this.unmuteDomain(domain)))
|
|
},
|
|
|
|
// Login/Logout
|
|
async loginUser(accessToken) {
|
|
const store = window.vuex
|
|
const dispatch =
|
|
store?.dispatch ??
|
|
(() => {
|
|
/* no-op */
|
|
}) // for tests
|
|
|
|
this.loggingIn = true
|
|
|
|
try {
|
|
const { data: user, ...rest } = await verifyCredentials({
|
|
credentials: useOAuthStore().token,
|
|
})
|
|
|
|
user.blockIds = new Set()
|
|
user.muteIds = new Set()
|
|
user.domainMutes = new Set()
|
|
|
|
useTimelinesStore().deactivateAll()
|
|
useStatusesStore().resetStatuses()
|
|
|
|
this.users = new Map()
|
|
this.usersByName = new Map()
|
|
this.usersByURL = new Map()
|
|
this.relationships = new Map()
|
|
this.currentUser = user
|
|
this.addNewUsers({ data: user, ...rest })
|
|
|
|
useInterfaceStore().onLogin()
|
|
useSyncConfigStore()
|
|
.initSyncConfig(user)
|
|
.then(() => {
|
|
useInterfaceStore()
|
|
.applyTheme()
|
|
.catch((e) => {
|
|
console.error('Error setting theme', e)
|
|
})
|
|
})
|
|
|
|
useUserHighlightStore().initUserHighlight(user)
|
|
|
|
useEmojiStore().fetchEmoji()
|
|
|
|
// Do server-side storage migrations
|
|
|
|
// Debug snippet to clean up storage and reset migrations
|
|
/*
|
|
// Reset wordfilter
|
|
Object.keys(
|
|
useSyncConfigStore().prefsStorage.simple.muteFilters
|
|
).forEach(key => {
|
|
useSyncConfigStore().unsetSimplePrefAndSave({ path: 'muteFilters.' + key, value: null })
|
|
})
|
|
|
|
// Reset flag to 0 to re-run migrations
|
|
useSyncConfigStore().setFlag({ flag: 'configMigration', value: 0 })
|
|
/**/
|
|
|
|
if (user.token) {
|
|
// Shoutbox
|
|
dispatch('setWsToken', user.token)
|
|
dispatch('initializeSocket')
|
|
}
|
|
|
|
// DMs and Home
|
|
useTimelinesStore().activatePersistents()
|
|
useNotificationsStore().activate()
|
|
|
|
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
|
|
// Start fetching chats
|
|
useChatsStore().startFetching()
|
|
}
|
|
|
|
useListsStore().startFetching()
|
|
useBookmarkFoldersStore().startFetching()
|
|
|
|
if (user.locked) {
|
|
dispatch('startFetchingFollowRequests')
|
|
}
|
|
|
|
if (useMergedConfigStore().mergedConfig.useStreamingApi) {
|
|
useStreamingStore().initSocket(true)
|
|
}
|
|
|
|
// Start fetching things that don't need to block the UI
|
|
useAnnouncementsStore().startFetching()
|
|
|
|
this.fetchMutes()
|
|
dispatch('loadDrafts')
|
|
} catch (error) {
|
|
console.error(error)
|
|
|
|
// Authentication failed
|
|
this.loggingIn = false
|
|
|
|
// remove authentication token on client/authentication errors
|
|
if ([400, 401, 403, 422].includes(error.statusCode)) {
|
|
useOAuthStore().clearToken()
|
|
}
|
|
|
|
if (error.tatusCode === 401) {
|
|
throw new Error('Wrong username or password', error)
|
|
} else {
|
|
throw new Error('An error occurred, please try again', error)
|
|
}
|
|
} finally {
|
|
this.loggingIn = false
|
|
}
|
|
},
|
|
logout() {
|
|
const store = window.vuex
|
|
const oauth = useOAuthStore()
|
|
|
|
// Pause fetching
|
|
useNotificationsStore().pause()
|
|
useTimelinesStore().pauseAll()
|
|
|
|
// Pause-less stores
|
|
useAnnouncementsStore().stopFetching()
|
|
useListsStore().stopFetching()
|
|
useBookmarkFoldersStore().stopFetching()
|
|
store?.dispatch('stopFetchingFollowRequests')
|
|
|
|
// NOTE: No need to verify the app still exists, because if it doesn't,
|
|
// the token will be invalid too
|
|
return oauth
|
|
.ensureApp()
|
|
.then((app) => {
|
|
const params = {
|
|
app,
|
|
instance: useInstanceStore().server,
|
|
token: oauth.userToken,
|
|
}
|
|
|
|
return revokeToken(params)
|
|
})
|
|
.then(() => {
|
|
oauth.clearToken()
|
|
|
|
this.currentUser = null
|
|
|
|
useNotificationsStore().deactivate()
|
|
|
|
// Full reset on logout success
|
|
useTimelinesStore().deactivateAll()
|
|
useStatusesStore().resetStatuses()
|
|
useChatsStore().stopFetching()
|
|
useChatsStore().resetChats()
|
|
|
|
this.users = new Map()
|
|
this.usersByName = new Map()
|
|
this.usersByURL = new Map()
|
|
this.relationships = new Map()
|
|
|
|
// Socket is most likely already closed by server
|
|
if (
|
|
useMergedConfigStore().mergedConfig.useStreamingApi &&
|
|
useStreamingStore().state !== WSConnectionStatus.CLOSED
|
|
) {
|
|
useStreamingStore().stopSocket()
|
|
}
|
|
|
|
Cookies.remove('__Host-pleroma_key', { path: '/' })
|
|
useInterfaceStore().onLogout()
|
|
})
|
|
.catch((e) => {
|
|
useInterfaceStore().pushGlobalNotice({
|
|
messageKey: 'user.logout_failure',
|
|
messageArgs: {
|
|
error: e,
|
|
},
|
|
level: 'error',
|
|
})
|
|
console.error('Logout error!', e)
|
|
|
|
useAnnouncementsStore().startFetching()
|
|
useListsStore().startFetching()
|
|
useBookmarkFoldersStore().startFetching()
|
|
useChatsStore().startFetching()
|
|
store?.dispatch('startFetchingFollowRequests')
|
|
})
|
|
.finally(() => {
|
|
useNotificationsStore().resume()
|
|
useTimelinesStore().resumeAll()
|
|
})
|
|
},
|
|
},
|
|
})
|