From 0995658757b89eeb38b78e997bec2d85b96296af Mon Sep 17 00:00:00 2001 From: kPherox Date: Tue, 19 Nov 2019 14:07:15 +0000 Subject: backend interactor service: implement startFetchingFollowRequest backend interactor service: remove unused fetchFollowRequests --- src/modules/users.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/modules/users.js') diff --git a/src/modules/users.js b/src/modules/users.js index 1c9ff5e8..14b2d8b5 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -434,6 +434,7 @@ const users = { store.dispatch('stopFetching', 'friends') store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) store.dispatch('stopFetching', 'notifications') + store.dispatch('stopFetching', 'followRequest') store.commit('clearNotifications') store.commit('resetStatuses') }) -- cgit v1.2.3-70-g09d2 From ddb6fb9217789e90490a4ec1ce7a2dd9ced67631 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 24 Nov 2019 13:57:46 +0200 Subject: Backend Interactor service overhaul, removed the need for copypasting --- .../follow_request_card/follow_request_card.js | 4 +- .../moderation_tools/moderation_tools.js | 16 +- .../user_reporting_modal/user_reporting_modal.js | 2 +- src/components/user_settings/user_settings.js | 8 +- src/modules/oauth_tokens.js | 2 +- src/modules/polls.js | 4 +- src/modules/statuses.js | 26 +-- src/modules/users.js | 16 +- .../backend_interactor_service.js | 231 ++------------------- .../follow_manipulate/follow_manipulate.js | 2 +- 10 files changed, 55 insertions(+), 256 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index 1a00a1c1..a8931787 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -7,11 +7,11 @@ const FollowRequestCard = { }, methods: { approveUser () { - this.$store.state.api.backendInteractor.approveUser(this.user.id) + this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) }, denyUser () { - this.$store.state.api.backendInteractor.denyUser(this.user.id) + this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) } } diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index 8aadc8c5..5bb76497 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -45,12 +45,12 @@ const ModerationTools = { toggleTag (tag) { const store = this.$store if (this.tagsSet.has(tag)) { - store.state.api.backendInteractor.untagUser(this.user, tag).then(response => { + store.state.api.backendInteractor.untagUser({ user: this.user, tag }).then(response => { if (!response.ok) { return } store.commit('untagUser', { user: this.user, tag }) }) } else { - store.state.api.backendInteractor.tagUser(this.user, tag).then(response => { + store.state.api.backendInteractor.tagUser({ user: this.user, tag }).then(response => { if (!response.ok) { return } store.commit('tagUser', { user: this.user, tag }) }) @@ -59,21 +59,21 @@ const ModerationTools = { toggleRight (right) { const store = this.$store if (this.user.rights[right]) { - store.state.api.backendInteractor.deleteRight(this.user, right).then(response => { + store.state.api.backendInteractor.deleteRight({ user: this.user, right }).then(response => { if (!response.ok) { return } - store.commit('updateRight', { user: this.user, right: right, value: false }) + store.commit('updateRight', { user: this.user, right, value: false }) }) } else { - store.state.api.backendInteractor.addRight(this.user, right).then(response => { + store.state.api.backendInteractor.addRight({ user: this.user, right }).then(response => { if (!response.ok) { return } - store.commit('updateRight', { user: this.user, right: right, value: true }) + store.commit('updateRight', { user: this.user, right, value: true }) }) } }, toggleActivationStatus () { const store = this.$store const status = !!this.user.deactivated - store.state.api.backendInteractor.setActivationStatus(this.user, status).then(response => { + store.state.api.backendInteractor.setActivationStatus({ user: this.user, status }).then(response => { if (!response.ok) { return } store.commit('updateActivationStatus', { user: this.user, status: status }) }) @@ -85,7 +85,7 @@ const ModerationTools = { const store = this.$store const user = this.user const { id, name } = user - store.state.api.backendInteractor.deleteUser(user) + store.state.api.backendInteractor.deleteUser({ user }) .then(e => { this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id) const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile' diff --git a/src/components/user_reporting_modal/user_reporting_modal.js b/src/components/user_reporting_modal/user_reporting_modal.js index 833fa98a..38cf117b 100644 --- a/src/components/user_reporting_modal/user_reporting_modal.js +++ b/src/components/user_reporting_modal/user_reporting_modal.js @@ -64,7 +64,7 @@ const UserReportingModal = { forward: this.forward, statusIds: this.statusIdsToReport } - this.$store.state.api.backendInteractor.reportUser(params) + this.$store.state.api.backendInteractor.reportUser({ ...params }) .then(() => { this.processing = false this.resetState() diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 3fdc5340..d5d671e4 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -242,7 +242,7 @@ const UserSettings = { }) }, importFollows (file) { - return this.$store.state.api.backendInteractor.importFollows(file) + return this.$store.state.api.backendInteractor.importFollows({ file }) .then((status) => { if (!status) { throw new Error('failed') @@ -250,7 +250,7 @@ const UserSettings = { }) }, importBlocks (file) { - return this.$store.state.api.backendInteractor.importBlocks(file) + return this.$store.state.api.backendInteractor.importBlocks({ file }) .then((status) => { if (!status) { throw new Error('failed') @@ -297,7 +297,7 @@ const UserSettings = { newPassword: this.changePasswordInputs[1], newPasswordConfirmation: this.changePasswordInputs[2] } - this.$store.state.api.backendInteractor.changePassword(params) + this.$store.state.api.backendInteractor.changePassword({ params }) .then((res) => { if (res.status === 'success') { this.changedPassword = true @@ -314,7 +314,7 @@ const UserSettings = { email: this.newEmail, password: this.changeEmailPassword } - this.$store.state.api.backendInteractor.changeEmail(params) + this.$store.state.api.backendInteractor.changeEmail({ params }) .then((res) => { if (res.status === 'success') { this.changedEmail = true diff --git a/src/modules/oauth_tokens.js b/src/modules/oauth_tokens.js index 0159a3f1..907cae4a 100644 --- a/src/modules/oauth_tokens.js +++ b/src/modules/oauth_tokens.js @@ -9,7 +9,7 @@ const oauthTokens = { }) }, revokeToken ({ rootState, commit, state }, id) { - rootState.api.backendInteractor.revokeOAuthToken(id).then((response) => { + 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 index e6158b63..92b89a06 100644 --- a/src/modules/polls.js +++ b/src/modules/polls.js @@ -40,7 +40,7 @@ const polls = { commit('mergeOrAddPoll', poll) }, updateTrackedPoll ({ rootState, dispatch, commit }, pollId) { - rootState.api.backendInteractor.fetchPoll(pollId).then(poll => { + rootState.api.backendInteractor.fetchPoll({ pollId }).then(poll => { setTimeout(() => { if (rootState.polls.trackedPolls[pollId]) { dispatch('updateTrackedPoll', pollId) @@ -59,7 +59,7 @@ const polls = { commit('untrackPoll', pollId) }, votePoll ({ rootState, commit }, { id, pollId, choices }) { - return rootState.api.backendInteractor.vote(pollId, choices).then(poll => { + return rootState.api.backendInteractor.vote({ pollId, choices }).then(poll => { commit('mergeOrAddPoll', poll) return poll }) diff --git a/src/modules/statuses.js b/src/modules/statuses.js index f11ffdcd..6a743a4a 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -551,45 +551,45 @@ const statuses = { favorite ({ rootState, commit }, status) { // Optimistic favoriting... commit('setFavorited', { status, value: true }) - rootState.api.backendInteractor.favorite(status.id) + rootState.api.backendInteractor.favorite({ id: status.id }) .then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser })) }, unfavorite ({ rootState, commit }, status) { // Optimistic unfavoriting... commit('setFavorited', { status, value: false }) - rootState.api.backendInteractor.unfavorite(status.id) + rootState.api.backendInteractor.unfavorite({ id: status.id }) .then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser })) }, fetchPinnedStatuses ({ rootState, dispatch }, userId) { - rootState.api.backendInteractor.fetchPinnedStatuses(userId) + rootState.api.backendInteractor.fetchPinnedStatuses({ id: userId }) .then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true })) }, pinStatus ({ rootState, dispatch }, statusId) { - return rootState.api.backendInteractor.pinOwnStatus(statusId) + return rootState.api.backendInteractor.pinOwnStatus({ id: statusId }) .then((status) => dispatch('addNewStatuses', { statuses: [status] })) }, unpinStatus ({ rootState, dispatch }, statusId) { - rootState.api.backendInteractor.unpinOwnStatus(statusId) + rootState.api.backendInteractor.unpinOwnStatus({ id: statusId }) .then((status) => dispatch('addNewStatuses', { statuses: [status] })) }, muteConversation ({ rootState, commit }, statusId) { - return rootState.api.backendInteractor.muteConversation(statusId) + return rootState.api.backendInteractor.muteConversation({ id: statusId }) .then((status) => commit('setMutedStatus', status)) }, unmuteConversation ({ rootState, commit }, statusId) { - return rootState.api.backendInteractor.unmuteConversation(statusId) + return rootState.api.backendInteractor.unmuteConversation({ id: statusId }) .then((status) => commit('setMutedStatus', status)) }, retweet ({ rootState, commit }, status) { // Optimistic retweeting... commit('setRetweeted', { status, value: true }) - rootState.api.backendInteractor.retweet(status.id) + rootState.api.backendInteractor.retweet({ id: status.id }) .then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser })) }, unretweet ({ rootState, commit }, status) { // Optimistic unretweeting... commit('setRetweeted', { status, value: false }) - rootState.api.backendInteractor.unretweet(status.id) + rootState.api.backendInteractor.unretweet({ id: status.id }) .then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser })) }, queueFlush ({ rootState, commit }, { timeline, id }) { @@ -604,19 +604,19 @@ const statuses = { }, fetchFavsAndRepeats ({ rootState, commit }, id) { Promise.all([ - rootState.api.backendInteractor.fetchFavoritedByUsers(id), - rootState.api.backendInteractor.fetchRebloggedByUsers(id) + rootState.api.backendInteractor.fetchFavoritedByUsers({ id }), + rootState.api.backendInteractor.fetchRebloggedByUsers({ id }) ]).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) + rootState.api.backendInteractor.fetchFavoritedByUsers({ id }) .then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })) }, fetchRepeats ({ rootState, commit }, id) { - rootState.api.backendInteractor.fetchRebloggedByUsers(id) + rootState.api.backendInteractor.fetchRebloggedByUsers({ id }) .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })) }, search (store, { q, resolve, limit, offset, following }) { diff --git a/src/modules/users.js b/src/modules/users.js index 14b2d8b5..e1373220 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -32,7 +32,7 @@ const getNotificationPermission = () => { } const blockUser = (store, id) => { - return store.rootState.api.backendInteractor.blockUser(id) + return store.rootState.api.backendInteractor.blockUser({ id }) .then((relationship) => { store.commit('updateUserRelationship', [relationship]) store.commit('addBlockId', id) @@ -43,12 +43,12 @@ const blockUser = (store, id) => { } const unblockUser = (store, id) => { - return store.rootState.api.backendInteractor.unblockUser(id) + return store.rootState.api.backendInteractor.unblockUser({ id }) .then((relationship) => store.commit('updateUserRelationship', [relationship])) } const muteUser = (store, id) => { - return store.rootState.api.backendInteractor.muteUser(id) + return store.rootState.api.backendInteractor.muteUser({ id }) .then((relationship) => { store.commit('updateUserRelationship', [relationship]) store.commit('addMuteId', id) @@ -56,7 +56,7 @@ const muteUser = (store, id) => { } const unmuteUser = (store, id) => { - return store.rootState.api.backendInteractor.unmuteUser(id) + return store.rootState.api.backendInteractor.unmuteUser({ id }) .then((relationship) => store.commit('updateUserRelationship', [relationship])) } @@ -324,11 +324,11 @@ const users = { commit('clearFollowers', userId) }, subscribeUser ({ rootState, commit }, id) { - return rootState.api.backendInteractor.subscribeUser(id) + return rootState.api.backendInteractor.subscribeUser({ id }) .then((relationship) => commit('updateUserRelationship', [relationship])) }, unsubscribeUser ({ rootState, commit }, id) { - return rootState.api.backendInteractor.unsubscribeUser(id) + return rootState.api.backendInteractor.unsubscribeUser({ id }) .then((relationship) => commit('updateUserRelationship', [relationship])) }, registerPushNotifications (store) { @@ -382,7 +382,7 @@ const users = { }) }, searchUsers (store, query) { - return store.rootState.api.backendInteractor.searchUsers(query) + return store.rootState.api.backendInteractor.searchUsers({ query }) .then((users) => { store.commit('addNewUsers', users) return users @@ -394,7 +394,7 @@ const users = { let rootState = store.rootState try { - let data = await rootState.api.backendInteractor.register(userInfo) + let data = await rootState.api.backendInteractor.register({ ...userInfo }) store.commit('signUpSuccess') store.commit('setToken', data.access_token) store.dispatch('loginUser', data.access_token) diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index c16bd1f1..57fdccde 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -3,228 +3,27 @@ import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service 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 }) => { + startFetchingFollowRequest ({ store }) { return followRequestFetcher.startFetching({ store, credentials }) - } - - // eslint-disable-next-line camelcase - const tagUser = ({ screen_name }, tag) => { - return apiService.tagUser({ screen_name, tag, credentials }) - } - - // eslint-disable-next-line camelcase - const untagUser = ({ screen_name }, tag) => { - return apiService.untagUser({ screen_name, tag, credentials }) - } - - // 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 - } + ...Object.entries(apiService).reduce((acc, [key, func]) => { + return { + ...acc, + [key]: (args) => func({ credentials, ...args }) + } + }, {}), - return backendInteractorServiceInstance -} + verifyCredentials: apiService.verifyCredentials +}) export default backendInteractorService diff --git a/src/services/follow_manipulate/follow_manipulate.js b/src/services/follow_manipulate/follow_manipulate.js index 598cb5f7..29b38a0f 100644 --- a/src/services/follow_manipulate/follow_manipulate.js +++ b/src/services/follow_manipulate/follow_manipulate.js @@ -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({ -- cgit v1.2.3-70-g09d2 From 319bb4ac2895b8eb62da42e3f95addc9bb67b1a0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 24 Nov 2019 18:50:28 +0200 Subject: initial streaming work --- src/modules/api.js | 15 ++++++++ src/modules/users.js | 13 ++++--- src/services/api/api.service.js | 40 ++++++++++++++++++++++ .../backend_interactor_service.js | 15 +++++++- 4 files changed, 77 insertions(+), 6 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/modules/api.js b/src/modules/api.js index 1293e3c8..1bf65db5 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -6,6 +6,7 @@ const api = { backendInteractor: backendInteractorService(), fetchers: {}, socket: null, + mastoSocket: null, followRequests: [] }, mutations: { @@ -29,6 +30,20 @@ const api = { } }, actions: { + startMastoSocket (store) { + store.state.mastoSocket = store.state.backendInteractor + .startUserSocket({ + store, + onMessage: (message) => { + if (!message) return + if (message.event === 'notification') { + store.dispatch('addNewNotifications', { notifications: [message.notification], older: false }) + } else if (message.event === 'update') { + store.dispatch('addNewStatuses', { statuses: [message.status], userId: false, showImmediately: false, timeline: 'friends' }) + } + } + }) + }, startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) { // Don't start fetching if we already are. if (store.state.fetchers[timeline]) return diff --git a/src/modules/users.js b/src/modules/users.js index e1373220..861a2f4f 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -469,11 +469,14 @@ const users = { store.dispatch('initializeSocket') } - // Start getting fresh posts. - store.dispatch('startFetchingTimeline', { timeline: 'friends' }) - - // Start fetching notifications - store.dispatch('startFetchingNotifications') + store.dispatch('startMastoSocket').catch((error) => { + console.error(error) + // Start getting fresh posts. + store.dispatch('startFetchingTimeline', { timeline: 'friends' }) + + // Start fetching notifications + store.dispatch('startFetchingNotifications') + }) // Get user mutes store.dispatch('fetchMutes') diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 8f5eb416..7f27564f 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -71,6 +71,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 @@ -932,6 +933,45 @@ 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' +]) + +export const handleMastoWS = (wsEvent) => { + console.debug('Event', wsEvent) + const { data } = wsEvent + if (!data) return + const parsedEvent = JSON.parse(data) + const { event, payload } = parsedEvent + if (MASTODON_STREAMING_EVENTS.has(event)) { + 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, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 57fdccde..0cef4640 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -1,4 +1,4 @@ -import apiService from '../api/api.service.js' +import apiService, { getMastodonSocketURI, handleMastoWS } 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' @@ -16,6 +16,19 @@ const backendInteractorService = credentials => ({ return followRequestFetcher.startFetching({ store, credentials }) }, + startUserSocket ({ store, onMessage }) { + const serv = store.rootState.instance.server.replace('https', 'wss') + // const serb = 'ws://localhost:8080/' + const url = serv + getMastodonSocketURI({ credentials, stream: 'user' }) + const socket = new WebSocket(url) + console.log(socket) + if (socket) { + socket.addEventListener('message', (wsEvent) => onMessage(handleMastoWS(wsEvent))) + } else { + throw new Error('failed to connect to socket') + } + }, + ...Object.entries(apiService).reduce((acc, [key, func]) => { return { ...acc, -- cgit v1.2.3-70-g09d2 From 172ebaf4e67358852bfaafd8f069763ca5e602b1 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 24 Nov 2019 22:01:12 +0200 Subject: improved initial notifications fetching --- src/components/notifications/notifications.js | 5 +++++ src/modules/api.js | 23 +++++++++++++++++++--- src/modules/users.js | 2 +- .../backend_interactor_service.js | 9 +++++++-- 4 files changed, 33 insertions(+), 6 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 6c4054fd..a89c0cdc 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -47,6 +47,11 @@ const Notifications = { components: { Notification }, + created () { + const { dispatch } = this.$store + + dispatch('fetchAndUpdateNotifications') + }, watch: { unseenCount (count) { if (count > 0) { diff --git a/src/modules/api.js b/src/modules/api.js index 1bf65db5..0e7e5e19 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -31,18 +31,32 @@ const api = { }, actions: { startMastoSocket (store) { - store.state.mastoSocket = store.state.backendInteractor + const { state, dispatch } = store + state.mastoSocket = state.backendInteractor .startUserSocket({ store, onMessage: (message) => { if (!message) return if (message.event === 'notification') { - store.dispatch('addNewNotifications', { notifications: [message.notification], older: false }) + dispatch('addNewNotifications', { + notifications: [message.notification], + older: false + }) } else if (message.event === 'update') { - store.dispatch('addNewStatuses', { statuses: [message.status], userId: false, showImmediately: false, timeline: 'friends' }) + dispatch('addNewStatuses', { + statuses: [message.status], + userId: false, + showImmediately: false, + timeline: 'friends' + }) } } }) + state.mastoSocket.addEventListener('error', error => { + console.error('Error with MastoAPI websocket:', error) + dispatch('startFetchingTimeline', { timeline: 'friends' }) + dispatch('startFetchingNotifications') + }) }, startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) { // Don't start fetching if we already are. @@ -58,6 +72,9 @@ const api = { const fetcher = store.state.backendInteractor.startFetchingNotifications({ store }) store.commit('addFetcher', { fetcherName: 'notifications', fetcher }) }, + fetchAndUpdateNotifications (store) { + store.state.backendInteractor.fetchAndUpdateNotifications({ store }) + }, startFetchingFollowRequest (store) { // Don't start fetching if we already are. if (store.state.fetchers['followRequest']) return diff --git a/src/modules/users.js b/src/modules/users.js index 861a2f4f..eff0c5d5 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -470,7 +470,7 @@ const users = { } store.dispatch('startMastoSocket').catch((error) => { - console.error(error) + console.error('Failed initializing MastoAPI Streaming socket', error) // Start getting fresh posts. store.dispatch('startFetchingTimeline', { timeline: 'friends' }) diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 0cef4640..850b7867 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -12,18 +12,23 @@ const backendInteractorService = credentials => ({ return notificationsFetcher.startFetching({ store, credentials }) }, + fetchAndUpdateNotifications ({ store }) { + return notificationsFetcher.fetchAndUpdate({ store, credentials }) + }, + startFetchingFollowRequest ({ store }) { return followRequestFetcher.startFetching({ store, credentials }) }, startUserSocket ({ store, onMessage }) { - const serv = store.rootState.instance.server.replace('https', 'wss') - // const serb = 'ws://localhost:8080/' + const serv = store.rootState.instance.server.replace('http', 'ws') const url = serv + getMastodonSocketURI({ credentials, stream: 'user' }) const socket = new WebSocket(url) console.log(socket) if (socket) { socket.addEventListener('message', (wsEvent) => onMessage(handleMastoWS(wsEvent))) + socket.addEventListener('error', (error) => console.error('WebSocket Error:', error)) + return socket } else { throw new Error('failed to connect to socket') } -- cgit v1.2.3-70-g09d2 From ff95d865d223fed5bab2a4d72ff3a22f014d3c56 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 8 Dec 2019 16:05:41 +0200 Subject: Updated streaming and improved error-handling, some more refactoring to api --- .../public_and_external_timeline.js | 2 +- src/components/public_timeline/public_timeline.js | 2 +- src/components/tag_timeline/tag_timeline.js | 2 +- src/components/user_profile/user_profile.js | 6 +- src/modules/api.js | 99 ++++++++++++++++------ src/modules/users.js | 8 +- .../backend_interactor_service.js | 5 +- 7 files changed, 84 insertions(+), 40 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js index f614c13b..cbd4491b 100644 --- a/src/components/public_and_external_timeline/public_and_external_timeline.js +++ b/src/components/public_and_external_timeline/public_and_external_timeline.js @@ -10,7 +10,7 @@ const PublicAndExternalTimeline = { this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' }) }, destroyed () { - this.$store.dispatch('stopFetching', 'publicAndExternal') + this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal') } } diff --git a/src/components/public_timeline/public_timeline.js b/src/components/public_timeline/public_timeline.js index 8976a99c..66c40d3a 100644 --- a/src/components/public_timeline/public_timeline.js +++ b/src/components/public_timeline/public_timeline.js @@ -10,7 +10,7 @@ const PublicTimeline = { this.$store.dispatch('startFetchingTimeline', { timeline: 'public' }) }, destroyed () { - this.$store.dispatch('stopFetching', 'public') + this.$store.dispatch('stopFetchingTimeline', 'public') } } diff --git a/src/components/tag_timeline/tag_timeline.js b/src/components/tag_timeline/tag_timeline.js index 458eb1c5..400c6a4b 100644 --- a/src/components/tag_timeline/tag_timeline.js +++ b/src/components/tag_timeline/tag_timeline.js @@ -19,7 +19,7 @@ const TagTimeline = { } }, destroyed () { - this.$store.dispatch('stopFetching', 'tag') + this.$store.dispatch('stopFetchingTimeline', 'tag') } } diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 00055707..9558a0bd 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -112,9 +112,9 @@ const UserProfile = { } }, stopFetching () { - this.$store.dispatch('stopFetching', 'user') - this.$store.dispatch('stopFetching', 'favorites') - this.$store.dispatch('stopFetching', 'media') + this.$store.dispatch('stopFetchingTimeline', 'user') + this.$store.dispatch('stopFetchingTimeline', 'favorites') + this.$store.dispatch('stopFetchingTimeline', 'media') }, switchUser (userNameOrId) { this.stopFetching() diff --git a/src/modules/api.js b/src/modules/api.js index 0e7e5e19..185c9db6 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -6,7 +6,7 @@ const api = { backendInteractor: backendInteractorService(), fetchers: {}, socket: null, - mastoSocket: null, + mastoUserSocket: null, followRequests: [] }, mutations: { @@ -16,7 +16,8 @@ const api = { addFetcher (state, { fetcherName, fetcher }) { state.fetchers[fetcherName] = fetcher }, - removeFetcher (state, { fetcherName }) { + removeFetcher (state, { fetcherName, fetcher }) { + window.clearInterval(fetcher) delete state.fetchers[fetcherName] }, setWsToken (state, token) { @@ -30,13 +31,14 @@ const api = { } }, actions: { - startMastoSocket (store) { + // MastoAPI 'User' sockets + startMastoUserSocket (store) { const { state, dispatch } = store - state.mastoSocket = state.backendInteractor + state.mastoUserSocket = state.backendInteractor .startUserSocket({ store, onMessage: (message) => { - if (!message) return + if (!message) return // pings if (message.event === 'notification') { dispatch('addNewNotifications', { notifications: [message.notification], @@ -52,41 +54,86 @@ const api = { } } }) - state.mastoSocket.addEventListener('error', error => { - console.error('Error with MastoAPI websocket:', error) - dispatch('startFetchingTimeline', { timeline: 'friends' }) - dispatch('startFetchingNotifications') + state.mastoUserSocket.addEventListener('error', error => { + console.error('Error in MastoAPI websocket:', error) + }) + state.mastoUserSocket.addEventListener('close', closeEvent => { + const ignoreCodes = new Set([ + 1000, // Normal (intended) closure + 1001 // Going away + ]) + const { code } = closeEvent + console.debug('Socket closure event:', closeEvent) + if (ignoreCodes.has(code)) { + console.debug(`Not restarting socket becasue of closure code ${code} is in ignore list`) + } else { + console.warn(`MastoAPI websocket disconnected, restarting. CloseEvent code: ${code}`) + dispatch('startFetchingTimeline', { timeline: 'friends' }) + dispatch('startFetchingNotifications') + dispatch('restartMastoUserSocket') + } }) }, - startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) { - // Don't start fetching if we already are. + restartMastoUserSocket ({ dispatch }) { + // This basically starts MastoAPI user socket and stops conventional + // fetchers when connection reestablished + dispatch('startMastoUserSocket').then(() => { + dispatch('stopFetchingTimeline', { timeline: 'friends' }) + dispatch('stopFetchingNotifications') + }) + }, + + // Timelines + startFetchingTimeline (store, { + timeline = 'friends', + tag = false, + userId = false + }) { if (store.state.fetchers[timeline]) return - const fetcher = store.state.backendInteractor.startFetchingTimeline({ timeline, store, userId, tag }) + const fetcher = store.state.backendInteractor.startFetchingTimeline({ + timeline, store, userId, tag + }) store.commit('addFetcher', { fetcherName: timeline, fetcher }) }, - startFetchingNotifications (store) { - // Don't start fetching if we already are. - if (store.state.fetchers['notifications']) return + stopFetchingTimeline (store, timeline) { + const fetcher = store.state.fetchers[timeline] + if (!fetcher) return + store.commit('removeFetcher', { fetcherName: timeline, fetcher }) + }, + // Notifications + startFetchingNotifications (store) { + if (store.state.fetchers.notifications) return const fetcher = store.state.backendInteractor.startFetchingNotifications({ store }) store.commit('addFetcher', { fetcherName: 'notifications', fetcher }) }, + stopFetchingNotifications (store) { + const fetcher = store.state.fetchers.notifications + if (!fetcher) return + store.commit('removeFetcher', { fetcherName: 'notifications', fetcher }) + }, fetchAndUpdateNotifications (store) { store.state.backendInteractor.fetchAndUpdateNotifications({ store }) }, - startFetchingFollowRequest (store) { - // Don't start fetching if we already are. - if (store.state.fetchers['followRequest']) return - const fetcher = store.state.backendInteractor.startFetchingFollowRequest({ store }) - store.commit('addFetcher', { fetcherName: 'followRequest', fetcher }) + // Follow requests + startFetchingFollowRequests (store) { + if (store.state.fetchers['followRequests']) return + const fetcher = store.state.backendInteractor.startFetchingFollowRequests({ store }) + store.commit('addFetcher', { fetcherName: 'followRequests', fetcher }) }, - stopFetching (store, fetcherName) { - const fetcher = store.state.fetchers[fetcherName] - window.clearInterval(fetcher) - store.commit('removeFetcher', { fetcherName }) + stopFetchingFollowRequests (store) { + const fetcher = store.state.fetchers.followRequests + if (!fetcher) return + store.commit('removeFetcher', { fetcherName: 'followRequests', fetcher }) + }, + removeFollowRequest (store, request) { + let requests = store.state.followRequests.filter((it) => it !== request) + store.commit('setFollowRequests', requests) }, + + // Pleroma websocket setWsToken (store, token) { store.commit('setWsToken', token) }, @@ -104,10 +151,6 @@ const api = { disconnectFromSocket ({ commit, state }) { state.socket && state.socket.disconnect() commit('setSocket', null) - }, - removeFollowRequest (store, request) { - let requests = store.state.followRequests.filter((it) => it !== request) - store.commit('setFollowRequests', requests) } } } diff --git a/src/modules/users.js b/src/modules/users.js index eff0c5d5..6bdaf193 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -431,10 +431,10 @@ const users = { store.commit('clearCurrentUser') store.dispatch('disconnectFromSocket') store.commit('clearToken') - store.dispatch('stopFetching', 'friends') + store.dispatch('stopFetchingTimeline', 'friends') store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) - store.dispatch('stopFetching', 'notifications') - store.dispatch('stopFetching', 'followRequest') + store.dispatch('stopFetchingNotifications') + store.dispatch('stopFetchingFollowRequests') store.commit('clearNotifications') store.commit('resetStatuses') }) @@ -469,7 +469,7 @@ const users = { store.dispatch('initializeSocket') } - store.dispatch('startMastoSocket').catch((error) => { + store.dispatch('startMastoUserSocket').catch((error) => { console.error('Failed initializing MastoAPI Streaming socket', error) // Start getting fresh posts. store.dispatch('startFetchingTimeline', { timeline: 'friends' }) diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 850b7867..33b79a40 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -24,10 +24,11 @@ const backendInteractorService = credentials => ({ const serv = store.rootState.instance.server.replace('http', 'ws') const url = serv + getMastodonSocketURI({ credentials, stream: 'user' }) const socket = new WebSocket(url) - console.log(socket) + console.debug('Socket created:', socket) if (socket) { + socket.addEventListener('open', (wsEvent) => console.debug('MastoAPI User WebSocket connection established')) socket.addEventListener('message', (wsEvent) => onMessage(handleMastoWS(wsEvent))) - socket.addEventListener('error', (error) => console.error('WebSocket Error:', error)) + socket.addEventListener('error', (error) => console.error('MastoApi User WebSocket Error:', error)) return socket } else { throw new Error('failed to connect to socket') -- cgit v1.2.3-70-g09d2 From 6acd889589e46b18491d96b5fa992154b4e58d88 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 10 Dec 2019 21:30:27 +0200 Subject: Option to enable streaming --- src/components/settings/settings.js | 14 +++++++++++++- src/components/settings/settings.vue | 9 +++++++++ src/i18n/en.json | 2 ++ src/i18n/ru.json | 2 ++ src/modules/api.js | 18 ++++++++++++++++++ src/modules/config.js | 1 + src/modules/users.js | 14 +++++++++++--- src/services/api/api.service.js | 6 ++++++ 8 files changed, 62 insertions(+), 4 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index c49083f9..2d7723cc 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -84,7 +84,7 @@ const settings = { } }]) .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}), - // Special cases (need to transform values) + // Special cases (need to transform values or perform actions first) muteWordsString: { get () { return this.$store.getters.mergedConfig.muteWords.join('\n') }, set (value) { @@ -93,6 +93,18 @@ const settings = { value: filter(value.split('\n'), (word) => trim(word).length > 0) }) } + }, + useStreamingApi: { + get () { return this.$store.getters.mergedConfig.useStreamingApi }, + set (value) { + const promise = value + ? this.$store.dispatch('enableMastoSockets') + : this.$store.dispatch('disableMastoSockets') + + promise.then(() => { + this.$store.dispatch('setOption', { name: 'useStreamingApi', value }) + }) + } } }, // Updating nested properties diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index c4021137..b40c85dd 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -73,6 +73,15 @@ +
  • + + {{ $t('settings.useStreamingApi') }} +
    + + {{ $t('settings.useStreamingApiWarning') }} + +
    +
  • {{ $t('settings.autoload') }} diff --git a/src/i18n/en.json b/src/i18n/en.json index 85146ef5..60fc792f 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -358,6 +358,8 @@ "post_status_content_type": "Post status content type", "stop_gifs": "Play-on-hover GIFs", "streaming": "Enable automatic streaming of new posts when scrolled to the top", + "useStreamingApi": "Receive posts and notifications real-time", + "useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)", "text": "Text", "theme": "Theme", "theme_help": "Use hex color codes (#rrggbb) to customize your color theme.", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 19e10f1e..4cb2d497 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -219,6 +219,8 @@ "subject_input_always_show": "Всегда показывать поле ввода темы", "stop_gifs": "Проигрывать GIF анимации только при наведении", "streaming": "Включить автоматическую загрузку новых сообщений при прокрутке вверх", + "useStreamingApi": "Получать сообщения и уведомления в реальном времени", + "useStreamingApiWarning": "(Не рекомендуется, экспериментально, сообщения могут пропадать)", "text": "Текст", "theme": "Тема", "theme_help": "Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.", diff --git a/src/modules/api.js b/src/modules/api.js index 593f8498..dc91d00e 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -31,6 +31,18 @@ const api = { } }, actions: { + // Global MastoAPI socket control, in future should disable ALL sockets/(re)start relevant sockets + enableMastoSockets (store) { + const { state, dispatch } = store + if (state.mastoUserSocket) return + dispatch('startMastoUserSocket') + }, + disableMastoSockets (store) { + const { state, dispatch } = store + if (!state.mastoUserSocket) return + dispatch('stopMastoUserSocket') + }, + // MastoAPI 'User' sockets startMastoUserSocket (store) { const { state, dispatch } = store @@ -81,6 +93,12 @@ const api = { dispatch('stopFetchingNotifications') }) }, + stopMastoUserSocket ({ state, dispatch }) { + dispatch('startFetchingTimeline', { timeline: 'friends' }) + dispatch('startFetchingNotifications') + console.log(state.mastoUserSocket) + state.mastoUserSocket.close() + }, // Timelines startFetchingTimeline (store, { diff --git a/src/modules/config.js b/src/modules/config.js index 329b4091..74025db1 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -35,6 +35,7 @@ export const defaultState = { highlight: {}, interfaceLanguage: browserLocale, hideScopeNotice: false, + useStreamingApi: false, scopeCopy: undefined, // instance default subjectLineBehavior: undefined, // instance default alwaysShowSubjectInput: undefined, // instance default diff --git a/src/modules/users.js b/src/modules/users.js index 6bdaf193..cbec6063 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -469,14 +469,22 @@ const users = { store.dispatch('initializeSocket') } - store.dispatch('startMastoUserSocket').catch((error) => { - console.error('Failed initializing MastoAPI Streaming socket', error) + const startPolling = () => { // Start getting fresh posts. store.dispatch('startFetchingTimeline', { timeline: 'friends' }) // Start fetching notifications store.dispatch('startFetchingNotifications') - }) + } + + if (store.getters.mergedConfig.useStreamingApi) { + store.dispatch('enableMastoSockets').catch((error) => { + console.error('Failed initializing MastoAPI Streaming socket', error) + startPolling() + }) + } else { + startPolling() + } // Get user mutes store.dispatch('fetchMutes') diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index c6818df4..517b953e 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -983,18 +983,24 @@ export const ProcessedWS = ({ 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 } -- cgit v1.2.3-70-g09d2 From c3e7806acbd32483eab497a347f947158ab8febf Mon Sep 17 00:00:00 2001 From: kPherox Date: Wed, 11 Dec 2019 18:48:18 +0900 Subject: remove unused fallback --- src/components/notification/notification.js | 16 ++-------------- src/modules/users.js | 2 ++ 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 93edf2fa..e7bd769e 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -43,26 +43,14 @@ const Notification = { const user = this.notification.from_profile return highlightStyle(highlight[user.screen_name]) }, - userInStore () { - return this.$store.getters.findUser(this.notification.from_profile.id) - }, user () { - if (this.userInStore) { - return this.userInStore - } - return this.notification.from_profile + return this.$store.getters.findUser(this.notification.from_profile.id) }, userProfileLink () { return this.generateUserProfileLink(this.user) }, - targetUserInStore () { - return this.$store.getters.findUser(this.notification.target.id) - }, targetUser () { - if (this.targetUserInStore) { - return this.targetUserInStore - } - return this.notification.target + return this.$store.getters.findUser(this.notification.target.id) }, targetUserProfileLink () { return this.generateUserProfileLink(this.targetUser) diff --git a/src/modules/users.js b/src/modules/users.js index 14b2d8b5..f209b23b 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -368,8 +368,10 @@ const users = { }, addNewNotifications (store, { notifications }) { const users = map(notifications, 'from_profile') + const targetUsers = map(notifications, 'target') const notificationIds = notifications.map(_ => _.id) store.commit('addNewUsers', users) + store.commit('addNewUsers', targetUsers) const notificationsObject = store.rootState.statuses.notifications.idStore const relevantNotifications = Object.entries(notificationsObject) -- cgit v1.2.3-70-g09d2 From 585702b1cedf25547ff5faf0170263088e5484a6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 12 Dec 2019 18:53:36 +0200 Subject: fix desktop notifications not working with streaming --- src/modules/users.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/modules/users.js') diff --git a/src/modules/users.js b/src/modules/users.js index cbec6063..5dc2f36f 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -481,6 +481,8 @@ const users = { store.dispatch('enableMastoSockets').catch((error) => { console.error('Failed initializing MastoAPI Streaming socket', error) startPolling() + }).then(() => { + setTimeout(() => store.dispatch('setNotificationsSilence', false), 10000) }) } else { startPolling() -- cgit v1.2.3-70-g09d2 From 36376ce57c93c81317b6a8b0b50699d6b8488f57 Mon Sep 17 00:00:00 2001 From: taehoon Date: Mon, 18 Nov 2019 20:42:10 -0500 Subject: use vuex action --- src/components/moderation_tools/moderation_tools.js | 7 +------ src/modules/users.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index 10a20709..02b92fef 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -71,12 +71,7 @@ const ModerationTools = { } }, toggleActivationStatus () { - const store = this.$store - const status = !!this.user.deactivated - store.state.api.backendInteractor.toggleActivationStatus(this.user).then(response => { - if (!response.ok) { return } - store.commit('updateActivationStatus', { user: this.user, status: status }) - }) + this.$store.dispatch('toggleActivationStatus', this.user) }, deleteUserDialog (show) { this.showDeleteUserDialog = show diff --git a/src/modules/users.js b/src/modules/users.js index 14b2d8b5..ec2ef608 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -95,9 +95,9 @@ export const mutations = { newRights[right] = value set(user, 'rights', newRights) }, - updateActivationStatus (state, { user: { id }, status }) { + updateActivationStatus (state, { user: { id }, deactivated }) { const user = state.usersObject[id] - set(user, 'deactivated', !status) + set(user, 'deactivated', deactivated) }, setCurrentUser (state, user) { state.lastLoginName = user.screen_name @@ -331,6 +331,12 @@ const users = { return rootState.api.backendInteractor.unsubscribeUser(id) .then((relationship) => commit('updateUserRelationship', [relationship])) }, + toggleActivationStatus ({ rootState, commit }, user) { + rootState.api.backendInteractor.toggleActivationStatus(user) + .then(response => { + commit('updateActivationStatus', { user, deactivated: response.deactivated }) + }) + }, registerPushNotifications (store) { const token = store.state.currentUser.credentials const vapidPublicKey = store.rootState.instance.vapidPublicKey -- cgit v1.2.3-70-g09d2 From 4e4c4af422c400d016e4605f8bcf699f7154a8b4 Mon Sep 17 00:00:00 2001 From: taehoon Date: Tue, 19 Nov 2019 14:41:39 -0500 Subject: toggle_activation api is also deprecated --- src/modules/users.js | 7 +++-- src/services/api/api.service.js | 31 +++++++++++++++++----- .../backend_interactor_service.js | 12 ++++++--- 3 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src/modules/users.js') diff --git a/src/modules/users.js b/src/modules/users.js index ec2ef608..82d3c4e8 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -332,10 +332,9 @@ const users = { .then((relationship) => commit('updateUserRelationship', [relationship])) }, toggleActivationStatus ({ rootState, commit }, user) { - rootState.api.backendInteractor.toggleActivationStatus(user) - .then(response => { - commit('updateActivationStatus', { user, deactivated: response.deactivated }) - }) + const api = user.deactivated ? rootState.api.backendInteractor.activateUser : rootState.api.backendInteractor.deactivateUser + api(user) + .then(({ deactivated }) => commit('updateActivationStatus', { user, deactivated })) }, registerPushNotifications (store) { const token = store.state.currentUser.credentials diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index b739ec1f..a69fa53c 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -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 TOGGLE_ACTIVATION_URL = screenName => `/api/pleroma/admin/users/${screenName}/toggle_activation` +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' @@ -450,9 +451,26 @@ const deleteRight = ({ right, credentials, ...user }) => { }) } -// eslint-disable-next-line camelcase -const toggleActivationStatus = ({ credentials, screen_name }) => { - return promisedRequest({ url: TOGGLE_ACTIVATION_URL(screen_name), method: 'PATCH', credentials }) +const activateUser = ({ credentials, screen_name: nickname }) => { + return promisedRequest({ + url: ACTIVATE_USER_URL, + method: 'PATCH', + credentials, + payload: { + nicknames: [nickname] + } + }).then(response => get(response, 'users.0')) +} + +const deactivateUser = ({ credentials, 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 }) => { @@ -968,7 +986,8 @@ const apiService = { deleteUser, addRight, deleteRight, - toggleActivationStatus, + activateUser, + deactivateUser, register, getCaptcha, updateAvatar, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index e0a15d3b..3d4ec6ac 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -89,8 +89,13 @@ const backendInteractorService = credentials => { } // eslint-disable-next-line camelcase - const toggleActivationStatus = ({ screen_name }) => { - return apiService.toggleActivationStatus({ screen_name, credentials }) + const activateUser = ({ screen_name }) => { + return apiService.activateUser({ screen_name, credentials }) + } + + // eslint-disable-next-line camelcase + const deactivateUser = ({ screen_name }) => { + return apiService.deactivateUser({ screen_name, credentials }) } // eslint-disable-next-line camelcase @@ -191,7 +196,8 @@ const backendInteractorService = credentials => { addRight, deleteRight, deleteUser, - toggleActivationStatus, + activateUser, + deactivateUser, register, getCaptcha, updateAvatar, -- cgit v1.2.3-70-g09d2 From 662afe973a72efc17e61fd4c071ed985bfe4bf6b Mon Sep 17 00:00:00 2001 From: Shpuld Shpludson Date: Tue, 14 Jan 2020 13:45:00 +0000 Subject: Fix #750 , fix error messages and captcha resetting --- CHANGELOG.md | 2 ++ src/components/registration/registration.js | 3 ++- src/components/registration/registration.vue | 2 +- src/modules/users.js | 4 +++- src/services/errors/errors.js | 14 ++++++++++---- 5 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/modules/users.js') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f5a9305..6dcbc7da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Changed +- Captcha now resets on failed registrations - Notifications column now cleans itself up to optimize performance when tab is left open for a long time ### Fixed - Single notifications left unread when hitting read on another device/tab +- Registration fixed ## [1.1.8] - 2020-01-10 ### Added diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js index 57f3caf0..ace8cc7c 100644 --- a/src/components/registration/registration.js +++ b/src/components/registration/registration.js @@ -63,7 +63,8 @@ const registration = { await this.signUp(this.user) this.$router.push({ name: 'friends' }) } catch (error) { - console.warn('Registration failed: ' + error) + console.warn('Registration failed: ', error) + this.setCaptcha() } } }, diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index 222b67a8..fdbda007 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -170,7 +170,7 @@ + >{{ $t('registration.captcha') }}