diff options
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/api.js | 21 | ||||
| -rw-r--r-- | src/modules/auth_flow.js | 90 | ||||
| -rw-r--r-- | src/modules/chat.js | 12 | ||||
| -rw-r--r-- | src/modules/config.js | 36 | ||||
| -rw-r--r-- | src/modules/errors.js | 1 | ||||
| -rw-r--r-- | src/modules/instance.js | 27 | ||||
| -rw-r--r-- | src/modules/oauth.js | 45 | ||||
| -rw-r--r-- | src/modules/oauth_tokens.js | 4 | ||||
| -rw-r--r-- | src/modules/polls.js | 70 | ||||
| -rw-r--r-- | src/modules/postStatus.js | 25 | ||||
| -rw-r--r-- | src/modules/statuses.js | 86 | ||||
| -rw-r--r-- | src/modules/users.js | 135 |
12 files changed, 440 insertions, 112 deletions
diff --git a/src/modules/api.js b/src/modules/api.js index 7ed3edac..eb6a7980 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -6,7 +6,6 @@ const api = { backendInteractor: backendInteractorService(), fetchers: {}, socket: null, - chatDisabled: false, followRequests: [] }, mutations: { @@ -25,9 +24,6 @@ const api = { setSocket (state, socket) { state.socket = socket }, - setChatDisabled (state, value) { - state.chatDisabled = value - }, setFollowRequests (state, value) { state.followRequests = value } @@ -55,17 +51,20 @@ const api = { setWsToken (store, token) { store.commit('setWsToken', token) }, - initializeSocket (store) { + initializeSocket ({ dispatch, commit, state, rootState }) { // Set up websocket connection - if (!store.state.chatDisabled) { - const token = store.state.wsToken - const socket = new Socket('/socket', {params: {token}}) + const token = state.wsToken + if (rootState.instance.chatAvailable && typeof token !== 'undefined' && state.socket === null) { + const socket = new Socket('/socket', { params: { token } }) socket.connect() - store.dispatch('initializeChat', socket) + + commit('setSocket', socket) + dispatch('initializeChat', socket) } }, - disableChat (store) { - store.commit('setChatDisabled', true) + disconnectFromSocket ({ commit, state }) { + state.socket && state.socket.disconnect() + commit('setSocket', null) }, removeFollowRequest (store, request) { let requests = store.state.followRequests.filter((it) => it !== request) diff --git a/src/modules/auth_flow.js b/src/modules/auth_flow.js new file mode 100644 index 00000000..d0a90feb --- /dev/null +++ b/src/modules/auth_flow.js @@ -0,0 +1,90 @@ +const PASSWORD_STRATEGY = 'password' +const TOKEN_STRATEGY = 'token' + +// MFA strategies +const TOTP_STRATEGY = 'totp' +const RECOVERY_STRATEGY = 'recovery' + +// initial state +const state = { + app: null, + settings: {}, + strategy: PASSWORD_STRATEGY, + initStrategy: PASSWORD_STRATEGY // default strategy from config +} + +const resetState = (state) => { + state.strategy = state.initStrategy + state.settings = {} + state.app = null +} + +// getters +const getters = { + app: (state, getters) => { + return state.app + }, + settings: (state, getters) => { + return state.settings + }, + requiredPassword: (state, getters, rootState) => { + return state.strategy === PASSWORD_STRATEGY + }, + requiredToken: (state, getters, rootState) => { + return state.strategy === TOKEN_STRATEGY + }, + requiredTOTP: (state, getters, rootState) => { + return state.strategy === TOTP_STRATEGY + }, + requiredRecovery: (state, getters, rootState) => { + return state.strategy === RECOVERY_STRATEGY + } +} + +// mutations +const mutations = { + setInitialStrategy (state, strategy) { + if (strategy) { + state.initStrategy = strategy + state.strategy = strategy + } + }, + requirePassword (state) { + state.strategy = PASSWORD_STRATEGY + }, + requireToken (state) { + state.strategy = TOKEN_STRATEGY + }, + requireMFA (state, { app, settings }) { + state.settings = settings + state.app = app + state.strategy = TOTP_STRATEGY // default strategy of MFA + }, + requireRecovery (state) { + state.strategy = RECOVERY_STRATEGY + }, + requireTOTP (state) { + state.strategy = TOTP_STRATEGY + }, + abortMFA (state) { + resetState(state) + } +} + +// actions +const actions = { + // eslint-disable-next-line camelcase + async login ({ state, dispatch, commit }, { access_token }) { + commit('setToken', access_token, { root: true }) + await dispatch('loginUser', access_token, { root: true }) + resetState(state) + } +} + +export default { + namespaced: true, + state, + getters, + mutations, + actions +} diff --git a/src/modules/chat.js b/src/modules/chat.js index 2804e577..c798549d 100644 --- a/src/modules/chat.js +++ b/src/modules/chat.js @@ -1,16 +1,12 @@ const chat = { state: { messages: [], - channel: {state: ''}, - socket: null + channel: { state: '' } }, mutations: { setChannel (state, channel) { state.channel = channel }, - setSocket (state, socket) { - state.socket = socket - }, addMessage (state, message) { state.messages.push(message) state.messages = state.messages.slice(-19, 20) @@ -20,16 +16,12 @@ const chat = { } }, actions: { - disconnectFromChat (store) { - store.state.socket.disconnect() - }, initializeChat (store, socket) { const channel = socket.channel('chat:public') - store.commit('setSocket', socket) channel.on('new_msg', (msg) => { store.commit('addMessage', msg) }) - channel.on('messages', ({messages}) => { + channel.on('messages', ({ messages }) => { store.commit('setMessages', messages) }) channel.join() diff --git a/src/modules/config.js b/src/modules/config.js index a8da525a..78314118 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -3,10 +3,12 @@ import { setPreset, applyTheme } from '../services/style_setter/style_setter.js' const browserLocale = (window.navigator.language || 'en').split('-')[0] -const defaultState = { +export const defaultState = { colors: {}, + // bad name: actually hides posts of muted USERS hideMutedPosts: undefined, // instance default collapseMessageWithSubject: undefined, // instance default + padEmoji: true, hideAttachments: false, hideAttachmentsInConv: false, maxThumbnails: 16, @@ -36,11 +38,37 @@ const defaultState = { subjectLineBehavior: undefined, // instance default alwaysShowSubjectInput: undefined, // instance default postContentType: undefined, // instance default - minimalScopesMode: undefined // instance default + minimalScopesMode: undefined, // instance default + // This hides statuses filtered via a word filter + hideFilteredStatuses: undefined, // instance default + playVideosInModal: false, + useOneClickNsfw: false, + useContainFit: false, + hidePostStats: undefined, // instance default + hideUserStats: undefined // instance default } +// caching the instance default properties +export const instanceDefaultProperties = Object.entries(defaultState) + .filter(([key, value]) => value === undefined) + .map(([key, value]) => key) + const config = { state: defaultState, + getters: { + mergedConfig (state, getters, rootState, rootGetters) { + const { instance } = rootState + return { + ...state, + ...instanceDefaultProperties + .map(key => [key, state[key] === undefined + ? instance[key] + : state[key] + ]) + .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) + } + } + }, mutations: { setOption (state, { name, value }) { set(state, name, value) @@ -56,10 +84,10 @@ const config = { }, actions: { setHighlight ({ commit, dispatch }, { user, color, type }) { - commit('setHighlight', {user, color, type}) + commit('setHighlight', { user, color, type }) }, setOption ({ commit, dispatch }, { name, value }) { - commit('setOption', {name, value}) + commit('setOption', { name, value }) switch (name) { case 'theme': setPreset(value, commit) diff --git a/src/modules/errors.js b/src/modules/errors.js index c809e1b5..ca89dc0f 100644 --- a/src/modules/errors.js +++ b/src/modules/errors.js @@ -9,4 +9,3 @@ export function humanizeErrors (errors) { return [...errs, message] }, []) } - diff --git a/src/modules/instance.js b/src/modules/instance.js index d4185f6a..0c1235ca 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -1,5 +1,6 @@ import { set } from 'vue' import { setPreset } from '../services/style_setter/style_setter.js' +import { instanceDefaultProperties } from './config.js' const defaultState = { // Stuff from static/config.json and apiConfig @@ -16,7 +17,6 @@ const defaultState = { redirectRootNoLogin: '/main/all', redirectRootLogin: '/main/friends', showInstanceSpecificPanel: false, - formattingOptionsEnabled: false, alwaysShowSubjectInput: true, hideMutedPosts: false, collapseMessageWithSubject: false, @@ -27,7 +27,6 @@ const defaultState = { scopeCopy: true, subjectLineBehavior: 'email', postContentType: 'text/plain', - loginMethod: 'password', nsfwCensorImage: undefined, vapidPublicKey: undefined, noAttachmentLinks: false, @@ -54,7 +53,15 @@ const defaultState = { // Version Information backendVersion: '', - frontendVersion: '' + frontendVersion: '', + + pollsAvailable: false, + pollLimits: { + max_options: 4, + max_option_chars: 255, + min_expiration: 60, + max_expiration: 60 * 60 * 24 + } } const instance = { @@ -66,13 +73,25 @@ const instance = { } } }, + getters: { + instanceDefaultConfig (state) { + return instanceDefaultProperties + .map(key => [key, state[key]]) + .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) + } + }, actions: { setInstanceOption ({ commit, dispatch }, { name, value }) { - commit('setInstanceOption', {name, value}) + commit('setInstanceOption', { name, value }) switch (name) { case 'name': dispatch('setPageTitle') break + case 'chatAvailable': + if (value) { + dispatch('initializeSocket') + } + break } }, setTheme ({ commit }, themeName) { diff --git a/src/modules/oauth.js b/src/modules/oauth.js index 144ff830..a2a83450 100644 --- a/src/modules/oauth.js +++ b/src/modules/oauth.js @@ -1,16 +1,47 @@ +import { delete as del } from 'vue' + const oauth = { state: { - client_id: false, - client_secret: false, - token: false + clientId: false, + clientSecret: false, + /* App token is authentication for app without any user, used mostly for + * MastoAPI's registration of new users, stored so that we can fall back to + * it on logout + */ + appToken: false, + /* User token is authentication for app with user, this is for every calls + * that need authorized user to be successful (i.e. posting, liking etc) + */ + userToken: false }, mutations: { - setClientData (state, data) { - state.client_id = data.client_id - state.client_secret = data.client_secret + setClientData (state, { clientId, clientSecret }) { + state.clientId = clientId + state.clientSecret = clientSecret + }, + setAppToken (state, token) { + state.appToken = token }, setToken (state, token) { - state.token = token + state.userToken = token + }, + clearToken (state) { + state.userToken = false + // state.token is userToken with older name, coming from persistent state + // let's clear it as well, since it is being used as a fallback of state.userToken + del(state, 'token') + } + }, + getters: { + getToken: state => () => { + // state.token is userToken with older name, coming from persistent state + // added here for smoother transition, otherwise user will be logged out + return state.userToken || state.token || state.appToken + }, + getUserToken: state => () => { + // state.token is userToken with older name, coming from persistent state + // added here for smoother transition, otherwise user will be logged out + return state.userToken || state.token } } } diff --git a/src/modules/oauth_tokens.js b/src/modules/oauth_tokens.js index 00ac1431..0159a3f1 100644 --- a/src/modules/oauth_tokens.js +++ b/src/modules/oauth_tokens.js @@ -3,12 +3,12 @@ const oauthTokens = { tokens: [] }, actions: { - fetchTokens ({rootState, commit}) { + fetchTokens ({ rootState, commit }) { rootState.api.backendInteractor.fetchOAuthTokens().then((tokens) => { commit('swapTokens', tokens) }) }, - revokeToken ({rootState, commit, state}, id) { + revokeToken ({ rootState, commit, state }, id) { rootState.api.backendInteractor.revokeOAuthToken(id).then((response) => { if (response.status === 201) { commit('swapTokens', state.tokens.filter(token => token.id !== id)) diff --git a/src/modules/polls.js b/src/modules/polls.js new file mode 100644 index 00000000..e6158b63 --- /dev/null +++ b/src/modules/polls.js @@ -0,0 +1,70 @@ +import { merge } from 'lodash' +import { set } from 'vue' + +const polls = { + state: { + // Contains key = id, value = number of trackers for this poll + trackedPolls: {}, + pollsObject: {} + }, + mutations: { + mergeOrAddPoll (state, poll) { + const existingPoll = state.pollsObject[poll.id] + // Make expired-state change trigger re-renders properly + poll.expired = Date.now() > Date.parse(poll.expires_at) + if (existingPoll) { + set(state.pollsObject, poll.id, merge(existingPoll, poll)) + } else { + set(state.pollsObject, poll.id, poll) + } + }, + trackPoll (state, pollId) { + const currentValue = state.trackedPolls[pollId] + if (currentValue) { + set(state.trackedPolls, pollId, currentValue + 1) + } else { + set(state.trackedPolls, pollId, 1) + } + }, + untrackPoll (state, pollId) { + const currentValue = state.trackedPolls[pollId] + if (currentValue) { + set(state.trackedPolls, pollId, currentValue - 1) + } else { + set(state.trackedPolls, pollId, 0) + } + } + }, + actions: { + mergeOrAddPoll ({ commit }, poll) { + commit('mergeOrAddPoll', poll) + }, + updateTrackedPoll ({ rootState, dispatch, commit }, pollId) { + rootState.api.backendInteractor.fetchPoll(pollId).then(poll => { + setTimeout(() => { + if (rootState.polls.trackedPolls[pollId]) { + dispatch('updateTrackedPoll', pollId) + } + }, 30 * 1000) + commit('mergeOrAddPoll', poll) + }) + }, + trackPoll ({ rootState, commit, dispatch }, pollId) { + if (!rootState.polls.trackedPolls[pollId]) { + setTimeout(() => dispatch('updateTrackedPoll', pollId), 30 * 1000) + } + commit('trackPoll', pollId) + }, + untrackPoll ({ commit }, pollId) { + commit('untrackPoll', pollId) + }, + votePoll ({ rootState, commit }, { id, pollId, choices }) { + return rootState.api.backendInteractor.vote(pollId, choices).then(poll => { + commit('mergeOrAddPoll', poll) + return poll + }) + } + } +} + +export default polls diff --git a/src/modules/postStatus.js b/src/modules/postStatus.js new file mode 100644 index 00000000..638c1fb2 --- /dev/null +++ b/src/modules/postStatus.js @@ -0,0 +1,25 @@ +const postStatus = { + state: { + params: null, + modalActivated: false + }, + mutations: { + openPostStatusModal (state, params) { + state.params = params + state.modalActivated = true + }, + closePostStatusModal (state) { + state.modalActivated = false + } + }, + actions: { + openPostStatusModal ({ commit }, params) { + commit('openPostStatusModal', params) + }, + closePostStatusModal ({ commit }) { + commit('closePostStatusModal') + } + } +} + +export default postStatus diff --git a/src/modules/statuses.js b/src/modules/statuses.js index e6ee5447..f11ffdcd 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -80,13 +80,13 @@ const mergeOrAdd = (arr, obj, item) => { merge(oldItem, omitBy(item, (v, k) => v === null || k === 'user')) // Reactivity fix. oldItem.attachments.splice(oldItem.attachments.length) - return {item: oldItem, new: false} + return { item: oldItem, new: false } } else { // This is a new item, prepare it prepareStatus(item) arr.push(item) set(obj, item.id, item) - return {item, new: true} + return { item, new: true } } } @@ -137,7 +137,7 @@ const removeStatusFromGlobalStorage = (state, status) => { // TODO: Need to remove from allStatusesObject? // Remove possible notification - remove(state.notifications.data, ({action: {id}}) => id === status.id) + remove(state.notifications.data, ({ action: { id } }) => id === status.id) // Remove from conversation const conversationId = status.statusnet_conversation_id @@ -146,7 +146,8 @@ const removeStatusFromGlobalStorage = (state, status) => { } } -const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, noIdUpdate = false, userId }) => { +const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, + noIdUpdate = false, userId }) => { // Sanity check if (!isArray(statuses)) { return false @@ -269,7 +270,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us }, 'deletion': (deletion) => { const uri = deletion.uri - const status = find(allStatuses, {uri}) + const status = find(allStatuses, { uri }) if (!status) { return } @@ -394,8 +395,9 @@ export const mutations = { state[key] = value }) }, - clearTimeline (state, { timeline }) { - state.timelines[timeline] = emptyTl(state.timelines[timeline].userId) + clearTimeline (state, { timeline, excludeUserId = false }) { + const userId = excludeUserId ? state.timelines[timeline].userId : undefined + state.timelines[timeline] = emptyTl(userId) }, clearNotifications (state) { state.notifications = emptyNotifications() @@ -424,9 +426,13 @@ export const mutations = { newStatus.favoritedBy.push(user) } }, - setPinned (state, status) { + setMutedStatus (state, status) { const newStatus = state.allStatusesObject[status.id] - newStatus.pinned = status.pinned + newStatus.thread_muted = status.thread_muted + + if (newStatus.thread_muted !== undefined) { + state.conversationsObject[newStatus.statusnet_conversation_id].forEach(status => { status.thread_muted = newStatus.thread_muted }) + } }, setRetweeted (state, { status, value }) { const newStatus = state.allStatusesObject[status.id] @@ -490,10 +496,23 @@ export const mutations = { queueFlush (state, { timeline, id }) { state.timelines[timeline].flushMarker = id }, - addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers }) { + addRepeats (state, { id, rebloggedByUsers, currentUser }) { const newStatus = state.allStatusesObject[id] - newStatus.favoritedBy = favoritedByUsers.filter(_ => _) newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _) + // repeats stats can be incorrect based on polling condition, let's update them using the most recent data + newStatus.repeat_num = newStatus.rebloggedBy.length + newStatus.repeated = !!newStatus.rebloggedBy.find(({ id }) => currentUser.id === id) + }, + addFavs (state, { id, favoritedByUsers, currentUser }) { + const newStatus = state.allStatusesObject[id] + newStatus.favoritedBy = favoritedByUsers.filter(_ => _) + // favorites stats can be incorrect based on polling condition, let's update them using the most recent data + newStatus.fave_num = newStatus.favoritedBy.length + newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id) + }, + updateStatusWithPoll (state, { id, poll }) { + const status = state.allStatusesObject[id] + status.poll = poll } } @@ -518,6 +537,10 @@ const statuses = { setNotificationsSilence ({ rootState, commit }, { value }) { commit('setNotificationsSilence', { value }) }, + fetchStatus ({ rootState, dispatch }, id) { + rootState.api.backendInteractor.fetchStatus({ id }) + .then((status) => dispatch('addNewStatuses', { statuses: [status] })) + }, deleteStatus ({ rootState, commit }, status) { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) @@ -539,15 +562,23 @@ const statuses = { }, fetchPinnedStatuses ({ rootState, dispatch }, userId) { rootState.api.backendInteractor.fetchPinnedStatuses(userId) - .then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true })) + .then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true })) }, - pinStatus ({ rootState, commit }, statusId) { + pinStatus ({ rootState, dispatch }, statusId) { return rootState.api.backendInteractor.pinOwnStatus(statusId) - .then((status) => commit('setPinned', status)) + .then((status) => dispatch('addNewStatuses', { statuses: [status] })) }, - unpinStatus ({ rootState, commit }, statusId) { + unpinStatus ({ rootState, dispatch }, statusId) { rootState.api.backendInteractor.unpinOwnStatus(statusId) - .then((status) => commit('setPinned', status)) + .then((status) => dispatch('addNewStatuses', { statuses: [status] })) + }, + muteConversation ({ rootState, commit }, statusId) { + return rootState.api.backendInteractor.muteConversation(statusId) + .then((status) => commit('setMutedStatus', status)) + }, + unmuteConversation ({ rootState, commit }, statusId) { + return rootState.api.backendInteractor.unmuteConversation(statusId) + .then((status) => commit('setMutedStatus', status)) }, retweet ({ rootState, commit }, status) { // Optimistic retweeting... @@ -575,9 +606,26 @@ const statuses = { Promise.all([ rootState.api.backendInteractor.fetchFavoritedByUsers(id), rootState.api.backendInteractor.fetchRebloggedByUsers(id) - ]).then(([favoritedByUsers, rebloggedByUsers]) => - commit('addFavsAndRepeats', { id, favoritedByUsers, rebloggedByUsers }) - ) + ]).then(([favoritedByUsers, rebloggedByUsers]) => { + commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }) + commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }) + }) + }, + fetchFavs ({ rootState, commit }, id) { + rootState.api.backendInteractor.fetchFavoritedByUsers(id) + .then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })) + }, + fetchRepeats ({ rootState, commit }, id) { + rootState.api.backendInteractor.fetchRebloggedByUsers(id) + .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })) + }, + search (store, { q, resolve, limit, offset, following }) { + return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following }) + .then((data) => { + store.commit('addNewUsers', data.accounts) + store.commit('addNewStatuses', { statuses: data.statuses }) + return data + }) } }, mutations diff --git a/src/modules/users.js b/src/modules/users.js index e72a657c..6d259dc2 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -1,10 +1,8 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' -import userSearchApi from '../services/new_api/user_search.js' +import oauthApi from '../services/new_api/oauth.js' import { compact, map, each, merge, last, concat, uniq } from 'lodash' import { set } from 'vue' import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js' -import oauthApi from '../services/new_api/oauth' -import { humanizeErrors } from './errors' // TODO: Unify with mergeOrAdd in statuses.js export const mergeOrAdd = (arr, obj, item) => { @@ -62,6 +60,18 @@ const unmuteUser = (store, id) => { .then((relationship) => store.commit('updateUserRelationship', [relationship])) } +const hideReblogs = (store, userId) => { + return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: false }) + .then((relationship) => { + store.commit('updateUserRelationship', [relationship]) + }) +} + +const showReblogs = (store, userId) => { + return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: true }) + .then((relationship) => store.commit('updateUserRelationship', [relationship])) +} + export const mutations = { setMuted (state, { user: { id }, muted }) { const user = state.usersObject[id] @@ -136,6 +146,8 @@ export const mutations = { user.following = relationship.following user.muted = relationship.muting user.statusnet_blocking = relationship.blocking + user.subscribed = relationship.subscribing + user.showing_reblogs = relationship.showing_reblogs } }) }, @@ -165,13 +177,13 @@ export const mutations = { state.currentUser.muteIds.push(muteId) } }, - setPinned (state, status) { + setPinnedToUser (state, status) { const user = state.usersObject[status.user.id] - const index = user.pinnedStatuseIds.indexOf(status.id) + const index = user.pinnedStatusIds.indexOf(status.id) if (status.pinned && index === -1) { - user.pinnedStatuseIds.push(status.id) + user.pinnedStatusIds.push(status.id) } else if (!status.pinned && index !== -1) { - user.pinnedStatuseIds.splice(index, 1) + user.pinnedStatusIds.splice(index, 1) } }, setUserForStatus (state, status) { @@ -273,6 +285,12 @@ const users = { unmuteUser (store, id) { return unmuteUser(store, id) }, + hideReblogs (store, id) { + return hideReblogs(store, id) + }, + showReblogs (store, id) { + return showReblogs(store, id) + }, muteUsers (store, ids = []) { return Promise.all(ids.map(id => muteUser(store, id))) }, @@ -305,6 +323,14 @@ const users = { clearFollowers ({ commit }, userId) { commit('clearFollowers', userId) }, + subscribeUser ({ rootState, commit }, id) { + return rootState.api.backendInteractor.subscribeUser(id) + .then((relationship) => commit('updateUserRelationship', [relationship])) + }, + unsubscribeUser ({ rootState, commit }, id) { + return rootState.api.backendInteractor.unsubscribeUser(id) + .then((relationship) => commit('updateUserRelationship', [relationship])) + }, registerPushNotifications (store) { const token = store.state.currentUser.credentials const vapidPublicKey = store.rootState.instance.vapidPublicKey @@ -331,13 +357,13 @@ const users = { // Reconnect users to statuses store.commit('setUserForStatus', status) // Set pinned statuses to user - store.commit('setPinned', status) + store.commit('setPinnedToUser', status) }) each(compact(map(statuses, 'retweeted_status')), (status) => { // Reconnect users to retweets store.commit('setUserForStatus', status) // Set pinned retweets to user - store.commit('setPinned', status) + store.commit('setPinnedToUser', status) }) }, addNewNotifications (store, { notifications }) { @@ -347,8 +373,8 @@ const users = { const notificationsObject = store.rootState.statuses.notifications.idStore const relevantNotifications = Object.entries(notificationsObject) - .filter(([k, val]) => notificationIds.includes(k)) - .map(([k, val]) => val) + .filter(([k, val]) => notificationIds.includes(k)) + .map(([k, val]) => val) // Reconnect users to notifications each(relevantNotifications, (notification) => { @@ -356,8 +382,7 @@ const users = { }) }, searchUsers (store, query) { - // TODO: Move userSearch api into api.service - return userSearchApi.search({query, store: { state: store.rootState }}) + return store.rootState.api.backendInteractor.searchUsers(query) .then((users) => { store.commit('addNewUsers', users) return users @@ -368,48 +393,50 @@ const users = { let rootState = store.rootState - let response = await rootState.api.backendInteractor.register(userInfo) - if (response.ok) { - const data = { - oauth: rootState.oauth, - instance: rootState.instance.server - } - let app = await oauthApi.getOrCreateApp(data) - let result = await oauthApi.getTokenWithCredentials({ - app, - instance: data.instance, - username: userInfo.username, - password: userInfo.password - }) + try { + let data = await rootState.api.backendInteractor.register(userInfo) store.commit('signUpSuccess') - store.commit('setToken', result.access_token) - store.dispatch('loginUser', result.access_token) - } else { - const data = await response.json() - let errors = JSON.parse(data.error) - // replace ap_id with username - if (errors.ap_id) { - errors.username = errors.ap_id - delete errors.ap_id - } - errors = humanizeErrors(errors) + store.commit('setToken', data.access_token) + store.dispatch('loginUser', data.access_token) + } catch (e) { + let errors = e.message store.commit('signUpFailure', errors) - throw Error(errors) + throw e } }, async getCaptcha (store) { - return await store.rootState.api.backendInteractor.getCaptcha() + return store.rootState.api.backendInteractor.getCaptcha() }, logout (store) { - store.commit('clearCurrentUser') - store.dispatch('disconnectFromChat') - store.commit('setToken', false) - store.dispatch('stopFetching', 'friends') - store.commit('setBackendInteractor', backendInteractorService()) - store.dispatch('stopFetching', 'notifications') - store.commit('clearNotifications') - store.commit('resetStatuses') + const { oauth, instance } = store.rootState + + const data = { + ...oauth, + commit: store.commit, + instance: instance.server + } + + return oauthApi.getOrCreateApp(data) + .then((app) => { + const params = { + app, + instance: data.instance, + token: oauth.userToken + } + + return oauthApi.revokeToken(params) + }) + .then(() => { + store.commit('clearCurrentUser') + store.dispatch('disconnectFromSocket') + store.commit('clearToken') + store.dispatch('stopFetching', 'friends') + store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) + store.dispatch('stopFetching', 'notifications') + store.commit('clearNotifications') + store.commit('resetStatuses') + }) }, loginUser (store, accessToken) { return new Promise((resolve, reject) => { @@ -456,19 +483,19 @@ const users = { // Authentication failed commit('endLogin') if (response.status === 401) { - reject('Wrong username or password') + reject(new Error('Wrong username or password')) } else { - reject('An error occurred, please try again') + reject(new Error('An error occurred, please try again')) } } commit('endLogin') resolve() }) - .catch((error) => { - console.log(error) - commit('endLogin') - reject('Failed to connect to server, try again') - }) + .catch((error) => { + console.log(error) + commit('endLogin') + reject(new Error('Failed to connect to server, try again')) + }) }) } } |
