From 01b07f01e9340935faf51e5a3c8034cc90423989 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Sat, 25 Apr 2020 07:04:39 +0300 Subject: Add support for follow request notifications --- src/modules/statuses.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index f1b7dcbd..239f41eb 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -13,6 +13,7 @@ import { omitBy } from 'lodash' import { set } from 'vue' +import { isStatusNotification } from '../services/notification_utils/notification_utils.js' import apiService from '../services/api/api.service.js' // import parse from '../services/status_parser/status_parser.js' @@ -321,7 +322,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => { each(notifications, (notification) => { - if (notification.type !== 'follow' && notification.type !== 'move') { + if (isStatusNotification(notification.type)) { notification.action = addStatusToGlobalStorage(state, notification.action).item notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item } @@ -361,13 +362,16 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot case 'move': i18nString = 'migrated_to' break + case 'follow_request': + i18nString = 'follow_request' + break } if (notification.type === 'pleroma:emoji_reaction') { notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji]) } else if (i18nString) { notifObj.body = rootGetters.i18n.t('notifications.' + i18nString) - } else { + } else if (isStatusNotification(notification.type)) { notifObj.body = notification.status.text } @@ -521,6 +525,13 @@ export const mutations = { notification.seen = true }) }, + dismissNotification (state, { id }) { + state.notifications.data = state.notifications.data.filter(n => n.id !== id) + }, + updateNotification (state, { id, updater }) { + const notification = find(state.notifications.data, n => n.id === id) + notification && updater(notification) + }, queueFlush (state, { timeline, id }) { state.timelines[timeline].flushMarker = id }, @@ -680,6 +691,13 @@ const statuses = { credentials: rootState.users.currentUser.credentials }) }, + dismissNotification ({ rootState, commit }, { id }) { + rootState.api.backendInteractor.dismissNotification({ id }) + .then(() => commit('dismissNotification', { id })) + }, + updateNotification ({ rootState, commit }, { id, updater }) { + commit('updateNotification', { id, updater }) + }, fetchFavsAndRepeats ({ rootState, commit }, id) { Promise.all([ rootState.api.backendInteractor.fetchFavoritedByUsers({ id }), -- cgit v1.2.3-70-g09d2 From 75519223f9a715aacb99d3780ee681089a479292 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Sat, 2 May 2020 10:52:57 +0300 Subject: mark single notifs as seen properly on server --- src/components/follow_request_card/follow_request_card.js | 2 +- src/components/notification/notification.js | 2 +- src/modules/statuses.js | 12 ++++++++++++ src/services/api/api.service.js | 12 ++++++++---- 4 files changed, 22 insertions(+), 6 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index 2a9d3db5..33e2699e 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -18,11 +18,11 @@ const FollowRequestCard = { this.$store.dispatch('removeFollowRequest', this.user) const notifId = this.findFollowRequestNotificationId() + this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId }) this.$store.dispatch('updateNotification', { id: notifId, updater: notification => { notification.type = 'follow' - notification.seen = true } }) }, diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 8c20ff09..abe3bebe 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -37,11 +37,11 @@ const Notification = { approveUser () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) + this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id }) this.$store.dispatch('updateNotification', { id: this.notification.id, updater: notification => { notification.type = 'follow' - notification.seen = true } }) }, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 239f41eb..2a8b9581 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -525,6 +525,10 @@ export const mutations = { notification.seen = true }) }, + markSingleNotificationAsSeen (state, { id }) { + const notification = find(state.notifications.data, n => n.id === id) + if (notification) notification.seen = true + }, dismissNotification (state, { id }) { state.notifications.data = state.notifications.data.filter(n => n.id !== id) }, @@ -691,6 +695,14 @@ const statuses = { credentials: rootState.users.currentUser.credentials }) }, + markSingleNotificationAsSeen ({ rootState, commit }, { id }) { + commit('markSingleNotificationAsSeen', { id }) + apiService.markNotificationsAsSeen({ + single: true, + id, + credentials: rootState.users.currentUser.credentials + }) + }, dismissNotification ({ rootState, commit }, { id }) { rootState.api.backendInteractor.dismissNotification({ id }) .then(() => commit('dismissNotification', { id })) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 3a58c38d..72c8874f 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -4,7 +4,6 @@ import 'whatwg-fetch' import { RegistrationError, StatusCodeError } from '../errors/errors' /* eslint-env browser */ -const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json' const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' @@ -17,6 +16,7 @@ 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' +const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa' const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes' @@ -841,12 +841,16 @@ const suggestions = ({ credentials }) => { }).then((data) => data.json()) } -const markNotificationsAsSeen = ({ id, credentials }) => { +const markNotificationsAsSeen = ({ id, credentials, single = false }) => { const body = new FormData() - body.append('latest_id', id) + if (single) { + body.append('id', id) + } else { + body.append('max_id', id) + } - return fetch(QVITTER_USER_NOTIFICATIONS_READ_URL, { + return fetch(NOTIFICATION_READ_URL, { body, headers: authHeaders(credentials), method: 'POST' -- cgit v1.2.3-70-g09d2 From 92ccaa97bb0a2c15b96e2fbcf03823ba902dc516 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Sat, 2 May 2020 11:51:39 +0300 Subject: don't dismiss a rejected follow request on server --- src/components/follow_request_card/follow_request_card.js | 9 +++++---- src/components/notification/notification.js | 6 ++++-- src/modules/statuses.js | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index 33e2699e..cbd75311 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -27,11 +27,12 @@ const FollowRequestCard = { }) }, denyUser () { - this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) - this.$store.dispatch('removeFollowRequest', this.user) - const notifId = this.findFollowRequestNotificationId() - this.$store.dispatch('dismissNotification', { id: notifId }) + this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) + .then(() => { + this.$store.dispatch('dismissNotificationLocal', { id: notifId }) + this.$store.dispatch('removeFollowRequest', this.user) + }) } } } diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index abe3bebe..1ae81ce4 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -47,8 +47,10 @@ const Notification = { }, denyUser () { this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) - this.$store.dispatch('removeFollowRequest', this.user) - this.$store.dispatch('dismissNotification', { id: this.notification.id }) + .then(() => { + this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id }) + this.$store.dispatch('removeFollowRequest', this.user) + }) } }, computed: { diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 2a8b9581..cd8c1dba 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -703,9 +703,12 @@ const statuses = { credentials: rootState.users.currentUser.credentials }) }, + dismissNotificationLocal ({ rootState, commit }, { id }) { + commit('dismissNotification', { id }) + }, dismissNotification ({ rootState, commit }, { id }) { + commit('dismissNotification', { id }) rootState.api.backendInteractor.dismissNotification({ id }) - .then(() => commit('dismissNotification', { id })) }, updateNotification ({ rootState, commit }, { id, updater }) { commit('updateNotification', { id, updater }) -- cgit v1.2.3-70-g09d2 From b5c1d074f83d08473a19a3885f6ff5eeb95274e5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 25 May 2020 23:38:31 +0300 Subject: fix reprööted posts not being muted properly. fix muted posts making desktop notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/status/status.js | 57 ++++++++++++++++++++++------- src/components/status/status.vue | 18 ++++++++- src/i18n/en.json | 4 +- src/modules/statuses.js | 10 ++++- src/services/status_parser/status_parser.js | 11 ++++++ 5 files changed, 83 insertions(+), 17 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/components/status/status.js b/src/components/status/status.js index 9cd9d61c..95278968 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -12,7 +12,8 @@ import StatusPopover from '../status_popover/status_popover.vue' import EmojiReactions from '../emoji_reactions/emoji_reactions.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' -import { filter, unescape, uniqBy } from 'lodash' +import { muteWordHits } from '../../services/status_parser/status_parser.js' +import { unescape, uniqBy } from 'lodash' import { mapGetters, mapState } from 'vuex' const Status = { @@ -44,6 +45,12 @@ const Status = { muteWords () { return this.mergedConfig.muteWords }, + showReasonMutedThread () { + return ( + this.status.thread_muted || + (this.status.reblog && this.status.reblog.thread_muted) + ) && !this.inConversation + }, repeaterClass () { const user = this.statusoid.user return highlightClass(user) @@ -93,20 +100,44 @@ const Status = { return !!this.currentUser }, muteWordHits () { - const statusText = this.status.text.toLowerCase() - const statusSummary = this.status.summary.toLowerCase() - const hits = filter(this.muteWords, (muteWord) => { - return statusText.includes(muteWord.toLowerCase()) || statusSummary.includes(muteWord.toLowerCase()) - }) - - return hits + return muteWordHits(this.status, this.muteWords) }, muted () { - const relationship = this.$store.getters.relationship(this.status.user.id) - return !this.unmuted && ( - (!(this.inProfile && this.status.user.id === this.profileUserId) && relationship.muting) || - (!this.inConversation && this.status.thread_muted) || - this.muteWordHits.length > 0) + const { status } = this + const { reblog } = status + const relationship = this.$store.getters.relationship(status.user.id) + const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id) + const reasonsToMute = ( + // Post is muted according to BE + status.muted || + // Reprööt of a muted post according to BE + (reblog && reblog.muted) || + // Muted user + relationship.muting || + // Muted user of a reprööt + (relationshipReblog && relationshipReblog.muting) || + // Thread is muted + status.thread_muted || + // Wordfiltered + this.muteWordHits.length > 0 + ) + const excusesNotToMute = ( + // Currently showing status + this.unmuted || + ( + this.inProfile && ( + // Don't mute user's posts on user timeline (except reblogs) + (!reblog && status.user.id === this.profileUserId) || + // Same as above but also allow self-reblogs + (reblog && reblog.user.id === this.profileUserId) + ) + ) || + // Don't mute statuses in muted conversation when said conversation is opened + (this.inConversation && status.thread_muted) + // No excuses if post has muted words + ) && !this.muteWordHits.length > 0 + + return !excusesNotToMute && reasonsToMute }, hideFilteredStatuses () { return this.mergedConfig.hideFilteredStatuses diff --git a/src/components/status/status.vue b/src/components/status/status.vue index e4c7545b..1c287aa7 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -18,10 +18,26 @@