Merge branch 'issue-436-mastoapi-notifications' into 'develop'

#436: integrate mastoAPI notifications

Closes #436

See merge request pleroma/pleroma-fe!678
This commit is contained in:
HJ 2019-04-10 17:28:42 +00:00
commit 84505e01f5
15 changed files with 205 additions and 6790 deletions

View File

@ -28,21 +28,21 @@ const Notification = {
}, },
computed: { computed: {
userClass () { userClass () {
return highlightClass(this.notification.action.user) return highlightClass(this.notification.from_profile)
}, },
userStyle () { userStyle () {
const highlight = this.$store.state.config.highlight const highlight = this.$store.state.config.highlight
const user = this.notification.action.user const user = this.notification.from_profile
return highlightStyle(highlight[user.screen_name]) return highlightStyle(highlight[user.screen_name])
}, },
userInStore () { userInStore () {
return this.$store.getters.findUser(this.notification.action.user.id) return this.$store.getters.findUser(this.notification.from_profile.id)
}, },
user () { user () {
if (this.userInStore) { if (this.userInStore) {
return this.userInStore return this.userInStore
} }
return {} return this.notification.from_profile
} }
} }
} }

View File

@ -1,15 +1,20 @@
<template> <template>
<status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status> <status
v-if="notification.type === 'mention'"
:compact="true"
:statusoid="notification.status"
>
</status>
<div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]" v-else> <div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]" v-else>
<a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded"> <a class='avatar-container' :href="notification.from_profile.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
<UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/> <UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.from_profile.profile_image_url_original" />
</a> </a>
<div class='notification-right'> <div class='notification-right'>
<UserCard :user="getUser(notification)" :rounded="true" :bordered="true" v-if="userExpanded"/> <UserCard :user="getUser(notification)" :rounded="true" :bordered="true" v-if="userExpanded" />
<span class="notification-details"> <span class="notification-details">
<div class="name-and-action"> <div class="name-and-action">
<span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span> <span class="username" v-if="!!notification.from_profile.name_html" :title="'@'+notification.from_profile.screen_name" v-html="notification.from_profile.name_html"></span>
<span class="username" v-else :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> <span class="username" v-else :title="'@'+notification.from_profile.screen_name">{{ notification.from_profile.name }}</span>
<span v-if="notification.type === 'like'"> <span v-if="notification.type === 'like'">
<i class="fa icon-star lit"></i> <i class="fa icon-star lit"></i>
<small>{{$t('notifications.favorited_you')}}</small> <small>{{$t('notifications.favorited_you')}}</small>
@ -23,19 +28,24 @@
<small>{{$t('notifications.followed_you')}}</small> <small>{{$t('notifications.followed_you')}}</small>
</span> </span>
</div> </div>
<div class="timeago"> <div class="timeago" v-if="notification.type === 'follow'">
<span class="faint">
<timeago :since="notification.created_at" :auto-update="240"></timeago>
</span>
</div>
<div class="timeago" v-else>
<router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }" class="faint-link"> <router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }" class="faint-link">
<timeago :since="notification.action.created_at" :auto-update="240"></timeago> <timeago :since="notification.created_at" :auto-update="240"></timeago>
</router-link> </router-link>
</div> </div>
</span> </span>
<div class="follow-text" v-if="notification.type === 'follow'"> <div class="follow-text" v-if="notification.type === 'follow'">
<router-link :to="userProfileLink(notification.action.user)"> <router-link :to="userProfileLink(notification.from_profile)">
@{{notification.action.user.screen_name}} @{{notification.from_profile.screen_name}}
</router-link> </router-link>
</div> </div>
<template v-else> <template v-else>
<status class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status> <status class="faint" :compact="true" :statusoid="notification.action" :noHeading="true"></status>
</template> </template>
</div> </div>
</div> </div>

View File

