Merge branch 'develop' into 'fix-move-type-notification'
# Conflicts: # static/fontello.json
This commit is contained in:
commit
215662afde
54 changed files with 1548 additions and 982 deletions
|
@ -1,4 +1,4 @@
|
|||
import { each, map, concat, last } from 'lodash'
|
||||
import { each, map, concat, last, get } from 'lodash'
|
||||
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
|
||||
import 'whatwg-fetch'
|
||||
import { RegistrationError, StatusCodeError } from '../errors/errors'
|
||||
|
@ -12,7 +12,8 @@ const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
|
|||
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
||||
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
|
||||
const ACTIVATION_STATUS_URL = screenName => `/api/pleroma/admin/users/${screenName}/activation_status`
|
||||
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
|
||||
const DEACTIVATE_USER_URL = '/api/pleroma/admin/users/deactivate'
|
||||
const ADMIN_USERS_URL = '/api/pleroma/admin/users'
|
||||
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
||||
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
||||
|
@ -22,7 +23,7 @@ const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
|
|||
|
||||
const MFA_SETUP_OTP_URL = '/api/pleroma/accounts/mfa/setup/totp'
|
||||
const MFA_CONFIRM_OTP_URL = '/api/pleroma/accounts/mfa/confirm/totp'
|
||||
const MFA_DISABLE_OTP_URL = '/api/pleroma/account/mfa/totp'
|
||||
const MFA_DISABLE_OTP_URL = '/api/pleroma/accounts/mfa/totp'
|
||||
|
||||
const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
|
||||
const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
|
||||
|
@ -71,6 +72,7 @@ const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
|
|||
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
||||
const MASTODON_SEARCH_2 = `/api/v2/search`
|
||||
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
||||
const MASTODON_STREAMING = '/api/v1/streaming'
|
||||
|
||||
const oldfetch = window.fetch
|
||||
|
||||
|
@ -450,20 +452,26 @@ const deleteRight = ({ right, credentials, ...user }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const setActivationStatus = ({ status, credentials, ...user }) => {
|
||||
const screenName = user.screen_name
|
||||
const body = {
|
||||
status: status
|
||||
}
|
||||
const activateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||
return promisedRequest({
|
||||
url: ACTIVATE_USER_URL,
|
||||
method: 'PATCH',
|
||||
credentials,
|
||||
payload: {
|
||||
nicknames: [nickname]
|
||||
}
|
||||
}).then(response => get(response, 'users.0'))
|
||||
}
|
||||
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(ACTIVATION_STATUS_URL(screenName), {
|
||||
method: 'PUT',
|
||||
headers: headers,
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
const deactivateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||
return promisedRequest({
|
||||
url: DEACTIVATE_USER_URL,
|
||||
method: 'PATCH',
|
||||
credentials,
|
||||
payload: {
|
||||
nicknames: [nickname]
|
||||
}
|
||||
}).then(response => get(response, 'users.0'))
|
||||
}
|
||||
|
||||
const deleteUser = ({ credentials, ...user }) => {
|
||||
|
@ -529,16 +537,24 @@ const fetchTimeline = ({
|
|||
|
||||
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
||||
url += `?${queryString}`
|
||||
|
||||
let status = ''
|
||||
let statusText = ''
|
||||
return fetch(url, { headers: authHeaders(credentials) })
|
||||
.then((data) => {
|
||||
if (data.ok) {
|
||||
return data
|
||||
}
|
||||
throw new Error('Error fetching timeline', data)
|
||||
status = data.status
|
||||
statusText = data.statusText
|
||||
return data
|
||||
})
|
||||
.then((data) => data.json())
|
||||
.then((data) => data.map(isNotifications ? parseNotification : parseStatus))
|
||||
.then((data) => {
|
||||
if (!data.error) {
|
||||
return data.map(isNotifications ? parseNotification : parseStatus)
|
||||
} else {
|
||||
data.status = status
|
||||
data.statusText = statusText
|
||||
return data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const fetchPinnedStatuses = ({ id, credentials }) => {
|
||||
|
@ -932,6 +948,99 @@ const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
|
||||
return Object.entries({
|
||||
...(credentials
|
||||
? { access_token: credentials }
|
||||
: {}
|
||||
),
|
||||
stream,
|
||||
...args
|
||||
}).reduce((acc, [key, val]) => {
|
||||
return acc + `${key}=${val}&`
|
||||
}, MASTODON_STREAMING + '?')
|
||||
}
|
||||
|
||||
const MASTODON_STREAMING_EVENTS = new Set([
|
||||
'update',
|
||||
'notification',
|
||||
'delete',
|
||||
'filters_changed'
|
||||
])
|
||||
|
||||
// A thin wrapper around WebSocket API that allows adding a pre-processor to it
|
||||
// Uses EventTarget and a CustomEvent to proxy events
|
||||
export const ProcessedWS = ({
|
||||
url,
|
||||
preprocessor = handleMastoWS,
|
||||
id = 'Unknown'
|
||||
}) => {
|
||||
const eventTarget = new EventTarget()
|
||||
const socket = new WebSocket(url)
|
||||
if (!socket) throw new Error(`Failed to create socket ${id}`)
|
||||
const proxy = (original, eventName, processor = a => a) => {
|
||||
original.addEventListener(eventName, (eventData) => {
|
||||
eventTarget.dispatchEvent(new CustomEvent(
|
||||
eventName,
|
||||
{ detail: processor(eventData) }
|
||||
))
|
||||
})
|
||||
}
|
||||
socket.addEventListener('open', (wsEvent) => {
|
||||
console.debug(`[WS][${id}] Socket connected`, wsEvent)
|
||||
})
|
||||
socket.addEventListener('error', (wsEvent) => {
|
||||
console.debug(`[WS][${id}] Socket errored`, wsEvent)
|
||||
})
|
||||
socket.addEventListener('close', (wsEvent) => {
|
||||
console.debug(
|
||||
`[WS][${id}] Socket disconnected with code ${wsEvent.code}`,
|
||||
wsEvent
|
||||
)
|
||||
})
|
||||
// Commented code reason: very spammy, uncomment to enable message debug logging
|
||||
/*
|
||||
socket.addEventListener('message', (wsEvent) => {
|
||||
console.debug(
|
||||
`[WS][${id}] Message received`,
|
||||
wsEvent
|
||||
)
|
||||
})
|
||||
/**/
|
||||
|
||||
proxy(socket, 'open')
|
||||
proxy(socket, 'close')
|
||||
proxy(socket, 'message', preprocessor)
|
||||
proxy(socket, 'error')
|
||||
|
||||
// 1000 = Normal Closure
|
||||
eventTarget.close = () => { socket.close(1000, 'Shutting down socket') }
|
||||
|
||||
return eventTarget
|
||||
}
|
||||
|
||||
export const handleMastoWS = (wsEvent) => {
|
||||
const { data } = wsEvent
|
||||
if (!data) return
|
||||
const parsedEvent = JSON.parse(data)
|
||||
const { event, payload } = parsedEvent
|
||||
if (MASTODON_STREAMING_EVENTS.has(event)) {
|
||||
// MastoBE and PleromaBE both send payload for delete as a PLAIN string
|
||||
if (event === 'delete') {
|
||||
return { event, id: payload }
|
||||
}
|
||||
const data = payload ? JSON.parse(payload) : null
|
||||
if (event === 'update') {
|
||||
return { event, status: parseStatus(data) }
|
||||
} else if (event === 'notification') {
|
||||
return { event, notification: parseNotification(data) }
|
||||
}
|
||||
} else {
|
||||
console.warn('Unknown event', wsEvent)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const apiService = {
|
||||
verifyCredentials,
|
||||
fetchTimeline,
|
||||
|
@ -971,7 +1080,8 @@ const apiService = {
|
|||
deleteUser,
|
||||
addRight,
|
||||
deleteRight,
|
||||
setActivationStatus,
|
||||
activateUser,
|
||||
deactivateUser,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
|
|
|
@ -1,230 +1,39 @@
|
|||
import apiService from '../api/api.service.js'
|
||||
import apiService, { getMastodonSocketURI, ProcessedWS } from '../api/api.service.js'
|
||||
import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js'
|
||||
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
|
||||
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
||||
|
||||
const backendInteractorService = credentials => {
|
||||
const fetchStatus = ({ id }) => {
|
||||
return apiService.fetchStatus({ id, credentials })
|
||||
}
|
||||
|
||||
const fetchConversation = ({ id }) => {
|
||||
return apiService.fetchConversation({ id, credentials })
|
||||
}
|
||||
|
||||
const fetchFriends = ({ id, maxId, sinceId, limit }) => {
|
||||
return apiService.fetchFriends({ id, maxId, sinceId, limit, credentials })
|
||||
}
|
||||
|
||||
const exportFriends = ({ id }) => {
|
||||
return apiService.exportFriends({ id, credentials })
|
||||
}
|
||||
|
||||
const fetchFollowers = ({ id, maxId, sinceId, limit }) => {
|
||||
return apiService.fetchFollowers({ id, maxId, sinceId, limit, credentials })
|
||||
}
|
||||
|
||||
const fetchUser = ({ id }) => {
|
||||
return apiService.fetchUser({ id, credentials })
|
||||
}
|
||||
|
||||
const fetchUserRelationship = ({ id }) => {
|
||||
return apiService.fetchUserRelationship({ id, credentials })
|
||||
}
|
||||
|
||||
const followUser = ({ id, reblogs }) => {
|
||||
return apiService.followUser({ credentials, id, reblogs })
|
||||
}
|
||||
|
||||
const unfollowUser = (id) => {
|
||||
return apiService.unfollowUser({ credentials, id })
|
||||
}
|
||||
|
||||
const blockUser = (id) => {
|
||||
return apiService.blockUser({ credentials, id })
|
||||
}
|
||||
|
||||
const unblockUser = (id) => {
|
||||
return apiService.unblockUser({ credentials, id })
|
||||
}
|
||||
|
||||
const approveUser = (id) => {
|
||||
return apiService.approveUser({ credentials, id })
|
||||
}
|
||||
|
||||
const denyUser = (id) => {
|
||||
return apiService.denyUser({ credentials, id })
|
||||
}
|
||||
|
||||
const startFetchingTimeline = ({ timeline, store, userId = false, tag }) => {
|
||||
const backendInteractorService = credentials => ({
|
||||
startFetchingTimeline ({ timeline, store, userId = false, tag }) {
|
||||
return timelineFetcherService.startFetching({ timeline, store, credentials, userId, tag })
|
||||
}
|
||||
},
|
||||
|
||||
const startFetchingNotifications = ({ store }) => {
|
||||
startFetchingNotifications ({ store }) {
|
||||
return notificationsFetcher.startFetching({ store, credentials })
|
||||
}
|
||||
},
|
||||
|
||||
const startFetchingFollowRequest = ({ store }) => {
|
||||
fetchAndUpdateNotifications ({ store }) {
|
||||
return notificationsFetcher.fetchAndUpdate({ store, credentials })
|
||||
},
|
||||
|
||||
startFetchingFollowRequest ({ store }) {
|
||||
return followRequestFetcher.startFetching({ store, credentials })
|
||||
}
|
||||
},
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const tagUser = ({ screen_name }, tag) => {
|
||||
return apiService.tagUser({ screen_name, tag, credentials })
|
||||
}
|
||||
startUserSocket ({ store }) {
|
||||
const serv = store.rootState.instance.server.replace('http', 'ws')
|
||||
const url = serv + getMastodonSocketURI({ credentials, stream: 'user' })
|
||||
return ProcessedWS({ url, id: 'User' })
|
||||
},
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const untagUser = ({ screen_name }, tag) => {
|
||||
return apiService.untagUser({ screen_name, tag, credentials })
|
||||
}
|
||||
...Object.entries(apiService).reduce((acc, [key, func]) => {
|
||||
return {
|
||||
...acc,
|
||||
[key]: (args) => func({ credentials, ...args })
|
||||
}
|
||||
}, {}),
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const addRight = ({ screen_name }, right) => {
|
||||
return apiService.addRight({ screen_name, right, credentials })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const deleteRight = ({ screen_name }, right) => {
|
||||
return apiService.deleteRight({ screen_name, right, credentials })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const setActivationStatus = ({ screen_name }, status) => {
|
||||
return apiService.setActivationStatus({ screen_name, status, credentials })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const deleteUser = ({ screen_name }) => {
|
||||
return apiService.deleteUser({ screen_name, credentials })
|
||||
}
|
||||
|
||||
const vote = (pollId, choices) => {
|
||||
return apiService.vote({ credentials, pollId, choices })
|
||||
}
|
||||
|
||||
const fetchPoll = (pollId) => {
|
||||
return apiService.fetchPoll({ credentials, pollId })
|
||||
}
|
||||
|
||||
const updateNotificationSettings = ({ settings }) => {
|
||||
return apiService.updateNotificationSettings({ credentials, settings })
|
||||
}
|
||||
|
||||
const fetchMutes = () => apiService.fetchMutes({ credentials })
|
||||
const muteUser = (id) => apiService.muteUser({ credentials, id })
|
||||
const unmuteUser = (id) => apiService.unmuteUser({ credentials, id })
|
||||
const subscribeUser = (id) => apiService.subscribeUser({ credentials, id })
|
||||
const unsubscribeUser = (id) => apiService.unsubscribeUser({ credentials, id })
|
||||
const fetchBlocks = () => apiService.fetchBlocks({ credentials })
|
||||
const fetchOAuthTokens = () => apiService.fetchOAuthTokens({ credentials })
|
||||
const revokeOAuthToken = (id) => apiService.revokeOAuthToken({ id, credentials })
|
||||
const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({ credentials, id })
|
||||
const pinOwnStatus = (id) => apiService.pinOwnStatus({ credentials, id })
|
||||
const unpinOwnStatus = (id) => apiService.unpinOwnStatus({ credentials, id })
|
||||
const muteConversation = (id) => apiService.muteConversation({ credentials, id })
|
||||
const unmuteConversation = (id) => apiService.unmuteConversation({ credentials, id })
|
||||
|
||||
const getCaptcha = () => apiService.getCaptcha()
|
||||
const register = (params) => apiService.register({ credentials, params })
|
||||
const updateAvatar = ({ avatar }) => apiService.updateAvatar({ credentials, avatar })
|
||||
const updateBg = ({ background }) => apiService.updateBg({ credentials, background })
|
||||
const updateBanner = ({ banner }) => apiService.updateBanner({ credentials, banner })
|
||||
const updateProfile = ({ params }) => apiService.updateProfile({ credentials, params })
|
||||
|
||||
const importBlocks = (file) => apiService.importBlocks({ file, credentials })
|
||||
const importFollows = (file) => apiService.importFollows({ file, credentials })
|
||||
|
||||
const deleteAccount = ({ password }) => apiService.deleteAccount({ credentials, password })
|
||||
const changeEmail = ({ email, password }) => apiService.changeEmail({ credentials, email, password })
|
||||
const changePassword = ({ password, newPassword, newPasswordConfirmation }) =>
|
||||
apiService.changePassword({ credentials, password, newPassword, newPasswordConfirmation })
|
||||
|
||||
const fetchSettingsMFA = () => apiService.settingsMFA({ credentials })
|
||||
const generateMfaBackupCodes = () => apiService.generateMfaBackupCodes({ credentials })
|
||||
const mfaSetupOTP = () => apiService.mfaSetupOTP({ credentials })
|
||||
const mfaConfirmOTP = ({ password, token }) => apiService.mfaConfirmOTP({ credentials, password, token })
|
||||
const mfaDisableOTP = ({ password }) => apiService.mfaDisableOTP({ credentials, password })
|
||||
|
||||
const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({ id })
|
||||
const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({ id })
|
||||
const reportUser = (params) => apiService.reportUser({ credentials, ...params })
|
||||
|
||||
const favorite = (id) => apiService.favorite({ id, credentials })
|
||||
const unfavorite = (id) => apiService.unfavorite({ id, credentials })
|
||||
const retweet = (id) => apiService.retweet({ id, credentials })
|
||||
const unretweet = (id) => apiService.unretweet({ id, credentials })
|
||||
const search2 = ({ q, resolve, limit, offset, following }) =>
|
||||
apiService.search2({ credentials, q, resolve, limit, offset, following })
|
||||
const searchUsers = (query) => apiService.searchUsers({ query, credentials })
|
||||
|
||||
const backendInteractorServiceInstance = {
|
||||
fetchStatus,
|
||||
fetchConversation,
|
||||
fetchFriends,
|
||||
exportFriends,
|
||||
fetchFollowers,
|
||||
followUser,
|
||||
unfollowUser,
|
||||
blockUser,
|
||||
unblockUser,
|
||||
fetchUser,
|
||||
fetchUserRelationship,
|
||||
verifyCredentials: apiService.verifyCredentials,
|
||||
startFetchingTimeline,
|
||||
startFetchingNotifications,
|
||||
startFetchingFollowRequest,
|
||||
fetchMutes,
|
||||
muteUser,
|
||||
unmuteUser,
|
||||
subscribeUser,
|
||||
unsubscribeUser,
|
||||
fetchBlocks,
|
||||
fetchOAuthTokens,
|
||||
revokeOAuthToken,
|
||||
fetchPinnedStatuses,
|
||||
pinOwnStatus,
|
||||
unpinOwnStatus,
|
||||
muteConversation,
|
||||
unmuteConversation,
|
||||
tagUser,
|
||||
untagUser,
|
||||
addRight,
|
||||
deleteRight,
|
||||
deleteUser,
|
||||
setActivationStatus,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
updateBg,
|
||||
updateBanner,
|
||||
updateProfile,
|
||||
importBlocks,
|
||||
importFollows,
|
||||
deleteAccount,
|
||||
changeEmail,
|
||||
changePassword,
|
||||
fetchSettingsMFA,
|
||||
generateMfaBackupCodes,
|
||||
mfaSetupOTP,
|
||||
mfaConfirmOTP,
|
||||
mfaDisableOTP,
|
||||
approveUser,
|
||||
denyUser,
|
||||
vote,
|
||||
fetchPoll,
|
||||
fetchFavoritedByUsers,
|
||||
fetchRebloggedByUsers,
|
||||
reportUser,
|
||||
favorite,
|
||||
unfavorite,
|
||||
retweet,
|
||||
unretweet,
|
||||
updateNotificationSettings,
|
||||
search2,
|
||||
searchUsers
|
||||
}
|
||||
|
||||
return backendInteractorServiceInstance
|
||||
}
|
||||
verifyCredentials: apiService.verifyCredentials
|
||||
})
|
||||
|
||||
export default backendInteractorService
|
||||
|
|
|
@ -39,7 +39,7 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
|
|||
})
|
||||
|
||||
export const requestUnfollow = (user, store) => new Promise((resolve, reject) => {
|
||||
store.state.api.backendInteractor.unfollowUser(user.id)
|
||||
store.state.api.backendInteractor.unfollowUser({ id: user.id })
|
||||
.then((updated) => {
|
||||
store.commit('updateUserRelationship', [updated])
|
||||
resolve({
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
|
||||
const verifyOTPCode = ({ clientId, clientSecret, instance, mfaToken, code }) => {
|
||||
const url = `${instance}/oauth/mfa/challenge`
|
||||
const form = new window.FormData()
|
||||
|
||||
form.append('client_id', app.client_id)
|
||||
form.append('client_secret', app.client_secret)
|
||||
form.append('client_id', clientId)
|
||||
form.append('client_secret', clientSecret)
|
||||
form.append('mfa_token', mfaToken)
|
||||
form.append('code', code)
|
||||
form.append('challenge_type', 'totp')
|
||||
|
@ -14,12 +14,12 @@ const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
|
|||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const verifyRecoveryCode = ({ app, instance, mfaToken, code }) => {
|
||||
const verifyRecoveryCode = ({ clientId, clientSecret, instance, mfaToken, code }) => {
|
||||
const url = `${instance}/oauth/mfa/challenge`
|
||||
const form = new window.FormData()
|
||||
|
||||
form.append('client_id', app.client_id)
|
||||
form.append('client_secret', app.client_secret)
|
||||
form.append('client_id', clientId)
|
||||
form.append('client_secret', clientSecret)
|
||||
form.append('mfa_token', mfaToken)
|
||||
form.append('code', code)
|
||||
form.append('challenge_type', 'recovery')
|
||||
|
|
|
@ -12,7 +12,7 @@ export const getOrCreateApp = ({ clientId, clientSecret, instance, commit }) =>
|
|||
|
||||
form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`)
|
||||
form.append('redirect_uris', REDIRECT_URI)
|
||||
form.append('scopes', 'read write follow')
|
||||
form.append('scopes', 'read write follow push admin')
|
||||
|
||||
return window.fetch(url, {
|
||||
method: 'POST',
|
||||
|
@ -28,7 +28,7 @@ const login = ({ instance, clientId }) => {
|
|||
response_type: 'code',
|
||||
client_id: clientId,
|
||||
redirect_uri: REDIRECT_URI,
|
||||
scope: 'read write follow'
|
||||
scope: 'read write follow push admin'
|
||||
}
|
||||
|
||||
const dataString = reduce(data, (acc, v, k) => {
|
||||
|
|
|
@ -6,6 +6,7 @@ const update = ({ store, statuses, timeline, showImmediately, userId }) => {
|
|||
const ccTimeline = camelCase(timeline)
|
||||
|
||||
store.dispatch('setError', { value: false })
|
||||
store.dispatch('setErrorData', { value: null })
|
||||
|
||||
store.dispatch('addNewStatuses', {
|
||||
timeline: ccTimeline,
|
||||
|
@ -45,6 +46,10 @@ const fetchAndUpdate = ({
|
|||
|
||||
return apiService.fetchTimeline(args)
|
||||
.then((statuses) => {
|
||||
if (statuses.error) {
|
||||
store.dispatch('setErrorData', { value: statuses })
|
||||
return
|
||||
}
|
||||
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
|
||||
store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId })
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue