From 47211fb32cb18809912db6c939fdd3a17d3d4569 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 9 Mar 2019 02:15:35 +0200 Subject: emoji adder --- .../entity_normalizer/entity_normalizer.service.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index d20ce77f..633bd3dc 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -40,10 +40,10 @@ export const parseUser = (data) => { } output.name = null // missing - output.name_html = data.display_name + output.name_html = addEmojis(data.display_name, data.emojis) output.description = null // missing - output.description_html = data.note + output.description_html = addEmojis(data.note, data.emojis) // Utilize avatar_static for gif avatars? output.profile_image_url = data.avatar @@ -142,6 +142,14 @@ const parseAttachment = (data) => { return output } +const addEmojis = (string, emojis) => { + return emojis.reduce((acc, emoji) => { + return acc.replace( + new RegExp(`:${emoji.shortcode}:`, 'g'), + `${emoji.shortcode}` + ) + }, string) +} export const parseStatus = (data) => { const output = {} @@ -157,7 +165,7 @@ export const parseStatus = (data) => { output.type = data.reblog ? 'retweet' : 'status' output.nsfw = data.sensitive - output.statusnet_html = data.content + output.statusnet_html = addEmojis(data.content, data.emojis) // Not exactly the same but works? output.text = data.content @@ -176,7 +184,7 @@ export const parseStatus = (data) => { } output.summary = data.spoiler_text - output.summary_html = data.spoiler_text + output.summary_html = addEmojis(data.spoiler_text, data.emojis) output.external_url = data.url // FIXME missing!! -- cgit v1.2.3-70-g09d2 From 4efcda1b4137fa14659a586d4d8559dcdd0f479b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 11 Mar 2019 22:41:08 +0200 Subject: Added some tests --- .../entity_normalizer/entity_normalizer.service.js | 2 +- .../entity_normalizer/entity_normalizer.spec.js | 75 +++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 633bd3dc..b7e5711e 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -142,7 +142,7 @@ const parseAttachment = (data) => { return output } -const addEmojis = (string, emojis) => { +export const addEmojis = (string, emojis) => { return emojis.reduce((acc, emoji) => { return acc.replace( new RegExp(`:${emoji.shortcode}:`, 'g'), diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js index 6245361c..2b0b0d6d 100644 --- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -1,4 +1,4 @@ -import { parseStatus, parseUser, parseNotification } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js' +import { parseStatus, parseUser, parseNotification, addEmojis } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js' import mastoapidata from '../../../../fixtures/mastoapi.json' import qvitterapidata from '../../../../fixtures/statuses.json' @@ -143,6 +143,23 @@ const makeMockNotificationQvitter = (overrides = {}) => { }, overrides) } +const makeMockEmojiMasto = (overrides = [{}]) => { + return [ + Object.assign({ + shortcode: 'image', + static_url: 'https://example.com/image.png', + url: 'https://example.com/image.png', + visible_in_picker: false + }, overrides[0]), + Object.assign({ + shortcode: 'thinking', + static_url: 'https://example.com/think.png', + url: 'https://example.com/think.png', + visible_in_picker: false + }, overrides[1]) + ] +} + parseNotification parseUser parseStatus @@ -218,6 +235,22 @@ describe('API Entities normalizer', () => { expect(parsedRepeat).to.have.property('retweeted_status') expect(parsedRepeat).to.have.deep.property('retweeted_status.id', 'deadbeef') }) + + it('adds emojis to post content', () => { + const post = makeMockStatusMasto({ emojis: makeMockEmojiMasto(), content: 'Makes you think :thinking:' }) + + const parsedPost = parseStatus(post) + + expect(parsedPost).to.have.property('statusnet_html').that.contains(' { + const post = makeMockStatusMasto({ emojis: makeMockEmojiMasto(), spoiler_text: 'CW: 300 IQ :thinking:' }) + + const parsedPost = parseStatus(post) + + expect(parsedPost).to.have.property('summary_html').that.contains(' { expect(parseUser(local)).to.have.property('is_local', true) expect(parseUser(remote)).to.have.property('is_local', false) }) + + it('adds emojis to user name', () => { + const user = makeMockUserMasto({ emojis: makeMockEmojiMasto(), display_name: 'The :thinking: thinker' }) + + const parsedUser = parseUser(user) + + expect(parsedUser).to.have.property('name_html').that.contains(' { + const user = makeMockUserMasto({ emojis: makeMockEmojiMasto(), note: 'Hello i like to :thinking: a lot' }) + + const parsedUser = parseUser(user) + + expect(parsedUser).to.have.property('description_html').that.contains(' { expect(parseNotification(notif)).to.have.deep.property('from_profile.id', 'spurdo') }) }) + + describe('MastoAPI emoji adder', () => { + const emojis = makeMockEmojiMasto() + const imageHtml = 'image' + .replace(/"/g, '\'') + const thinkHtml = 'thinking' + .replace(/"/g, '\'') + + it('correctly replaces shortcodes in supplied string', () => { + const result = addEmojis('This post has :image: emoji and :thinking: emoji', emojis) + expect(result).to.include(thinkHtml) + expect(result).to.include(imageHtml) + }) + + it('handles consecutive emojis correctly', () => { + const result = addEmojis('Lelel emoji spam :thinking::thinking::thinking::thinking:', emojis) + expect(result).to.include(thinkHtml + thinkHtml + thinkHtml + thinkHtml) + }) + + it('Doesn\'t replace nonexistent emojis', () => { + const result = addEmojis('Admin add the :tenshi: emoji', emojis) + expect(result).to.equal('Admin add the :tenshi: emoji') + }) + }) }) -- cgit v1.2.3-70-g09d2 From a6a162177b8347917494ddd18de9d239b15bd7fa Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 11 Mar 2019 23:03:55 +0200 Subject: instead of filtering nulls, let's just not have them in the first place --- src/modules/users.js | 6 +++--- .../entity_normalizer/entity_normalizer.service.js | 15 +++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/modules/users.js b/src/modules/users.js index 5eabb1ec..d04c7f0b 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -1,5 +1,5 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' -import { compact, map, each, merge, find, omitBy } from 'lodash' +import { compact, map, each, merge, find } from 'lodash' import { set } from 'vue' import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js' import oauthApi from '../services/new_api/oauth' @@ -11,7 +11,7 @@ export const mergeOrAdd = (arr, obj, item) => { const oldItem = obj[item.id] if (oldItem) { // We already have this, so only merge the new info. - merge(oldItem, omitBy(item, _ => _ === null)) + merge(oldItem, item) return { item: oldItem, new: false } } else { // This is a new item, prepare it @@ -39,7 +39,7 @@ export const mutations = { }, setCurrentUser (state, user) { state.lastLoginName = user.screen_name - state.currentUser = merge(state.currentUser || {}, omitBy(user, _ => _ === null)) + state.currentUser = merge(state.currentUser || {}, user) }, clearCurrentUser (state) { state.currentUser = false diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index d20ce77f..7c840552 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -39,10 +39,10 @@ export const parseUser = (data) => { return output } - output.name = null // missing + // output.name = ??? missing output.name_html = data.display_name - output.description = null // missing + // output.description = ??? missing output.description_html = data.note // Utilize avatar_static for gif avatars? @@ -83,7 +83,7 @@ export const parseUser = (data) => { output.friends_count = data.friends_count - output.bot = null // missing + // output.bot = ??? missing output.statusnet_profile_url = data.statusnet_profile_url @@ -134,7 +134,7 @@ const parseAttachment = (data) => { output.meta = data.meta // not present in BE yet } else { output.mimetype = data.mimetype - output.meta = null // missing + // output.meta = ??? missing } output.url = data.url @@ -166,7 +166,7 @@ export const parseStatus = (data) => { output.in_reply_to_user_id = data.in_reply_to_account_id // Missing!! fix in UI? - output.in_reply_to_screen_name = null + // output.in_reply_to_screen_name = ??? // Not exactly the same but works output.statusnet_conversation_id = data.id @@ -179,8 +179,7 @@ export const parseStatus = (data) => { output.summary_html = data.spoiler_text output.external_url = data.url - // FIXME missing!! - output.is_local = false + // output.is_local = ??? missing } else { output.favorited = data.favorited output.fave_num = data.fave_num @@ -259,7 +258,7 @@ export const parseNotification = (data) => { if (masto) { output.type = mastoDict[data.type] || data.type - output.seen = null // missing + // output.seen = ??? missing output.status = parseStatus(data.status) output.action = output.status // not sure output.from_profile = parseUser(data.account) -- cgit v1.2.3-70-g09d2 From b9877a4323ab0025c14a8126eb2f6268a4bea6ac Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 11 Mar 2019 23:08:14 +0200 Subject: actually use embedded relationship if it's present --- src/services/entity_normalizer/entity_normalizer.service.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 7c840552..37c1f544 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -59,10 +59,13 @@ export const parseUser = (data) => { output.statusnet_profile_url = data.url if (data.pleroma) { - const pleroma = data.pleroma - output.follows_you = pleroma.follows_you - output.statusnet_blocking = pleroma.statusnet_blocking - output.muted = pleroma.muted + const relationship = data.pleroma.relationship + + if (relationship) { + output.follows_you = relationship.follows_you + output.statusnet_blocking = relationship.statusnet_blocking + output.muted = relationship.muted + } } // Missing, trying to recover -- cgit v1.2.3-70-g09d2 From ce8b5fcd11aed0dedf8dd8c16190e9f1a826da2d Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 12 Mar 2019 21:49:03 +0200 Subject: fix embedded relationship card parsing --- src/services/entity_normalizer/entity_normalizer.service.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 37c1f544..9f9db563 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -62,9 +62,10 @@ export const parseUser = (data) => { const relationship = data.pleroma.relationship if (relationship) { - output.follows_you = relationship.follows_you - output.statusnet_blocking = relationship.statusnet_blocking - output.muted = relationship.muted + output.follows_you = relationship.followed_by + output.following = relationship.following + output.statusnet_blocking = relationship.blocking + output.muted = relationship.muting } } -- cgit v1.2.3-70-g09d2 From cd9a7dd48802fff8942ae607a23677cfb43a7b14 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 12 Mar 2019 17:16:57 -0400 Subject: #436: integrate mastoAPI notifications --- src/components/notification/notification.js | 3 + src/components/notification/notification.vue | 83 +++++++++++++--------- src/components/notifications/notifications.js | 5 +- src/components/notifications/notifications.vue | 3 +- src/i18n/en.json | 2 + src/modules/statuses.js | 36 +++++++++- src/services/api/api.service.js | 29 +++++++- .../entity_normalizer/entity_normalizer.service.js | 16 ++++- 8 files changed, 135 insertions(+), 42 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index fe5b7018..c86f22bb 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -21,6 +21,9 @@ const Notification = { }, userProfileLink (user) { return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) + }, + dismiss () { + this.$store.dispatch('dismissNotifications', { id: this.notification.id }) } }, computed: { diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 5e9cef97..b281c7cf 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -1,44 +1,57 @@ + + \ No newline at end of file diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 9fc5e38a..68004d54 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -53,7 +53,10 @@ const Notifications = { }, methods: { markAsSeen () { - this.$store.dispatch('markNotificationsAsSeen', this.visibleNotifications) + this.$store.dispatch('markNotificationsAsSeen') + }, + clear () { + this.$store.dispatch('clearNotifications') }, fetchOlderNotifications () { const store = this.$store diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 6f162b62..6438361d 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -9,7 +9,8 @@
{{$t('timeline.error_fetching')}}
- + +
diff --git a/src/i18n/en.json b/src/i18n/en.json index 01fe2fba..38abfaf5 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -62,6 +62,8 @@ "load_older": "Load older notifications", "notifications": "Notifications", "read": "Read!", + "clear": "Clear!", + "dismiss": "Dismiss!", "repeated_you": "repeated your status", "no_more_notifications": "No more notifications" }, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 6b512fa3..fde783a5 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -1,4 +1,4 @@ -import { remove, slice, each, find, maxBy, minBy, merge, first, last, isArray } from 'lodash' +import { remove, slice, each, find, findIndex, maxBy, minBy, merge, first, last, isArray } from 'lodash' import apiService from '../services/api/api.service.js' // import parse from '../services/status_parser/status_parser.js' @@ -390,6 +390,27 @@ export const mutations = { notification.seen = true }) }, + clearNotifications (state) { + state.notifications.data = [] + state.notifications.idStore = {} + state.notifications.maxId = 0 + state.notifications.minId = 0 + }, + dismissNotifications (state, { id }) { + const { data } = state.notifications + const idx = findIndex(data, { id }) + + if (idx !== -1) { + const notification = data[idx] + data.splice(idx, 1) + delete state.notifications.idStore[id] + if (state.notifications.maxId === notification.id) { + state.notifications.maxId = data.length ? maxBy(data, 'id').id : 0 + } else if (state.notifications.minId === notification.id) { + state.notifications.minId = data.length ? minBy(data, 'id').id : 0 + } + } + }, queueFlush (state, { timeline, id }) { state.timelines[timeline].flushMarker = id } @@ -474,6 +495,19 @@ const statuses = { id: rootState.statuses.notifications.maxId, credentials: rootState.users.currentUser.credentials }) + }, + clearNotifications ({ rootState, commit }) { + commit('clearNotifications') + apiService.clearNotifications({ + credentials: rootState.users.currentUser.credentials + }) + }, + dismissNotifications ({ rootState, commit }, { id }) { + commit('dismissNotifications', { id }) + apiService.dismissNotifications({ + id, + credentials: rootState.users.currentUser.credentials + }) } }, mutations diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 2de87026..9d3139ce 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -29,7 +29,6 @@ const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json' const PROFILE_UPDATE_URL = '/api/account/update_profile.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json' -const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json' const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json' const BLOCKING_URL = '/api/blocks/create.json' const UNBLOCKING_URL = '/api/blocks/destroy.json' @@ -43,6 +42,9 @@ const DENY_USER_URL = '/api/pleroma/friendships/deny' const SUGGESTIONS_URL = '/api/v1/suggestions' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' +const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications' +const MASTODON_USER_NOTIFICATIONS_CLEAR_URL = '/api/v1/notifications/clear' +const MASTODON_USER_NOTIFICATIONS_DISMISS_URL = '/api/v1/notifications/dismiss' import { each, map } from 'lodash' import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js' @@ -345,7 +347,7 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use friends: FRIENDS_TIMELINE_URL, mentions: MENTIONS_URL, dms: DM_TIMELINE_URL, - notifications: QVITTER_USER_NOTIFICATIONS_URL, + notifications: MASTODON_USER_NOTIFICATIONS_URL, 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL, user: QVITTER_USER_TIMELINE_URL, media: QVITTER_USER_TIMELINE_URL, @@ -575,6 +577,25 @@ const markNotificationsAsSeen = ({id, credentials}) => { }).then((data) => data.json()) } +const clearNotifications = ({ credentials }) => { + return fetch(MASTODON_USER_NOTIFICATIONS_CLEAR_URL, { + headers: authHeaders(credentials), + method: 'POST' + }).then((data) => data.json()) +} + +const dismissNotifications = ({ id, credentials }) => { + const body = new FormData() + + body.append('id', id) + + return fetch(MASTODON_USER_NOTIFICATIONS_DISMISS_URL, { + body, + headers: authHeaders(credentials), + method: 'POST' + }).then((data) => data.json()) +} + const apiService = { verifyCredentials, fetchTimeline, @@ -615,7 +636,9 @@ const apiService = { approveUser, denyUser, suggestions, - markNotificationsAsSeen + markNotificationsAsSeen, + clearNotifications, + dismissNotifications } export default apiService diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index d20ce77f..81b88bf0 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -249,6 +249,18 @@ export const parseStatus = (data) => { return output } +export const parseFollow = (data) => { + const output = {} + output.id = String(data.id) + output.visibility = true + output.created_at = new Date(data.created_at) + + // Converting to string, the right way. + output.user = parseUser(data.account) + + return output +} + export const parseNotification = (data) => { const mastoDict = { 'favourite': 'like', @@ -260,7 +272,9 @@ export const parseNotification = (data) => { if (masto) { output.type = mastoDict[data.type] || data.type output.seen = null // missing - output.status = parseStatus(data.status) + output.status = output.type === 'follow' + ? parseFollow(data) + : parseStatus(data.status) output.action = output.status // not sure output.from_profile = parseUser(data.account) } else { -- cgit v1.2.3-70-g09d2 From 2f7d890ad228a2aeb8643373c9c9a6d925c6ff7f Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 13 Mar 2019 14:08:03 -0400 Subject: #436: add dismiss button, disable is_seen part --- src/components/notification/notification.vue | 93 +++++++++++----------- src/components/status/status.js | 6 +- src/components/status/status.vue | 3 + .../entity_normalizer/entity_normalizer.service.js | 6 +- .../notifications_fetcher.service.js | 22 ++--- 5 files changed, 68 insertions(+), 62 deletions(-) (limited to 'src/services/entity_normalizer/entity_normalizer.service.js') diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index b281c7cf..87b0fde2 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -1,57 +1,54 @@ - - \ No newline at end of file diff --git a/src/components/status/status.js b/src/components/status/status.js index 9e18fe15..4cd26be3 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -25,7 +25,8 @@ const Status = { 'replies', 'isPreview', 'noHeading', - 'inlineExpanded' + 'inlineExpanded', + 'isNotification' ], data () { return { @@ -365,6 +366,9 @@ const Status = { setMedia () { const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments return () => this.$store.dispatch('setMedia', attachments) + }, + dismissNotification () { + this.$emit('dismissNotification') } }, watch: { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 1f6d0325..28a44346 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -52,6 +52,9 @@ + + +