@ -49,7 +49,7 @@ const Notifications = {
}, },
methods: { methods: {
markAsSeen () { markAsSeen () {
this.$store.dispatch('markNotificationsAsSeen', this.visibleNotifications) this.$store.dispatch('markNotificationsAsSeen')
}, },
fetchOlderNotifications () { fetchOlderNotifications () {
const store = this.$store const store = this.$store

View File

@ -12,7 +12,7 @@
<button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button> <button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div v-for="notification in visibleNotifications" :key="notification.action.id" class="notification" :class='{"unseen": !notification.seen}'> <div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !notification.seen}'>
<div class="notification-overlay"></div> <div class="notification-overlay"></div>
<notification :notification="notification"></notification> <notification :notification="notification"></notification>
</div> </div>

View File

@ -59,6 +59,11 @@ const persistedStateOptions = {
const persistedState = await createPersistedState(persistedStateOptions) const persistedState = await createPersistedState(persistedStateOptions)
const store = new Vuex.Store({ const store = new Vuex.Store({
modules: { modules: {
i18n: {
getters: {
i18n: () => i18n
}
},
interface: interfaceModule, interface: interfaceModule,
instance: instanceModule, instance: instanceModule,
statuses: statusesModule, statuses: statusesModule,

View File

@ -272,12 +272,14 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
} }
} }
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes }) => { const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
const allStatuses = state.allStatuses const allStatuses = state.allStatuses
const allStatusesObject = state.allStatusesObject const allStatusesObject = state.allStatusesObject
each(notifications, (notification) => { each(notifications, (notification) => {
if (notification.type !== 'follow') {
notification.action = mergeOrAdd(allStatuses, allStatusesObject, notification.action).item notification.action = mergeOrAdd(allStatuses, allStatusesObject, notification.action).item
notification.status = notification.status && mergeOrAdd(allStatuses, allStatusesObject, notification.status).item notification.status = notification.status && mergeOrAdd(allStatuses, allStatusesObject, notification.status).item
}
// Only add a new notification if we don't have one for the same action // Only add a new notification if we don't have one for the same action
if (!state.notifications.idStore.hasOwnProperty(notification.id)) { if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
@ -293,15 +295,32 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
if ('Notification' in window && window.Notification.permission === 'granted') { if ('Notification' in window && window.Notification.permission === 'granted') {
const notifObj = {} const notifObj = {}
const action = notification.action const status = notification.status
const title = action.user.name const title = notification.from_profile.name
notifObj.icon = action.user.profile_image_url notifObj.icon = notification.from_profile.profile_image_url
notifObj.body = action.text // there's a problem that it doesn't put a space before links tho let i18nString
switch (notification.type) {
case 'like':
i18nString = 'favorited_you'
break
case 'repeat':
i18nString = 'repeated_you'
break
case 'follow':
i18nString = 'followed_you'
break
}
if (i18nString) {
notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
} else {
notifObj.body = notification.status.text
}
// Shows first attached non-nsfw image, if any. Should add configuration for this somehow... // Shows first attached non-nsfw image, if any. Should add configuration for this somehow...
if (action.attachments && action.attachments.length > 0 && !action.nsfw && if (status && status.attachments && status.attachments.length > 0 && !status.nsfw &&
action.attachments[0].mimetype.startsWith('image/')) { status.attachments[0].mimetype.startsWith('image/')) {
notifObj.image = action.attachments[0].url notifObj.image = status.attachments[0].url
} }
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) { if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
@ -421,8 +440,8 @@ const statuses = {
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) { addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) {
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId }) commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId })
}, },
addNewNotifications ({ rootState, commit, dispatch }, { notifications, older }) { addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) {
commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older }) commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters })
}, },
setError ({ rootState, commit }, { value }) { setError ({ rootState, commit }, { value }) {
commit('setError', { value }) commit('setError', { value })

View File

@ -144,8 +144,10 @@ export const mutations = {
status.user = state.usersObject[status.user.id] status.user = state.usersObject[status.user.id]
}, },
setUserForNotification (state, notification) { setUserForNotification (state, notification) {
if (notification.type !== 'follow') {
notification.action.user = state.usersObject[notification.action.user.id] notification.action.user = state.usersObject[notification.action.user.id]
notification.from_profile = state.usersObject[notification.action.user.id] }
notification.from_profile = state.usersObject[notification.from_profile.id]
}, },
setColor (state, { user: { id }, highlighted }) { setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id] const user = state.usersObject[id]

View File

@ -8,7 +8,6 @@ const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json' const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json'
const PROFILE_UPDATE_URL = '/api/account/update_profile.json' const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json' const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
@ -23,6 +22,7 @@ const ADMIN_USER_URL = '/api/pleroma/admin/user'
const SUGGESTIONS_URL = '/api/v1/suggestions' const SUGGESTIONS_URL = '/api/v1/suggestions'
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite` const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
const MASTODON_UNFAVORITE_URL = id => `/api/v1/statuses/${id}/unfavourite` const MASTODON_UNFAVORITE_URL = id => `/api/v1/statuses/${id}/unfavourite`
const MASTODON_RETWEET_URL = id => `/api/v1/statuses/${id}/reblog` const MASTODON_RETWEET_URL = id => `/api/v1/statuses/${id}/reblog`
@ -442,7 +442,7 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
friends: MASTODON_USER_HOME_TIMELINE_URL, friends: MASTODON_USER_HOME_TIMELINE_URL,
mentions: MENTIONS_URL, mentions: MENTIONS_URL,
dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL, dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
notifications: QVITTER_USER_NOTIFICATIONS_URL, notifications: MASTODON_USER_NOTIFICATIONS_URL,
'publicAndExternal': MASTODON_PUBLIC_TIMELINE, 'publicAndExternal': MASTODON_PUBLIC_TIMELINE,
user: MASTODON_USER_TIMELINE_URL, user: MASTODON_USER_TIMELINE_URL,
media: MASTODON_USER_TIMELINE_URL, media: MASTODON_USER_TIMELINE_URL,

View File

@ -39,7 +39,7 @@ export const parseUser = (data) => {
return output return output
} }
// output.name = ??? missing output.name = data.display_name
output.name_html = addEmojis(data.display_name, data.emojis) output.name_html = addEmojis(data.display_name, data.emojis)
// output.description = ??? missing // output.description = ??? missing
@ -74,7 +74,7 @@ export const parseUser = (data) => {
} }
} }
// Missing, trying to recover // TODO: handle is_local
output.is_local = !output.screen_name.includes('@') output.is_local = !output.screen_name.includes('@')
} else { } else {
output.screen_name = data.screen_name output.screen_name = data.screen_name
@ -239,7 +239,6 @@ export const parseStatus = (data) => {
output.in_reply_to_status_id = data.in_reply_to_status_id output.in_reply_to_status_id = data.in_reply_to_status_id
output.in_reply_to_user_id = data.in_reply_to_user_id output.in_reply_to_user_id = data.in_reply_to_user_id
output.in_reply_to_screen_name = data.in_reply_to_screen_name output.in_reply_to_screen_name = data.in_reply_to_screen_name
output.statusnet_conversation_id = data.statusnet_conversation_id output.statusnet_conversation_id = data.statusnet_conversation_id
if (output.type === 'retweet') { if (output.type === 'retweet') {
@ -290,9 +289,11 @@ export const parseNotification = (data) => {
if (masto) { if (masto) {
output.type = mastoDict[data.type] || data.type output.type = mastoDict[data.type] || data.type
// output.seen = ??? missing output.seen = data.pleroma.is_seen
output.status = parseStatus(data.status) output.status = output.type === 'follow'
output.action = output.status // not sure ? null
: parseStatus(data.status)
output.action = output.status // TODO: Refactor, this is unneeded
output.from_profile = parseUser(data.account) output.from_profile = parseUser(data.account)
} else { } else {
const parsedNotice = parseStatus(data.notice) const parsedNotice = parseStatus(data.notice)

View File

@ -10,8 +10,8 @@ export const visibleTypes = store => ([
].filter(_ => _)) ].filter(_ => _))
const sortById = (a, b) => { const sortById = (a, b) => {
const seqA = Number(a.action.id) const seqA = Number(a.id)
const seqB = Number(b.action.id) const seqB = Number(b.id)
const isSeqA = !Number.isNaN(seqA) const isSeqA = !Number.isNaN(seqA)
const isSeqB = !Number.isNaN(seqB) const isSeqB = !Number.isNaN(seqB)
if (isSeqA && isSeqB) { if (isSeqA && isSeqB) {
@ -21,7 +21,7 @@ const sortById = (a, b) => {
} else if (!isSeqA && isSeqB) { } else if (!isSeqA && isSeqB) {
return -1 return -1
} else { } else {
return a.action.id > b.action.id ? -1 : 1 return a.id > b.id ? -1 : 1
} }
} }

View File

@ -11,29 +11,35 @@ const fetchAndUpdate = ({store, credentials, older = false}) => {
const rootState = store.rootState || store.state const rootState = store.rootState || store.state
const timelineData = rootState.statuses.notifications const timelineData = rootState.statuses.notifications
args['timeline'] = 'notifications'
if (older) { if (older) {
if (timelineData.minId !== Number.POSITIVE_INFINITY) { if (timelineData.minId !== Number.POSITIVE_INFINITY) {
args['until'] = timelineData.minId args['until'] = timelineData.minId
} }
return fetchNotifications({ store, args, older })
} else { } else {
// load unread notifications repeadedly to provide consistency between browser tabs // fetch new notifications
if (timelineData.maxId !== Number.POSITIVE_INFINITY) {
args['since'] = timelineData.maxId
}
const result = fetchNotifications({ store, args, older })
// load unread notifications repeatedly to provide consistency between browser tabs
const notifications = timelineData.data const notifications = timelineData.data
const unread = notifications.filter(n => !n.seen).map(n => n.id) const unread = notifications.filter(n => !n.seen).map(n => n.id)
if (!unread.length) { if (unread.length) {
args['since'] = timelineData.maxId args['since'] = Math.min(...unread)
} else { fetchNotifications({ store, args, older })
args['since'] = Math.min(...unread) - 1
if (timelineData.maxId !== Math.max(...unread)) {
args['until'] = Math.max(...unread, args['since'] + 20)
}
}
} }
args['timeline'] = 'notifications' return result
}
}
const fetchNotifications = ({ store, args, older }) => {
return apiService.fetchTimeline(args) return apiService.fetchTimeline(args)
.then((notifications) => { .then((notifications) => {
update({store, notifications, older}) update({ store, notifications, older })
return notifications return notifications
}, () => store.dispatch('setNotificationsError', { value: true })) }, () => store.dispatch('setNotificationsError', { value: true }))
.catch(() => store.dispatch('setNotificationsError', { value: true })) .catch(() => store.dispatch('setNotificationsError', { value: true }))

View File

@ -58,7 +58,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639", "uri": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639",
"url": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639", "url": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -127,7 +130,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779", "uri": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779",
"url": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779", "url": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -250,7 +256,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b", "uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b", "url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, },
"reblogged": false, "reblogged": false,
"reblogs_count": 0, "reblogs_count": 0,
@ -260,7 +269,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b", "uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b", "url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -329,7 +341,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9", "uri": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9",
"url": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9", "url": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -390,7 +405,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0", "uri": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0",
"url": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0", "url": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -516,7 +534,10 @@
}], }],
"uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note", "uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
"url": "https://social.super-niche.club/notice/2353002", "url": "https://social.super-niche.club/notice/2353002",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, },
"reblogged": false, "reblogged": false,
"reblogs_count": 0, "reblogs_count": 0,
@ -529,7 +550,10 @@
}], }],
"uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note", "uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
"url": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note", "url": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -657,7 +681,10 @@
"tags": [], "tags": [],
"uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab", "uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab", "url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, },
"reblogged": false, "reblogged": false,
"reblogs_count": 0, "reblogs_count": 0,
@ -667,7 +694,10 @@
"tags": [], "tags": [],
"uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab", "uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab", "url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -733,7 +763,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d", "uri": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d",
"url": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d", "url": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -794,7 +827,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542", "uri": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542",
"url": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542", "url": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -850,7 +886,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e", "uri": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e",
"url": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e", "url": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -906,7 +945,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391", "uri": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391",
"url": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391", "url": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -962,7 +1004,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10", "uri": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10",
"url": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10", "url": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1023,7 +1068,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387", "uri": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387",
"url": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387", "url": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1084,7 +1132,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e", "uri": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e",
"url": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e", "url": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1145,7 +1196,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f", "uri": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f",
"url": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f", "url": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1252,7 +1306,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a", "uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a", "url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, },
"reblogged": false, "reblogged": false,
"reblogs_count": 0, "reblogs_count": 0,
@ -1262,7 +1319,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a", "uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a", "url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1323,7 +1383,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33", "uri": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33",
"url": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33", "url": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1446,7 +1509,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733", "uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733", "url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, },
"reblogged": false, "reblogged": false,
"reblogs_count": 0, "reblogs_count": 0,
@ -1456,7 +1522,10 @@
"tags": [], "tags": [],
"uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733", "uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733", "url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1517,7 +1586,10 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d", "uri": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d",
"url": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d", "url": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}, { }, {
"account": { "account": {
"acct": "hj", "acct": "hj",
@ -1578,5 +1650,8 @@
"tags": [], "tags": [],
"uri": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096", "uri": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096",
"url": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096", "url": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096",
"visibility": "public" "visibility": "public",
"pleroma": {
"local": true
}
}] }]

View File

@ -129,7 +129,10 @@ const makeMockStatusMasto = (overrides = {}) => {
tags: [], tags: [],
uri: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639', uri: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
url: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639', url: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
visibility: 'public' visibility: 'public',
pleroma: {
local: true
}
}, overrides) }, overrides)
} }

View File

@ -9,14 +9,17 @@ describe('NotificationUtils', () => {
notifications: { notifications: {
data: [ data: [
{ {
id: 1,
action: { id: '1' }, action: { id: '1' },
type: 'like' type: 'like'
}, },
{ {
id: 2,
action: { id: '2' }, action: { id: '2' },
type: 'mention' type: 'mention'
}, },
{ {
id: 3,
action: { id: '3' }, action: { id: '3' },
type: 'repeat' type: 'repeat'
} }
@ -35,10 +38,12 @@ describe('NotificationUtils', () => {
const expected = [ const expected = [
{ {
action: { id: '3' }, action: { id: '3' },
id: 3,
type: 'repeat' type: 'repeat'
}, },
{ {
action: { id: '1' }, action: { id: '1' },
id: 1,
type: 'like' type: 'like'
} }
] ]

6711
yarn.lock

File diff suppressed because it is too large Load Diff