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 ++-- src/components/moderation_tools/moderation_tools.js | 16 ++++++++-------- .../user_reporting_modal/user_reporting_modal.js | 2 +- src/components/user_settings/user_settings.js | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src/components') 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 -- 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/components') 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/components') 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 6af870cd9069a8fc45b7684d264656dad0cf4a70 Mon Sep 17 00:00:00 2001 From: kPherox Date: Wed, 11 Dec 2019 00:00:10 +0900 Subject: Add view for moves notifications --- src/components/notification/notification.vue | 14 +++++++++++++- src/components/notifications/notifications.scss | 7 ++++++- src/components/settings/settings.vue | 5 +++++ src/i18n/en.json | 1 + src/modules/config.js | 3 ++- src/modules/statuses.js | 3 ++- src/services/notification_utils/notification_utils.js | 3 ++- src/services/push/push.js | 3 ++- static/fontello.json | 6 ++++++ 9 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src/components') diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 1f192c77..cf4d8072 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -74,9 +74,13 @@ {{ $t('notifications.followed_you') }} + + + {{ $t('notifications.moved_to') }} +
@@ -115,6 +119,14 @@ @{{ notification.from_profile.screen_name }}
+
+ + @{{ notification.target.screen_name }} + +